diff --git a/Classes/Controller/AbstractController.php b/Classes/Controller/AbstractController.php new file mode 100644 index 0000000..842564a --- /dev/null +++ b/Classes/Controller/AbstractController.php @@ -0,0 +1,41 @@ +bookmarkRepository = $bookmarkRepository; + } + + + /** @var LikeRepository */ + protected $likeRepository; + + /** + * @param \WapplerSystems\BookmarksLikesRatings\Domain\Repository\LikeRepository $bookmarkRepository + */ + public function injectLikeRepository(LikeRepository $likeRepository) { + $this->likeRepository = $likeRepository; + } + + + protected function getCurrentUser() : array { + if (!$GLOBALS['TSFE']->fe_user) { + throw new Exception('no access'); + } + + return $GLOBALS['TSFE']->fe_user->user; + } + +} diff --git a/Classes/Controller/BookmarkController.php b/Classes/Controller/BookmarkController.php new file mode 100644 index 0000000..0f4cc4d --- /dev/null +++ b/Classes/Controller/BookmarkController.php @@ -0,0 +1,132 @@ +defaultViewObjectName = JsonView::class; + } + + /** + * @param int $objectUid + * @param string $tablename + * @throws \TYPO3\CMS\Frontend\Exception + */ + public function statusAction(int $objectUid,string $tablename) { + + $user = $this->getCurrentUser(); + + $this->view->setVariablesToRender(['status']); + $this->view->assignMultiple([ + 'status' => ['status' => $this->bookmarkRepository->countByUserTablenameObjectUid($user['uid'],$tablename,$objectUid) === 0? 'false':'true'] + ]); + + } + + + public function initializeToggleAction() + { + $this->defaultViewObjectName = JsonView::class; + } + + /** + * @param int $objectUid + * @param string $tablename + * @throws \TYPO3\CMS\Frontend\Exception + */ + public function toggleAction(int $objectUid, string $tablename) + { + + $user = $this->getCurrentUser(); + + $this->view->setVariablesToRender(['status']); + + if ($this->bookmarkRepository->countByUserTablenameObjectUid($user['uid'], $tablename, $objectUid) === 0) { + + $bookmark = new Bookmark(); + $bookmark->setUser($user['uid']); + $bookmark->setTablename($tablename); + $bookmark->setObjectUid($objectUid); + + $this->bookmarkRepository->add($bookmark); + + $this->view->assignMultiple([ + 'status' => ['status' => 'true'] + ]); + } else { + $this->bookmarkRepository->removeByUserTablenameObjectUid($user['uid'], $tablename, $objectUid); + + $this->view->assignMultiple([ + 'status' => ['status' => 'false'] + ]); + } + + } + + + /** + * @param int $objectUid + * @param string $tablename + * @throws \TYPO3\CMS\Frontend\Exception + */ + public function deleteAction(int $objectUid, string $tablename) + { + + $user = $this->getCurrentUser(); + $this->bookmarkRepository->removeByUserTablenameObjectUid($user['uid'], $tablename, $objectUid); + $this->forward('personalList'); + } + + + /** + */ + public function personalListAction() + { + + $user = $this->getCurrentUser(); + + $bookmarks = []; + + $objs = $this->bookmarkRepository->findByUser($user['uid']); + + /** @var Bookmark $obj */ + foreach ($objs as $obj) { + $bookmark = []; + $bookmark['tablename'] = $obj->getTablename(); + $bookmark['object_uid'] = $obj->getObjectUid(); + + if ($obj->getTablename() === 'pages') { + + $page = BackendUtility::getRecord('pages',$obj->getObjectUid(),'title'); + if ($page) { + + $bookmark['title'] = $page['title']; + $bookmark['url'] = $this->uriBuilder->reset()->setTargetPageUid($obj->getObjectUid())->buildFrontendUri(); + } + + $bookmarks[] = $bookmark; + } + + + } + + $this->view->assignMultiple([ + 'bookmarks' => $bookmarks + ]); + } + + +} diff --git a/Classes/Controller/BookmarksController.php b/Classes/Controller/BookmarksController.php deleted file mode 100644 index e7795cc..0000000 --- a/Classes/Controller/BookmarksController.php +++ /dev/null @@ -1,109 +0,0 @@ -view->assignMultiple([ - 'bookmark' => $bookmark->toArray() - ]); - } - - /** - * Adds the current page as bookmark and renders/returns updated list as html - * - * This is meant to be called by ajax (typoscript_rendering) - * - * @param array $localBookmarks - */ - public function bookmarkAction($localBookmarks = []) - { - // use the parameter directly and ignore chash because url is submitted by JS - $url = GeneralUtility::_GP('url'); - $url = $url ? $url : null; - - $bookmark = Bookmark::createFromCurrent($url); - - $bookmarks = new Bookmarks(); - $bookmarks->merge($localBookmarks); - $bookmarks->addBookmark($bookmark); - $bookmarks->persist(); - - $this->updateAndSendList($bookmarks); - } - - /** - * Remove a bookmark from list and renders/returns updated list as html - * - * This is meant to be called by ajax (typoscript_rendering) - * - * @param string $id - * @param array $localBookmarks - */ - public function deleteAction($id = '', $localBookmarks = []) - { - $bookmarks = new Bookmarks(); - $bookmarks->merge($localBookmarks); - if ($id) { - $bookmarks->removeBookmark($id); - $bookmarks->persist(); - } - $this->updateAndSendList($bookmarks); - } - - /** - * Action to get bookmark list - * - * @param array $localBookmarks - */ - public function listEntriesAction($localBookmarks = []) - { - $bookmarks = new Bookmarks(); - $bookmarks->merge($localBookmarks); - $this->updateAndSendList($bookmarks); - } - - /** - * This is for ajax requests - * - * @param Bookmarks $bookmarks - */ - public function updateAndSendList(Bookmarks $bookmarks) - { - // check if we bookmarked the current page - $bookmark = Bookmark::createFromCurrent(); - $isBookmarked = $bookmarks->bookmarkExists($bookmark); - - // build the ajax response data - $response = [ - 'isBookmarked' => $isBookmarked, - 'bookmarks' => $bookmarks->getBookmarksForLocalStorage() - ]; - - header('Content-Type: application/json'); - echo json_encode($response); - die(); - } -} diff --git a/Classes/Controller/LikeController.php b/Classes/Controller/LikeController.php new file mode 100644 index 0000000..2990f4b --- /dev/null +++ b/Classes/Controller/LikeController.php @@ -0,0 +1,1368 @@ +accessControlService = $accessControlService; + } + + /** + * @var \WapplerSystems\BookmarksLikesRatings\Service\JsonService + */ + protected $jsonService; + + /** + * @param \WapplerSystems\BookmarksLikesRatings\Service\JsonService $jsonService + */ + public function injectJsonService(\WapplerSystems\BookmarksLikesRatings\Service\JsonService $jsonService) + { + $this->jsonService = $jsonService; + } + + /** + * @var \WapplerSystems\BookmarksLikesRatings\Service\RichSnippetService + */ + protected $richSnippetService; + + /** + * @param \WapplerSystems\BookmarksLikesRatings\Service\RichSnippetService $richSnippetService + */ + public function injectRichSnippetService(RichSnippetService $richSnippetService): void + { + $this->richSnippetService = $richSnippetService; + } + + /** + * @var \WapplerSystems\BookmarksLikesRatings\Service\CookieService + */ + protected $cookieService; + + /** + * @param \WapplerSystems\BookmarksLikesRatings\Service\CookieService $cookieService + */ + public function injectCookieService(CookieService $cookieService): void + { + $this->cookieService = $cookieService; + } + + /** + * @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\Domain\Validator\VoteValidator + */ + protected $voteValidator; + + /** + * @param \WapplerSystems\BookmarksLikesRatings\Domain\Validator\VoteValidator $voteValidator + */ + public function injectVoteValidator(VoteValidator $voteValidator): void + { + $this->voteValidator = $voteValidator; + } + + /** + * @var \WapplerSystems\BookmarksLikesRatings\Domain\Validator\RatingValidator + */ + protected $ratingValidator; + + /** + * @param \WapplerSystems\BookmarksLikesRatings\Domain\Validator\RatingValidator $ratingValidator + */ + public function injectRatingValidator(RatingValidator $ratingValidator): void + { + $this->ratingValidator = $ratingValidator; + } + + /** + * @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\StepconfRepository + */ + protected $stepconfRepository; + + /** + * @param \WapplerSystems\BookmarksLikesRatings\Domain\Repository\StepconfRepository $stepconfRepository + */ + public function injectStepconfRepository(StepconfRepository $stepconfRepository): void + { + $this->stepconfRepository = $stepconfRepository; + } + + /** + * @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 \WapplerSystems\BookmarksLikesRatings\Service\ExtensionHelperService + */ + protected $extensionHelperService; + + /** + * @param \WapplerSystems\BookmarksLikesRatings\Service\ExtensionHelperService $extensionHelperService + */ + public function injectExtensionHelperService(ExtensionHelperService $extensionHelperService): void + { + $this->extensionHelperService = $extensionHelperService; + } + + /** + * @var \WapplerSystems\BookmarksLikesRatings\Service\ExtensionConfigurationService + */ + protected $extensionConfigurationService; + + /** + * @param \WapplerSystems\BookmarksLikesRatings\Service\ExtensionConfigurationService $extensionConfigurationService + */ + public function injectExtensionConfigurationService(ExtensionConfigurationService $extensionConfigurationService): void + { + $this->extensionConfigurationService = $extensionConfigurationService; + } + + + public function initializeStatusAction() + { + $this->defaultViewObjectName = JsonView::class; + } + + /** + * @param int $objectUid + * @param string $tablename + * @throws \TYPO3\CMS\Frontend\Exception + */ + public function statusAction(int $objectUid, string $tablename) + { + + $user = $this->getCurrentUser(); + + $this->view->setVariablesToRender(['status']); + $this->view->assignMultiple([ + 'status' => ['status' => $this->likeRepository->countByUserTablenameObjectUid($user['uid'], $tablename, $objectUid) === 0 ? 'false' : 'true'] + ]); + + } + + + public function initializeToggleAction() + { + $this->defaultViewObjectName = JsonView::class; + } + + /** + * @param int $objectUid + * @param string $tablename + * @throws \TYPO3\CMS\Frontend\Exception + */ + public function toggleAction(int $objectUid, string $tablename) + { + + $user = $this->getCurrentUser(); + + $this->view->setVariablesToRender(['status']); + + if ($this->likeRepository->countByUserTablenameObjectUid($user['uid'], $tablename, $objectUid) === 0) { + + $like = new Like(); + $like->setUser($user['uid']); + $like->setTablename($tablename); + $like->setObjectUid($objectUid); + + $this->likeRepository->add($like); + + $this->view->assignMultiple([ + 'status' => ['status' => 'true'] + ]); + } else { + $this->likeRepository->removeByUserTablenameObjectUid($user['uid'], $tablename, $objectUid); + + $this->view->assignMultiple([ + 'status' => ['status' => 'false'] + ]); + } + + } + + + + + + /** + * Initializes the current action + * + * @throws FeUserStoragePageException + * @throws InvalidStoragePageException + * @throws \Exception + * @throws \TYPO3\CMS\Extbase\Mvc\Exception\NoSuchArgumentException + */ + /** @noinspection PhpMissingParentCallCommonInspection */ + protected function initialize3Action(): void + { + //instantiate the logger + $this->logger = GeneralUtility::makeInstance(ObjectManager::class) + ->get(ExtensionHelperService::class)->getLogger(__CLASS__); + + $this->logger->log(LogLevel::DEBUG, 'Entry point'); + + $this->prefixId = + strtolower("tx_{$this->request->getControllerExtensionName()}_{$this->request->getPluginName()}"); + + //Set default storage pids + $this->extensionConfigurationService->setExtDefaultQuerySettings(); + + //make current request object avaiable to other classes + $this->extensionHelperService->setRequest($this->request); + + $frameworkConfiguration = $this->configurationManager->getConfiguration( + ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK + ); + + if ($this->request->hasArgument(self::AJAX_REFERENCE_ID)) { + //switch to JSON respone on AJAX request + $this->request->setFormat('json'); + $this->defaultViewObjectName = JsonView::class; + //read unique AJAX identification on AJAX request + $this->ajaxSelections['ajaxRef'] = $this->request->getArgument(self::AJAX_REFERENCE_ID); + /** @noinspection PhpElementIsNotAvailableInCurrentPhpVersionInspection */ + $this->settings = $this->jsonService->decodeJsonToArray($this->request->getArgument('settings')); + $frameworkConfiguration['settings'] = $this->settings; + $this->logger->log( + LogLevel::INFO, + 'AJAX request detected - set new frameworkConfiguration', + $frameworkConfiguration + ); + //\TYPO3\CMS\Extbase\Utility\DebuggerUtility::var_dump($this->settings,get_class($this).' initializeAction'); + } else { + //set unique AJAX identification + $this->ajaxSelections['ajaxRef'] = $this->prefixId . '_' . $this->getRandomId(); + $this->logger->log(LogLevel::DEBUG, 'Set id for AJAX requests', $this->ajaxSelections); + } + + if (!is_array($frameworkConfiguration['ratings'])) { + $frameworkConfiguration['ratings'] = []; + } + ArrayUtility::mergeRecursiveWithOverrule( + $this->settings['ratingConfigurations'], + $frameworkConfiguration['ratings'] + ); + $this->setCookieProtection(); + } + + /** + * Index action for this controller. + */ + public function indexAction(): void + { + // @var \WapplerSystems\BookmarksLikesRatings\Domain\Model\Ratingobject $ratingobject + //update foreign table for each rating + foreach ($this->ratingobjectRepository->findAll() as $ratingobject) { + foreach ($ratingobject->getRatings() as $rating) { + $this->setForeignRatingValues($rating); + } + } + $this->view->assign('ratingobjects', $this->ratingobjectRepository->findAll()); + + //initialize ratingobject and autocreate four ratingsteps + $ratingobject = $this->objectManager + ->get(ExtensionManagementService::class) + ->makeRatable('TestTable', 'TestField', 4); + + /** @var \WapplerSystems\BookmarksLikesRatings\Domain\Model\Stepconf $stepconf */ + $stepconf = $ratingobject->getStepconfs()->current(); + + //add descriptions in default language to each stepconf + $this->objectManager->get(ExtensionManagementService::class)->setStepname( + $stepconf, + 'Automatic generated entry ', + null, + true + ); + //add descriptions in german language to each stepconf + $this->objectManager->get(ExtensionManagementService::class)->setStepname( + $stepconf, + 'Automatischer Eintrag ', + 'de', + true + ); + } + + /** + * Includes the hidden form to handle AJAX requests + * + * @noinspection PhpUnused + */ + public function singletonAction(): void + { + $this->logger->log(LogLevel::DEBUG, 'Entry singletonAction'); + + $messageArray = $this->extensionHelperService->renderDynCSS(); + //generate dynamic CSS file and add messages to flashMessageQueue + foreach ($messageArray as $message) { + $this->logFlashMessage( + $message['messageText'], + $message['messageTitle'], + $message['severity'], + $message['additionalInfo'] + ); + } + $this->controllerContext->getFlashMessageQueue()->clear(); + $this->logger->log(LogLevel::DEBUG, 'Exit singletonAction'); + } + + /** + * Displays the vote of the current user + * + * @param \WapplerSystems\BookmarksLikesRatings\Domain\Model\Vote $vote + * @Extbase\IgnoreValidation("vote") + * @throws \TYPO3\CMS\Core\Exception + * @throws \WapplerSystems\BookmarksLikesRatings\Exception\InvalidAggregateRatingSchemaTypeException + * @throws \WapplerSystems\BookmarksLikesRatings\Exception\RecordNotFoundException + * @noinspection PhpUnused + */ + public function showAction(Vote $vote = null): void + { + $this->logger->log(LogLevel::DEBUG, 'Entry showAction'); + //is_object($vote) && \TYPO3\CMS\Extbase\Utility\DebuggerUtility::var_dump($vote->getUid(),'showAction'); + $this->initVoting($vote); //just to set all properties + + $this->fillSummaryView(); + if (!$this->voteValidator->validate($this->vote)->hasErrors()) { + if ($this->accessControlService->isLoggedIn($vote->getVoter()) || $vote->isAnonymous()) { + } else { + $this->logFlashMessage( + LocalizationUtility::translate('flash.vote.create.noPermission', 'ThRating'), + LocalizationUtility::translate('flash.heading.error', 'ThRating'), + 'ERROR', + ['errorCode' => 1403201246] + ); + } + } + $this->view->assign('actionMethodName', $this->actionMethodName); + $this->logger->log(LogLevel::DEBUG, 'Exit showAction'); + } + + /** + * Creates a new vote + * + * @param \WapplerSystems\BookmarksLikesRatings\Domain\Model\Vote $vote + * @throws \TYPO3\CMS\Core\Exception + * @throws \TYPO3\CMS\Extbase\Mvc\Exception\NoSuchArgumentException + * @throws \TYPO3\CMS\Extbase\Mvc\Exception\StopActionException + * @throws \TYPO3\CMS\Extbase\SignalSlot\Exception\InvalidSlotException + * @throws \TYPO3\CMS\Extbase\SignalSlot\Exception\InvalidSlotReturnException + * @noinspection PhpUnused + */ + public function createAction(\WapplerSystems\BookmarksLikesRatings\Domain\Model\Vote $vote): void + { + //http://localhost:8503/index.php?id=71&tx_thrating_pi1[controller]=Vote&tx_thrating_pi1[action]=create& + //tx_thrating_pi1[vote][rating]=1&tx_thrating_pi1[vote][voter]=1&tx_thrating_pi1[vote][vote]=1 + $this->logger->log(LogLevel::DEBUG, 'Entry createAction', ['errorCode' => 1404934047]); + if ($this->accessControlService->isLoggedIn($vote->getVoter()) || $vote->isAnonymous()) { + $this->logger->log(LogLevel::DEBUG, 'Start processing', ['errorCode' => 1404934054]); + + /** @var \WapplerSystems\BookmarksLikesRatings\Domain\Model\Vote $matchVote */ + $matchVote = null; + + //if not anonymous check if vote is already done + if (!$vote->isAnonymous()) { + $this->logger->log( + LogLevel::DEBUG, + 'FE user is logged in - looking for existing vote', + ['errorCode' => 1404933999] + ); + $matchVote = $this->voteRepository->findMatchingRatingAndVoter($vote->getRating(), $vote->getVoter()); + } + //add new or anonymous vote + if ($this->voteValidator->validate($matchVote)->hasErrors() || $vote->isAnonymous()) { + $this->logger->log(LogLevel::DEBUG, 'New vote could be added', ['errorCode' => 1404934012]); + $vote->getRating()->addVote($vote); + if ($this->cookieProtection && $vote->isAnonymous() && !$vote->hasAnonymousVote($this->prefixId)) { + $this->logger->log( + LogLevel::DEBUG, + 'Anonymous rating; preparing cookie potection', + ['errorCode' => 1404934021] + ); + $anonymousRating['ratingtime'] = time(); + $anonymousRating['voteUid'] = $vote->getUid(); + //TODO: switch to session store according to https://t3terminal.com/blog/de/typo3-cookie/ + if (!empty($this->cookieLifetime)) { + $expireTime = (new \DateTime('NOW'))->add(\DateInterval::createFromDateString($this->cookieLifetime . ' days'))->getTimestamp(); + + //set cookie to prevent multiple anonymous ratings + $this->cookieService->setVoteCookie( + $this->prefixId . '_AnonymousRating_' . $vote->getRating()->getUid(), + $this->jsonService->encodeToJson($anonymousRating), + $expireTime + ); + } + } + $setResult = $this->setForeignRatingValues($vote->getRating()); + if (!$setResult) { + $this->logFlashMessage( + LocalizationUtility::translate('flash.vote.create.foreignUpdateFailed', 'ThRating'), + LocalizationUtility::translate('flash.heading.warning', 'ThRating'), + 'WARNING', + [ + 'errorCode' => 1403201551, + 'ratingobject' => $vote->getRating()->getRatingobject()->getUid(), + 'ratetable' => $vote->getRating()->getRatingobject()->getRatetable(), + 'ratefield' => $vote->getRating()->getRatingobject()->getRatefield() + ] + ); + } + $this->logFlashMessage( + LocalizationUtility::translate('flash.vote.create.newCreated', 'ThRating'), + LocalizationUtility::translate('flash.heading.ok', 'ThRating'), + 'DEBUG', + [ + 'ratingobject' => $vote->getRating()->getRatingobject()->getUid(), + 'ratetable' => $vote->getRating()->getRatingobject()->getRatetable(), + 'ratefield' => $vote->getRating()->getRatingobject()->getRatefield(), + 'voter' => $vote->getVoter()->getUsername(), + 'vote' => (string)$vote->getVote() + ] + ); + } elseif (!empty($this->settings['enableReVote']) && + !$this->voteValidator->validate($matchVote)->hasErrors()) { + /** @var \WapplerSystems\BookmarksLikesRatings\Domain\Model\Stepconf $matchVoteStepconf */ + $matchVoteStepconf = $matchVote->getVote(); + /** @var \WapplerSystems\BookmarksLikesRatings\Domain\Model\Stepconf $newVoteStepconf */ + $newVoteStepconf = $vote->getVote(); + if ($matchVoteStepconf !== $newVoteStepconf) { + //do update of existing vote + $this->logFlashMessage( + LocalizationUtility::translate( + 'flash.vote.create.updateExistingVote', + 'ThRating', + [$matchVoteStepconf->getSteporder(), (string)$matchVoteStepconf] + ), + LocalizationUtility::translate('flash.heading.ok', 'ThRating'), + 'DEBUG', + [ + 'voter UID' => $vote->getVoter()->getUid(), + 'ratingobject UID' => $vote->getRating()->getRatingobject()->getUid(), + 'rating' => $vote->getRating()->getUid(), + 'vote UID' => $vote->getUid(), + 'new vote' => (string)$vote->getVote(), + 'old vote' => (string)$matchVoteStepconf + ] + ); + $vote->getRating()->updateVote($matchVote, $vote); + } else { + $this->logFlashMessage( + LocalizationUtility::translate('flash.vote.create.noUpdateSameVote', 'ThRating'), + LocalizationUtility::translate('flash.heading.warning', 'ThRating'), + 'WARNING', + [ + 'voter UID' => $vote->getVoter()->getUid(), + 'ratingobject UID' => $vote->getRating()->getRatingobject()->getUid(), + 'rating' => $vote->getRating()->getUid(), + 'vote UID' => $vote->getUid(), + 'new vote' => (string)$newVoteStepconf, + 'old vote' => (string)$matchVoteStepconf + ] + ); + } + } else { + //display message that rating has been already done + $vote = $matchVote; + $this->logFlashMessage( + LocalizationUtility::translate('flash.vote.create.alreadyRated', 'ThRating'), + LocalizationUtility::translate('flash.heading.notice', 'ThRating'), + 'NOTICE', + [ + 'errorCode' => 1403202280, + 'voter UID' => $vote->getVoter()->getUid(), + 'ratingobject UID' => $vote->getRating()->getRatingobject()->getUid(), + 'rating' => $vote->getRating()->getUid(), + 'vote UID' => $vote->getUid() + ] + ); + } + $this->vote = $vote; + } else { + $this->logFlashMessage( + LocalizationUtility::translate('flash.vote.create.noPermission', 'ThRating'), + LocalizationUtility::translate('flash.heading.error', 'ThRating'), + 'ERROR', + ['errorCode' => 1403203210] + ); + } + + $referrer = $this->request->getInternalArgument('__referrer'); + $newArguments = $this->request->getArguments(); + //replace vote argument with correct vote if user has already rated + $newArguments['vote']['vote'] = $this->vote->getVote(); + unset($newArguments['action'], $newArguments['controller']); + + //Send signal to connected slots + $this->initSignalSlotDispatcher('afterCreateAction'); + $newArguments = ['signalSlotHandlerContent' => $this->signalSlotHandlerContent] + $newArguments; + + $this->logger->log(LogLevel::DEBUG, 'Exit createAction - forwarding request', [ + 'action' => $referrer['@action'], /** @phpstan-ignore-line */ + 'controller' => $referrer['@controller'], /** @phpstan-ignore-line */ + 'extension' => $referrer['@extension'], /** @phpstan-ignore-line */ + 'arguments' => $newArguments + ]); + $this->controllerContext->getFlashMessageQueue()->clear(); + /** @var array $referrer */ + $this->forward($referrer['@action'], $referrer['@controller'], $referrer['@extension'], $newArguments); + } + + /** + * FE user gives a new vote by SELECT form + * A classic SELECT input form will be provided to AJAX-submit the vote + * + * @param \WapplerSystems\BookmarksLikesRatings\Domain\Model\Vote|null $vote The new vote (used on callback from createAction) + * @Extbase\IgnoreValidation("vote") + * @throws \WapplerSystems\BookmarksLikesRatings\Exception\InvalidAggregateRatingSchemaTypeException + * @throws \TYPO3\CMS\Core\Exception + * @throws \WapplerSystems\BookmarksLikesRatings\Exception\RecordNotFoundException + * @noinspection PhpUnused + */ + public function newAction(Vote $vote = null): void + { + $this->logger->log(LogLevel::DEBUG, 'Entry newAction'); + //find vote using additional information + $this->initSettings(); + $this->initVoting($vote); + $this->view->assign('actionMethodName', $this->actionMethodName); + if (!$this->vote->hasRated() || + (!$this->accessControlService->isLoggedIn($this->vote->getVoter()) && $this->vote->isAnonymous())) { + $this->view->assign('ajaxSelections', $this->ajaxSelections['json']); + } else { + $this->logger->log(LogLevel::INFO, 'New rating is not possible; forwarding to showAction'); + } + $this->fillSummaryView(); + if ($this->view instanceof JsonView) { + $this->view->assign('flashMessages', $this->view->getFlashMessages()); + } + $this->logger->log(LogLevel::DEBUG, 'Exit newAction'); + } + + /** + * FE user gives a new vote by using a starrating obejct + * A graphic starrating object containing links will be provided to AJAX-submit the vote + * + * @param \WapplerSystems\BookmarksLikesRatings\Domain\Model\Vote $vote The new vote + * @Extbase\IgnoreValidation("vote") + * @throws \TYPO3\CMS\Extbase\Mvc\Exception\NoSuchArgumentException + * @throws \TYPO3\CMS\Extbase\SignalSlot\Exception\InvalidSlotException + * @throws \TYPO3\CMS\Extbase\SignalSlot\Exception\InvalidSlotReturnException + * @throws \WapplerSystems\BookmarksLikesRatings\Exception\InvalidAggregateRatingSchemaTypeException* + * @throws \WapplerSystems\BookmarksLikesRatings\Exception\RecordNotFoundException + * @throws \TYPO3\CMS\Core\Exception + */ + //http://localhost:8503/index.php?id=71&tx_thrating_pi1[controller]=Vote&tx_thrating_pi1[action]=ratinglinks + public function ratinglinksAction(Vote $vote = null): void + { + //\TYPO3\CMS\Extbase\Utility\DebuggerUtility::var_dump($this->view,get_class($this).' ratinglinksAction'); + $this->logger->log(LogLevel::DEBUG, 'Entry ratinglinksAction'); + $this->settings['ratingConfigurations']['default'] = + $this->settings['defaultRatingConfiguration']['ratinglinks']; + $this->graphicActionHelper($vote); + $this->initSignalSlotDispatcher('afterRatinglinkAction'); + $this->logger->log(LogLevel::DEBUG, 'Exit ratinglinksAction'); + } + + /** + * Handle graphic pollings + * Graphic bars containing links will be provided to AJAX-submit the polling + * + * @param \WapplerSystems\BookmarksLikesRatings\Domain\Model\Vote $vote The new vote + * @Extbase\IgnoreValidation("vote") + * @throws \TYPO3\CMS\Extbase\Mvc\Exception\NoSuchArgumentException + * @throws \TYPO3\CMS\Extbase\SignalSlot\Exception\InvalidSlotException + * @throws \TYPO3\CMS\Extbase\SignalSlot\Exception\InvalidSlotReturnException + * @throws \WapplerSystems\BookmarksLikesRatings\Exception\InvalidAggregateRatingSchemaTypeException* + * @throws \WapplerSystems\BookmarksLikesRatings\Exception\RecordNotFoundException + * @throws \TYPO3\CMS\Core\Exception + * @noinspection PhpUnused + */ + public function pollingAction(Vote $vote = null): void + { + //\TYPO3\CMS\Extbase\Utility\DebuggerUtility::var_dump($this->view,get_class($this).' pollingAction'); + $this->logger->log(LogLevel::DEBUG, 'Entry pollingAction'); + $this->settings['ratingConfigurations']['default'] = + $this->settings['defaultRatingConfiguration']['polling']; + + $this->graphicActionHelper($vote); + $this->initSignalSlotDispatcher('afterPollingAction'); + $this->logger->log(LogLevel::DEBUG, 'Exit pollingAction'); + } + + /** + * Handle mark action + * An icon containing for the mark action will be provided for AJAX-submission + * + * @param \WapplerSystems\BookmarksLikesRatings\Domain\Model\Vote $vote The new vote + * @Extbase\IgnoreValidation("vote") + * @throws \TYPO3\CMS\Extbase\Mvc\Exception\NoSuchArgumentException + * @throws \TYPO3\CMS\Extbase\SignalSlot\Exception\InvalidSlotException + * @throws \TYPO3\CMS\Extbase\SignalSlot\Exception\InvalidSlotReturnException + * @throws \WapplerSystems\BookmarksLikesRatings\Exception\InvalidAggregateRatingSchemaTypeException* + * @throws \TYPO3\CMS\Core\Exception + * @throws \WapplerSystems\BookmarksLikesRatings\Exception\RecordNotFoundException + */ + public function markAction(\WapplerSystems\BookmarksLikesRatings\Domain\Model\Vote $vote = null): void + { + $this->logger->log(LogLevel::DEBUG, 'Entry markAction'); + $this->settings['ratingConfigurations']['default'] = $this->settings['defaultRatingConfiguration']['mark']; + + $this->graphicActionHelper($vote); + + $this->initSignalSlotDispatcher('afterMarkAction'); + $this->logger->log(LogLevel::DEBUG, 'Exit markAction'); + } + + /** + * FE user gives a new vote by using a starrating obejct + * A graphic starrating object containing links will be provided to AJAX-submit the vote + * + * @param \WapplerSystems\BookmarksLikesRatings\Domain\Model\Vote|null $vote The new vote + * @Extbase\IgnoreValidation("vote") + * @throws \WapplerSystems\BookmarksLikesRatings\Exception\InvalidAggregateRatingSchemaTypeException* + * @throws \TYPO3\CMS\Core\Exception + * @throws \WapplerSystems\BookmarksLikesRatings\Exception\RecordNotFoundException + */ + //http://localhost:8503/index.php?id=71&tx_thrating_pi1[controller]=Vote&tx_thrating_pi1[action]=ratinglinks + public function graphicActionHelper(Vote $vote = null): void + { + $this->logger->log(LogLevel::DEBUG, 'Entry graphicActionHelper'); + $this->initSettings(); + $this->initVoting($vote); + $this->view->assign('actionMethodName', $this->actionMethodName); + + $rating = $this->vote->getRating(); + if (!$this->ratingValidator->validate($rating)->hasErrors()) { + $this->ratingImage = $this->objectManager->get(\WapplerSystems\BookmarksLikesRatings\Domain\Model\RatingImage::class); + $this->ratingImage->setConf($this->settings['ratingConfigurations'][$this->ratingName]['imagefile']); + //read dimensions of the image + $imageDimensions = $this->ratingImage->getImageDimensions(); + $height = $imageDimensions['height']; + $width = $imageDimensions['width']; + + //calculate concrete values for polling display + $currentRates = $rating->getCurrentrates(); + $currentPollDimensions = $currentRates['currentPollDimensions']; + + foreach ($currentPollDimensions as $step => $currentPollDimension) { + $currentPollDimensions[$step]['steporder'] = $step; + $currentPollDimensions[$step]['backgroundPos'] = round( + $height / 3 * (($currentPollDimension['pctValue'] / 100) - 2), + 1 + ); + $currentPollDimensions[$step]['backgroundPosTilt'] = round( + $width / 3 * (($currentPollDimension['pctValue'] / 100) - 2), + 1 + ); + } + + $this->logger->log( + LogLevel::DEBUG, + 'Current polling dimensions', + ['currentPollDimensions' => $currentPollDimensions] + ); + $this->view->assign('currentPollDimensions', $currentPollDimensions); + } + $this->view->assign('ratingName', $this->ratingName); + $this->view->assign('ratingClass', $this->settings['ratingClass']); + if ((!$this->vote->isAnonymous() && + $this->accessControlService->isLoggedIn($this->vote->getVoter()) && + (!$this->vote->hasRated() || !empty($this->settings['enableReVote']))) || + ( + ($this->vote->isAnonymous() && + !$this->accessControlService->isLoggedIn($this->vote->getVoter())) && + ( + (!$this->vote->hasAnonymousVote($this->prefixId) && + $this->cookieProtection && + !$this->request->hasArgument('settings')) || + !$this->cookieProtection + ) + ) + ) { + //if user hasn�t voted yet then include ratinglinks + $this->view->assign('ajaxSelections', $this->ajaxSelections['steporder']); + $this->logger->log( + LogLevel::INFO, + 'Set ratinglink information', + ['errorCode' => 1404933850, 'ajaxSelections[steporder]' => $this->ajaxSelections['steporder']] + ); + } + $this->fillSummaryView(); + if ($this->view instanceof JsonView) { + $this->view->assign( + 'flashMessages', + $this->view->getFlashMessages() + ); + } + $this->logger->log(LogLevel::DEBUG, 'Exit graphicActionHelper'); + } + + /** + * Initialize signalSlotHandler for given action + * Registered slots are being called with two parameters + * 1. signalSlotMessage: an array consisting of + * 'tablename' - the tablename of the rated object + * 'fieldname' - the fieldname of the rated object + * 'uid' - the uid of the rated object + * 'currentRates' - an array constising of the actual rating statistics + * 'currentrate' - the calculated overall rating + * 'weightedVotes' - an array giving the voting counts for every ratingstep + * 'sumWeightedVotes' an array giving the voting counts for every ratingstep multiplied by their weights + * 'anonymousVotes' - count of anonymous votings + * if the user has voted anonymous or non-anonymous: + * 'voter' - the uid of the frontenduser that has voted + * 'votingStep' - the ratingstep that has been choosen + * 'votingName' - the name of the ratingstep + * 'anonymousVote' - boolean info if it was an anonymous rating + * + * @param string $slotName the slotname + * @throws \TYPO3\CMS\Extbase\Mvc\Exception\NoSuchArgumentException + * @throws \TYPO3\CMS\Extbase\SignalSlot\Exception\InvalidSlotException + * @throws \TYPO3\CMS\Extbase\SignalSlot\Exception\InvalidSlotReturnException + */ + protected function initSignalSlotDispatcher(string $slotName): void + { + $this->logger->log(LogLevel::DEBUG, 'Entry initSignalSlotDispatcher', ['slotName' => $slotName]); + if ($this->request->hasArgument('signalSlotHandlerContent')) { + //set orginal handlerContent if action has been forwarded + $this->signalSlotHandlerContent = $this->request->getArgument('signalSlotHandlerContent'); + $this->logger->log( + LogLevel::INFO, + 'Fetch static SignalSlotHandlerContent', + ['signalSlotHandlerContent' => $this->signalSlotHandlerContent] + ); + } else { + $signalSlotMessage = []; + $signalSlotMessage['tablename'] = $this->vote->getRating()->getRatingobject()->getRatetable(); + $signalSlotMessage['fieldname'] = $this->vote->getRating()->getRatingobject()->getRatefield(); + $signalSlotMessage['uid'] = (int)$this->vote->getRating()->getRatedobjectuid(); + $signalSlotMessage['currentRates'] = $this->vote->getRating()->getCurrentrates(); + if (!$this->voteValidator->validate($this->vote)->hasErrors()) { + $signalSlotMessage['voter'] = $this->vote->getVoter()->getUid(); + $signalSlotMessage['votingStep'] = $this->vote->getVote()->getSteporder(); + $signalSlotMessage['votingName'] = (string)$this->vote->getVote()->getStepname(); + $signalSlotMessage['anonymousVote'] = $this->vote->isAnonymous(); + } + $this->logger->log( + LogLevel::INFO, + 'Going to process signalSlot', + ['signalSlotMessage' => $signalSlotMessage] + ); + + //clear signalSlotHandlerArray for sure + $this->signalSlotHandlerContent = []; + $this->signalSlotDispatcher->dispatch( + __CLASS__, + $slotName, + [$signalSlotMessage, &$this->signalSlotHandlerContent] + ); + $this->logger->log( + LogLevel::INFO, + 'New signalSlotHandlerContent', + ['signalSlotHandlerContent' => $this->signalSlotHandlerContent] + ); + } + $this->view->assign('staticPreContent', $this->signalSlotHandlerContent['staticPreContent']); + $this->view->assign('staticPostContent', $this->signalSlotHandlerContent['staticPostContent']); + unset( + $this->signalSlotHandlerContent['staticPreContent'], + $this->signalSlotHandlerContent['staticPostContent'] + ); + $this->view->assign('preContent', $this->signalSlotHandlerContent['preContent']); + $this->view->assign('postContent', $this->signalSlotHandlerContent['postContent']); + $this->logger->log(LogLevel::DEBUG, 'Exit initSignalSlotDispatcher'); + } + + /** + * Check preconditions for rating + * + * @param \WapplerSystems\BookmarksLikesRatings\Domain\Model\Vote $vote the vote this selection is for + * @throws \WapplerSystems\BookmarksLikesRatings\Exception\RecordNotFoundException + * @throws \TYPO3\CMS\Core\Exception + */ + protected function initVoting(Vote $vote = null): void + { + $this->logger->log(LogLevel::DEBUG, 'Entry initVoting'); + + $logVoterUid = 0; + + if ($this->voteValidator->isObjSet($vote) && !$this->voteValidator->validate($vote)->hasErrors()) { + $this->vote = $vote; + $this->logger->log(LogLevel::DEBUG, 'Using valid vote'); + } else { + $this->logger->log(LogLevel::DEBUG, 'initVoting ELSE'); + //first initialize parent objects for vote object + $ratingobject = $this->extensionHelperService->getRatingobject($this->settings); + $rating = $this->extensionHelperService->getRating($this->settings, $ratingobject); + $this->vote = $this->extensionHelperService->getVote($this->prefixId, $this->settings, $rating); + + $countSteps = count($ratingobject->getStepconfs()); + if (empty($countSteps)) { + $this->logger->log(LogLevel::DEBUG, 'No ratingsteps configured', ['errorCode' => 1403201012]); + $this->logFlashMessage( + LocalizationUtility::translate('flash.ratingobject.noRatingsteps', 'ThRating'), + LocalizationUtility::translate('flash.heading.error', 'ThRating'), + 'ERROR', + ['errorCode' => 1403201012] + ); + } + + if (!$this->vote->getVoter() instanceof \WapplerSystems\BookmarksLikesRatings\Domain\Model\Voter) { + if (!empty($this->settings['showNoFEUser'])) { + $this->logFlashMessage( + LocalizationUtility::translate('flash.vote.noFEuser', 'ThRating'), + LocalizationUtility::translate('flash.heading.notice', 'ThRating'), + 'NOTICE', + ['errorCode' => 1403201096] + ); + } + } else { + $logVoterUid = $this->vote->getVoter()->getUid(); + } + } + $this->logger->log(LogLevel::INFO, 'Using vote', [ + 'ratingobject' => $this->vote->getRating()->getRatingobject()->getUid(), + 'rating' => $this->vote->getRating()->getUid(), + 'voter' => $logVoterUid + ]); + //set array to create voting information + $this->setAjaxSelections($this->vote); + $this->logger->log(LogLevel::DEBUG, 'Exit initVoting'); + } + + /** + * Check preconditions for settings + */ + protected function initSettings(): void + { + $this->logger->log(LogLevel::DEBUG, 'Entry initSettings'); + + //switch display mode to correct config if nothing is set + if (empty($this->settings['display'])) { + $this->settings['display'] = $this->settings['ratingConfigurations']['default']; + } + + //set display configuration + if (!empty($this->settings['display'])) { + if (isset($this->settings['ratingConfigurations'][$this->settings['display']])) { + $this->ratingName = $this->settings['display']; + } else { + //switch back to default if given display configuration does not exist + $this->ratingName = $this->settings['ratingConfigurations']['default']; + $this->logFlashMessage( + LocalizationUtility::translate('flash.vote.ratinglinks.wrongDisplayConfig', 'ThRating'), + LocalizationUtility::translate('flash.heading.error', 'ThRating'), + 'WARNING', + [ + 'errorCode' => 1403203414, + 'settings display' => $this->settings['display'], + 'avaiable ratingConfigurations' => $this->settings['ratingConfigurations'] + ] + ); + } + } else { + //choose default ratingConfiguration if nothing is defined + $this->ratingName = $this->settings['ratingConfigurations']['default']; + $this->logger->log( + LogLevel::WARNING, + 'Display name not set - using configured default', + ['default display' => $this->ratingName] + ); + } + $ratingConfiguration = $this->settings['ratingConfigurations'][$this->ratingName]; + //\TYPO3\CMS\Extbase\Utility\DebuggerUtility::var_dump( + //$this->settings,get_class($this).' settings '.$this->ratingName); + + //override extension settings with rating configuration settings + if (is_array($ratingConfiguration['settings'])) { + unset( + $ratingConfiguration['settings']['defaultObject'], + $ratingConfiguration['settings']['ratingConfigurations'] + ); + if (!is_array($ratingConfiguration['ratings'])) { + $ratingConfiguration['ratings'] = []; + } + ArrayUtility::mergeRecursiveWithOverrule($this->settings, $ratingConfiguration['settings']); + $this->logger->log( + LogLevel::DEBUG, + 'Override extension settings with rating configuration settings', + ['Original setting' => $this->settings, 'Overruling settings' => $ratingConfiguration['settings']] + ); + } + //override fluid settings with rating fluid settings + if (is_array($ratingConfiguration['fluid'])) { + ArrayUtility::mergeRecursiveWithOverrule($this->settings['fluid'], $ratingConfiguration['fluid']); + $this->logger->log(LogLevel::DEBUG, 'Override fluid settings with rating fluid settings'); + } + $this->logger->log(LogLevel::INFO, 'Final extension configuration', ['settings' => $this->settings]); + + //distinguish between bar and no-bar rating + $this->view->assign('barimage', 'noratingbar'); + if ($ratingConfiguration['barimage']) { + $this->view->assign('barimage', 'ratingbar'); + $this->logger->log(LogLevel::DEBUG, 'Set ratingbar config'); + } + + //set tilt or normal rating direction + $this->settings['ratingClass'] = 'normal'; + if ($ratingConfiguration['tilt']) { + $this->logger->log(LogLevel::DEBUG, 'Tilt rating class configuration'); + $this->settings['ratingClass'] = 'tilt'; + } + + $frameworkConfiguration = + $this->configurationManager->getConfiguration(ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK); + $frameworkConfiguration['settings'] = $this->settings; + + $this->configurationManager->setConfiguration($frameworkConfiguration); + $this->setCookieProtection(); + + $this->logger->log(LogLevel::DEBUG, 'Exit initSettings'); + } + + /** + * Build array of possible AJAX selection configuration + * + * @param \WapplerSystems\BookmarksLikesRatings\Domain\Model\Vote $vote the vote this selection is for + */ + protected function setAjaxSelections(Vote $vote): void + { + if (empty($this->settings['displayOnly']) && $vote->getVoter() instanceof Voter) { + //cleanup settings to reduce data size in POST form + $tmpDisplayConfig = $this->settings['ratingConfigurations'][$this->settings['display']]; + unset($this->settings['defaultObject'], $this->settings['ratingConfigurations']); + $this->settings['ratingConfigurations'][$this->settings['display']] = $tmpDisplayConfig; + //TODO: ?? $currentRates = $vote->getRating()->getCurrentrates(); + + /** @var \WapplerSystems\BookmarksLikesRatings\Domain\Model\Stepconf $stepConf */ + foreach ($vote->getRating()->getRatingobject()->getStepconfs() as $i => $stepConf) { + /** @noinspection PhpElementIsNotAvailableInCurrentPhpVersionInspection */ + $key = utf8_encode( + $this->jsonService->encodeToJson([ + 'value' => $stepConf->getUid(), + 'voter' => $vote->getVoter()->getUid(), + 'rating' => $vote->getRating()->getUid(), + 'ratingName' => $this->ratingName, + 'settings' => $this->jsonService->encodeToJson($this->settings), + 'actionName' => strtolower($this->request->getControllerActionName()), + self::AJAX_REFERENCE_ID => $this->ajaxSelections['ajaxRef'] + ]) + ); + $this->ajaxSelections['json'][$key] = (string)$stepConf; + $this->ajaxSelections['steporder'][$stepConf->getSteporder()]['step'] = $stepConf; + $this->ajaxSelections['steporder'][$stepConf->getSteporder()]['ajaxvalue'] = $key; + } + $this->logger->log( + LogLevel::DEBUG, + 'Finalized ajaxSelections', + ['ajaxSelections' => $this->ajaxSelections] + ); + } + } + + /** + * Fill all variables for FLUID + * + * @throws \WapplerSystems\BookmarksLikesRatings\Exception\InvalidAggregateRatingSchemaTypeException + */ + protected function fillSummaryView() + { + $this->view->assign('settings', $this->settings); + $this->view->assign('ajaxRef', $this->ajaxSelections['ajaxRef']); + $this->view->assign('rating', $this->vote->getRating()); + $this->view->assign('voter', $this->vote->getVoter()); + + if ($this->richSnippetService->setRichSnippetConfig($this->settings)) { + /** @var \WapplerSystems\BookmarksLikesRatings\Service\RichSnippetService $richSnippetObject */ + $richSnippetObject = + $this->richSnippetService->getRichSnippetObject($this->vote->getRating()->getRatedobjectuid()); + $richSnippetObject->setAnchor('RatingAX_' . $this->vote->getRating()->getRatingobject()->getUid() . + '_' . $this->vote->getRating()->getRatedobjectuid()); + if (empty($richSnippetObject->getName())) { + $richSnippetObject->setName('Rating AX ' . $this->vote->getRating()->getRatingobject()->getUid() . + '_' . $this->vote->getRating()->getRatedobjectuid()); + } + $this->view->assign('richSnippetObject', $richSnippetObject); + } + + $currentrate = $this->vote->getRating()->getCurrentrates(); + $this->view->assign('stepCount', count($currentrate['weightedVotes'])); + $this->view->assign('anonymousVotes', $currentrate['anonymousVotes']); + $this->view->assign( + 'anonymousVoting', + !empty($this->settings['mapAnonymous']) && !$this->accessControlService->getFrontendUserUid() + ); + if ($this->settings['showNotRated'] && empty($currentrate['currentrate'])) { + $this->logFlashMessage( + LocalizationUtility::translate('flash.vote.show.notRated', 'ThRating'), + LocalizationUtility::translate('flash.heading.info', 'ThRating'), + 'INFO', + ['errorCode' => 1403203414] + ); + } + if (!$this->voteValidator->validate($this->vote)->hasErrors()) { + /** @noinspection NotOptimalIfConditionsInspection */ + if (( + !$this->vote->isAnonymous() && + $this->vote->getVoter()->getUid() === $this->accessControlService->getFrontendUserUid() + ) || ($this->vote->isAnonymous() && ($this->vote->hasAnonymousVote($this->prefixId) || + $this->cookieProtection || $this->cookieService->isProtected()))) { + $this->view->assign('protected', $this->cookieService->isProtected()); + $this->view->assign('voting', $this->vote); + $this->view->assign( + 'usersRate', + $this->vote->getVote()->getSteporder() * 100 / count($currentrate['weightedVotes']) . '%' + ); + } + } + //$this->view->assign('LANG', \WapplerSystems\BookmarksLikesRatings\Utility\LocalizationUtility::getLangArray('ThRating')); + } + + /** + * Override getErrorFlashMessage to present + * nice flash error messages. + * + * @return string + */ + protected function getErrorFlashMessage() + { + switch ($this->actionMethodName) { + case 'createAction': + return 'Could not create the new vote:'; + case 'showAction': + return 'Could not show vote!'; + default: + return parent::getErrorFlashMessage(); + } + } + + /** + * Generates a random number + * used as the unique iddentifier for AJAX objects + * + * @return int + * @throws \Exception + */ + protected function getRandomId() + { + mt_srand((int)microtime() * 1000000); + return random_int(1000000, 9999999); + } + + protected function setCookieProtection(): void + { + $this->cookieLifetime = abs((int)$this->settings['cookieLifetime']); + $this->logger->log( + LogLevel::DEBUG, + 'Cookielifetime set to ' . $this->cookieLifetime . ' days', + ['errorCode' => 1465728751] + ); + if (empty($this->cookieLifetime)) { + $this->cookieProtection = false; + } else { + $this->cookieProtection = true; + } + } + + /** + * Sends log information to flashMessage and logging framework + * + * @param string $messageText + * @param string $messageTitle + * @param string $severity + * @param array $additionalInfo + */ + private function logFlashMessage( + string $messageText, + string $messageTitle, + string $severity, + array $additionalInfo + ) + { + $additionalInfo = ['messageTitle' => $messageTitle] + $additionalInfo; + $severity = strtoupper($severity); + switch ($severity) { + case 'DEBUG': + $flashSeverity = 'OK'; + break; + case 'INFO': + $flashSeverity = 'INFO'; + break; + case 'NOTICE': + $flashSeverity = 'NOTICE'; + break; + case 'WARNING': + $flashSeverity = 'WARNING'; + break; + default: + $flashSeverity = 'ERROR'; + } + if ((int)$additionalInfo['errorCode']) { + $messageText .= ' (' . $additionalInfo['errorCode'] . ')'; + } + + //TODO: locally enqueue flashmessages of setStoragePids when controllerContext has not been set yet + if (is_object($this->controllerContext)) { + $this->addFlashMessage( + $messageText, + $messageTitle, + constant('\TYPO3\CMS\Core\Messaging\AbstractMessage::' . $flashSeverity) + ); + } + $this->logger->log(constant('\TYPO3\CMS\Core\Log\LogLevel::' . $severity), $messageText, $additionalInfo); + } + + /** + * Sets the rating values in the foreign table + * Recommended field type is VARCHAR(255) + * + * @param Rating $rating The rating + * @return bool + */ + protected function setForeignRatingValues(Rating $rating) + { + $table = $rating->getRatingobject()->getRatetable(); + $lockedFieldnames = $this->getLockedfieldnames($table); + $rateField = $rating->getRatingobject()->getRatefield(); + if (!empty($GLOBALS['TCA'][$table]['columns'][$rateField]) && !in_array($rateField, $lockedFieldnames, false)) { + $rateUid = $rating->getRatedobjectuid(); + $currentRatesArray = $rating->getCurrentrates(); + if (empty($this->settings['foreignFieldArrayUpdate'])) { + //do update using DOUBLE value + $currentRates = round($currentRatesArray['currentrate'], 2); + } else { + //do update using whole currentrates JSON array + $currentRates = $this->jsonService->encodeToJson($currentRatesArray); + } + + /** @var \TYPO3\CMS\Core\Database\Query\QueryBuilder $queryBuilder */ + $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class) + ->getQueryBuilderForTable($table); + + //do update foreign table + $queryResult = $queryBuilder + ->update($table) + ->where($queryBuilder->expr()->eq('uid', $queryBuilder->createNamedParameter($rateUid))) + ->set($rateField, $currentRates) + ->execute(); + + return !empty($queryResult); + } + + $this->logger->log( + LogLevel::NOTICE, + 'Foreign ratefield does not exist in ratetable or is locked for rating updates', + [ + 'ratingobject UID' => $rating->getRatingobject()->getUid(), + 'ratetable' => $rating->getRatingobject()->getRatetable(), + 'ratefield' => $rating->getRatingobject()->getRatefield() + ] + ); + + return true; + } + + /** + * Create a list of fieldnamed that must not be updated with ratingvalues + * + * @param string $table tablename looking for system fields + * @return array + */ + protected function getLockedfieldnames($table) + { + $TCA = &$GLOBALS['TCA'][$table]['ctrl']; // Set private TCA var + + /** @var array $lockedFields */ + $lockedFields = GeneralUtility::intExplode(',', $TCA['label_alt'], true); + array_push( + $lockedFields, + 'pid', + 'uid', + 'pages', + 'pages_language_overlay', + $TCA['label'], + $TCA['tstamp'], + $TCA['crdate'], + $TCA['cruser_id'], + $TCA['delete'], + $TCA['enablecolumns']['disabled'], + $TCA['enablecolumns']['starttime'], + $TCA['enablecolumns']['endtime'], + $TCA['enablecolumns']['fe_group'], + $TCA['selicon_field'], + $TCA['sortby'], + $TCA['editlock'], + $TCA['origUid'], + $TCA['fe_cruser_id'], + $TCA['fe_crgroup_id'], + $TCA['fe_admin_lock'], + $TCA['languageField'], + $TCA['transOrigPointerField'], + $TCA['transOrigDiffSourceField'] + ); + + return $lockedFields; + } + + /** + * @return \TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController + */ + protected function getTypoScriptFrontendController() + { + /** @var \TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController $TSFE */ + global $TSFE; + + return $TSFE; + } + + /** + * Demo slotHandler for slot 'afterRatinglinkAction' + * + * @param array $signalSlotMessage array containing signal information + * @param array $customContent array by reference to return pre and post content + */ + public function afterRatinglinkActionHandler( + /** @noinspection PhpUnusedParameterInspection */ + $signalSlotMessage, + &$customContent + ) + { + //\TYPO3\CMS\Extbase\Utility\DebuggerUtility::var_dump($signalSlotMessage,'signalSlotMessage'); + $customContent['preContent'] = 'This ist my preContent'; + $customContent['staticPreContent'] = 'This ist my staticPreContent'; + $customContent['postContent'] = 'This ist my postContent'; + $customContent['staticPostContent'] = 'This ist my stticPostContent'; + } + + /** + * Demo slotHandler for slot 'afterCreateAction' + * + * @param array $signalSlotMessage array containing signal information + * @param array $customContent array by reference to return pre and post content + */ + /** @noinspection PhpUnusedParameterInspection */ + public function afterCreateActionHandler( + /** @noinspection PhpUnusedParameterInspection */ + $signalSlotMessage, + &$customContent + ) + { + //\TYPO3\CMS\Extbase\Utility\DebuggerUtility::var_dump($signalSlotMessage,'signalSlotMessage'); + $customContent['preContent'] = 'This ist my preContent after afterCreateActionHandler'; + $customContent['staticPreContent'] = 'This ist my staticPreContent after afterCreateActionHandler'; + $customContent['postContent'] = 'This ist my postContent after afterCreateActionHandler'; + } +} diff --git a/Classes/Domain/Model/Bookmark.php b/Classes/Domain/Model/Bookmark.php index 55a670b..2e13e8b 100644 --- a/Classes/Domain/Model/Bookmark.php +++ b/Classes/Domain/Model/Bookmark.php @@ -10,13 +10,26 @@ namespace WapplerSystems\BookmarksLikesRatings\Domain\Model; use TYPO3\CMS\Core\Utility\GeneralUtility; +use TYPO3\CMS\Extbase\DomainObject\AbstractEntity; /** * */ -class Bookmark +class Bookmark extends AbstractEntity { + + /** @var int */ + protected $user; + + /** @var string */ + protected $tablename; + + /** @var int */ + protected $objectUid; + + + /** * @var string */ @@ -29,15 +42,64 @@ class Bookmark * @var string */ protected $url; - /** - * @var int - */ - protected $pid; + /** * @var string */ protected $parameter; + + + /** + * @return int + */ + public function getUser(): int + { + return $this->user; + } + + /** + * @param int $user + */ + public function setUser(int $user): void + { + $this->user = $user; + } + + /** + * @return string + */ + public function getTablename(): string + { + return $this->tablename; + } + + /** + * @param string $tablename + */ + public function setTablename(string $tablename): void + { + $this->tablename = $tablename; + } + + /** + * @return int + */ + public function getObjectUid(): int + { + return $this->objectUid; + } + + /** + * @param int $objectUid + */ + public function setObjectUid(int $objectUid): void + { + $this->objectUid = $objectUid; + } + + + /** * Bookmark constructor. * Initialize the bookmark with data @@ -47,7 +109,7 @@ class Bookmark * @param null $pid page id * @param null $parameter */ - public function __construct($url, $title = null, $pid = null, $parameter = null) + public function construct2($url, $title = null, $pid = null, $parameter = null) { if (is_array($url)) { $this->id = $url['id']; @@ -169,22 +231,6 @@ class Bookmark $this->url = $url; } - /** - * @return int - */ - public function getPid() - { - return $this->pid; - } - - /** - * @param int $pid - */ - public function setPid($pid) - { - $this->pid = $pid; - } - /** * @return string */ diff --git a/Classes/Domain/Model/Like.php b/Classes/Domain/Model/Like.php new file mode 100644 index 0000000..da1fbda --- /dev/null +++ b/Classes/Domain/Model/Like.php @@ -0,0 +1,73 @@ +user; + } + + /** + * @param int $user + */ + public function setUser(int $user): void + { + $this->user = $user; + } + + /** + * @return string + */ + public function getTablename(): string + { + return $this->tablename; + } + + /** + * @param string $tablename + */ + public function setTablename(string $tablename): void + { + $this->tablename = $tablename; + } + + /** + * @return int + */ + public function getObjectUid(): int + { + return $this->objectUid; + } + + /** + * @param int $objectUid + */ + public function setObjectUid(int $objectUid): void + { + $this->objectUid = $objectUid; + } + + +} diff --git a/Classes/Domain/Repository/BookmarkRepository.php b/Classes/Domain/Repository/BookmarkRepository.php new file mode 100644 index 0000000..a3da679 --- /dev/null +++ b/Classes/Domain/Repository/BookmarkRepository.php @@ -0,0 +1,130 @@ +createQuery(); + + return $query->matching( + $query->logicalAnd( + [ + $query->equals('user', $userUid), + $query->equals('tablename', $tablename), + $query->equals('objectUid', $objectUid) + ] + ) + )->execute()->count(); + } + + + public function removeByUserTablenameObjectUid($userUid, $tablename, $objectUid) + { + $query = $this->createQuery(); + + $objs = $query->matching( + $query->logicalAnd( + [ + $query->equals('user', $userUid), + $query->equals('tablename', $tablename), + $query->equals('objectUid', $objectUid) + ] + ) + )->execute()->toArray(); + + foreach ($objs as $obj) { + $this->remove($obj); + } + + } + + + /** + * Initialize this repository + */ + 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 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; + } +} diff --git a/Classes/Domain/Repository/LikeRepository.php b/Classes/Domain/Repository/LikeRepository.php new file mode 100644 index 0000000..d1e7c5b --- /dev/null +++ b/Classes/Domain/Repository/LikeRepository.php @@ -0,0 +1,75 @@ +createQuery(); + + return $query->matching( + $query->logicalAnd( + [ + $query->equals('user', $userUid), + $query->equals('tablename', $tablename), + $query->equals('objectUid', $objectUid) + ] + ) + )->execute()->count(); + } + + public function removeByUserTablenameObjectUid($userUid, $tablename, $objectUid) + { + $query = $this->createQuery(); + + $objs = $query->matching( + $query->logicalAnd( + [ + $query->equals('user', $userUid), + $query->equals('tablename', $tablename), + $query->equals('objectUid', $objectUid) + ] + ) + )->execute()->toArray(); + + foreach ($objs as $obj) { + $this->remove($obj); + } + + } + + + public function getTop($limit) + { + + /** @var QueryBuilder $queryBuilder */ + $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tx_bookmarkslikesratings_domain_model_like'); + + return $queryBuilder + ->select('tablename') + ->addSelect('object_uid') + ->addSelectLiteral('count(*) as number') + ->from('tx_bookmarkslikesratings_domain_model_like') + ->groupBy('tablename') + ->addGroupBy('object_uid') + ->orderBy('number', 'DESC') + ->setMaxResults($limit) + ->execute()->fetchAll(); + } + + +} diff --git a/Classes/ViewHelpers/Bookmark2ViewHelper.php b/Classes/ViewHelpers/Bookmark2ViewHelper.php new file mode 100644 index 0000000..0489c00 --- /dev/null +++ b/Classes/ViewHelpers/Bookmark2ViewHelper.php @@ -0,0 +1,245 @@ +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; + } +} diff --git a/Classes/ViewHelpers/BookmarkViewHelper.php b/Classes/ViewHelpers/BookmarkViewHelper.php index e1e927b..1f5ea09 100644 --- a/Classes/ViewHelpers/BookmarkViewHelper.php +++ b/Classes/ViewHelpers/BookmarkViewHelper.php @@ -12,11 +12,13 @@ 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\Mvc\Web\Routing\UriBuilder; 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\TagBuilder; use TYPO3Fluid\Fluid\Core\ViewHelper\Traits\CompileWithRenderStatic; /** @@ -25,47 +27,21 @@ 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'); + $this->registerArgument('table', 'string', 'The rating tablename'); + $this->registerArgument('uid', 'integer', 'The uid of the object', true); + $this->registerArgument('class', 'string', 'The class', true); + $this->registerArgument('id', 'string', 'The id'); + } /** @@ -83,163 +59,29 @@ class BookmarkViewHelper extends AbstractViewHelper \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(); + $tagBuilder = new TagBuilder('button'); + if ($arguments['id']) { + $tagBuilder->addAttribute('id',$arguments['id']); } - $contentObjectRenderer->start([]); + $tagBuilder->addAttribute('class',$arguments['class']); + $tagBuilder->addAttribute('data-table',$arguments['table']); + $tagBuilder->addAttribute('data-uid',$arguments['uid']); + $tagBuilder->addAttribute('data-blr-type','bookmark'); - $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, ] - ); + /** @var UriBuilder $uriBuilder */ + $uriBuilder = $renderingContext->getControllerContext()->getUriBuilder(); + $uriBuilder->reset(); + $uriBuilder->setTargetPageType(874655); + $tagBuilder->addAttribute('data-status-url',$uriBuilder->buildFrontendUri()); - throw new \TYPO3Fluid\Fluid\Core\ViewHelper\Exception( - 'TypoScript object path "' . $typoscriptObjectPath . '" does not exist', - 1549388144 - ); - } - $setup = $setup[$segment . '.']; - } + $uriBuilder->reset(); + $uriBuilder->setTargetPageType(874654); + $tagBuilder->addAttribute('data-toggle-url',$uriBuilder->buildFrontendUri()); - if (!isset($setup[$lastSegment])) { - throw new \TYPO3Fluid\Fluid\Core\ViewHelper\Exception( - 'No Content Object definition found at TypoScript object path "' . $typoscriptObjectPath . '"', - 1549388123 - ); - } + $tagBuilder->setContent((string)$renderChildrenClosure()); - 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 $tagBuilder->render(); } - /** - * @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; - } } diff --git a/Classes/ViewHelpers/LikeViewHelper.php b/Classes/ViewHelpers/LikeViewHelper.php index b9ca4c1..02c4733 100644 --- a/Classes/ViewHelpers/LikeViewHelper.php +++ b/Classes/ViewHelpers/LikeViewHelper.php @@ -12,11 +12,13 @@ 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\Mvc\Web\Routing\UriBuilder; 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\TagBuilder; use TYPO3Fluid\Fluid\Core\ViewHelper\Traits\CompileWithRenderStatic; /** @@ -25,47 +27,21 @@ 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'); + $this->registerArgument('table', 'string', 'The rating tablename'); + $this->registerArgument('uid', 'integer', 'The uid of the object', true); + $this->registerArgument('class', 'string', 'The class', true); + $this->registerArgument('id', 'string', 'The id'); + } /** @@ -83,163 +59,31 @@ class LikeViewHelper extends AbstractViewHelper \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(); + $tagBuilder = new TagBuilder('button'); + if ($arguments['id']) { + $tagBuilder->addAttribute('id',$arguments['id']); } - $contentObjectRenderer->start([]); + $tagBuilder->addAttribute('class',$arguments['class']); + $tagBuilder->addAttribute('data-table',$arguments['table']); + $tagBuilder->addAttribute('data-uid',$arguments['uid']); + $tagBuilder->addAttribute('data-blr-type','like'); - $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, ] - ); + /** @var UriBuilder $uriBuilder */ + $uriBuilder = $renderingContext->getControllerContext()->getUriBuilder(); + $uriBuilder->reset(); + $uriBuilder->setTargetPageType(874645); + $tagBuilder->addAttribute('data-status-url',$uriBuilder->buildFrontendUri()); - throw new \TYPO3Fluid\Fluid\Core\ViewHelper\Exception( - 'TypoScript object path "' . $typoscriptObjectPath . '" does not exist', - 1549388144 - ); - } - $setup = $setup[$segment . '.']; - } + $uriBuilder->reset(); + $uriBuilder->setTargetPageType(874644); + $tagBuilder->addAttribute('data-toggle-url',$uriBuilder->buildFrontendUri()); - if (!isset($setup[$lastSegment])) { - throw new \TYPO3Fluid\Fluid\Core\ViewHelper\Exception( - 'No Content Object definition found at TypoScript object path "' . $typoscriptObjectPath . '"', - 1549388123 - ); - } + $tagBuilder->setContent((string)$renderChildrenClosure()); - 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 $tagBuilder->render(); } - /** - * @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; - } } diff --git a/Classes/Widgets/Provider/TopLikesDataProvider.php b/Classes/Widgets/Provider/TopLikesDataProvider.php index 8885d65..a1ac643 100644 --- a/Classes/Widgets/Provider/TopLikesDataProvider.php +++ b/Classes/Widgets/Provider/TopLikesDataProvider.php @@ -5,34 +5,52 @@ 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; +use TYPO3\CMS\Backend\Utility\BackendUtility; +use TYPO3\CMS\Core\Utility\DebugUtility; +use WapplerSystems\BookmarksLikesRatings\Domain\Repository\LikeRepository; -class TopLikesDataProvider implements ListDataProviderInterface +class TopLikesDataProvider { + /** @var LikeRepository */ + protected $likeRepository; + + /** + * @param \WapplerSystems\BookmarksLikesRatings\Domain\Repository\LikeRepository $bookmarkRepository + */ + public function injectLikeRepository(LikeRepository $likeRepository) { + $this->likeRepository = $likeRepository; + } + public function __construct() { } - public function getItems(): array + public function getItems() { - /** @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(); + + + $objs = $this->likeRepository->getTop(10); + + $items = []; + + foreach ($objs as $obj) { + $title = ''; + if ($obj['tablename'] === 'pages') { + + $page = BackendUtility::getRecord('pages',$obj['object_uid'],'title'); + if ($page) { + $title = $page['title']; + } + } + $items[] = [ + 'title' => $title, + 'number' => $obj['number'] + ]; + } + + return $items; } } diff --git a/Classes/Widgets/TopLikesWidget.php b/Classes/Widgets/TopLikesWidget.php index 8b7bcb7..e75fe71 100644 --- a/Classes/Widgets/TopLikesWidget.php +++ b/Classes/Widgets/TopLikesWidget.php @@ -4,7 +4,6 @@ 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; @@ -53,9 +52,9 @@ class TopLikesWidget implements WidgetInterface public function renderWidgetContent(): string { - $this->view->setTemplate('Widget/ListWidget'); + $this->view->setTemplate('TopLikesWidget'); $this->view->assignMultiple([ - 'items' => $this->getItems(), + 'items' => $this->dataProvider->getItems(), 'options' => $this->options, 'button' => $this->buttonProvider, 'configuration' => $this->configuration, @@ -63,8 +62,4 @@ class TopLikesWidget implements WidgetInterface return $this->view->render(); } - protected function getItems(): array - { - return $this->dataProvider->getTopLikes(); - } } diff --git a/Configuration/Backend/DashboardWidgets.yaml b/Configuration/Backend/DashboardWidgets.yaml index ce13bdc..c56f2db 100644 --- a/Configuration/Backend/DashboardWidgets.yaml +++ b/Configuration/Backend/DashboardWidgets.yaml @@ -11,6 +11,6 @@ services: groupNames: 'ratings' title: 'LLL:EXT:bookmarks_likes_ratings/Resources/Private/Language/locallang.xlf:widgets.bookmarks_likes_ratings.topLikes.title' description: 'LLL:EXT:bookmarks_likes_ratings/Resources/Private/Language/locallang.xlf:widgets.bookmarks_likes_ratings.topLikes.description' - iconIdentifier: 'content-widget-ratings' + iconIdentifier: 'content-widget-text' height: 'large' width: 'medium' diff --git a/Configuration/TCA/Overrides/fe_users.php b/Configuration/TCA/Overrides/fe_users.php new file mode 100644 index 0000000..e69de29 diff --git a/Configuration/TCA/Overrides/sys_template.php b/Configuration/TCA/Overrides/sys_template.php index ca4b678..2e602da 100644 --- a/Configuration/TCA/Overrides/sys_template.php +++ b/Configuration/TCA/Overrides/sys_template.php @@ -12,4 +12,4 @@ defined('TYPO3') || die('Access denied.'); /** * add TypoScript to template record */ -\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addStaticFile('bookmarks_likes_ratings', 'Configuration/TypoScript/', 'Bookmark Pages'); +\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addStaticFile('bookmarks_likes_ratings', 'Configuration/TypoScript/', 'Bookmarks/Likes/Pages'); diff --git a/Configuration/TCA/Overrides/tt_content.php b/Configuration/TCA/Overrides/tt_content.php index 829c028..9be06ab 100644 --- a/Configuration/TCA/Overrides/tt_content.php +++ b/Configuration/TCA/Overrides/tt_content.php @@ -1,12 +1,4 @@ [ + 'title' => 'LLL:EXT:bookmarks_likes_ratings/Resources/Private/Language/locallang.xlf:tca.model.bookmark.title', + 'label' => 'uid', + 'label_alt' => 'rating,fe_user,vote', + 'label_userFunc' => 'WapplerSystems\\BookmarksLikesRatings\\Userfuncs\\Tca->getVoteRecordTitle', + 'tstamp' => 'tstamp', + 'crdate' => 'crdate', + 'cruser_id' => 'cruser_id', + 'adminOnly' => true, + 'hideTable' => true, + 'editlock' => 'rating', + 'enablecolumns' => [ + 'disabled' => 'hidden', + ], + 'iconfile' => 'EXT:bookmarks_likes_ratings/Resources/Public/Icons/tx_bookmarkslikesratings_domain_model_vote.gif', + ], + 'interface' => [ + 'showRecordFieldList' => 'hidden, rating, user, vote', + ], + 'columns' => [ + 'pid' => [ + 'exclude' => 1, + 'config' => [ + 'type' => 'none', + ], + ], + 'hidden' => [ + 'exclude' => 1, + 'label' => 'LLL:EXT:lang/Resources/Private/Language/locallang_general.xlf:LGL.hidden', + 'config' => [ + 'type' => 'check', + ], + ], + 'tablename' => [ + 'exclude' => 1, + 'label' => 'LLL:EXT:bookmarks_likes_ratings/Resources/Private/Language/locallang.xlf:tca.model.vote.tablename', + 'config' => [ + 'type' => 'input', + ], + ], + 'object_uid' => [ + 'exclude' => 1, + 'label' => 'LLL:EXT:bookmarks_likes_ratings/Resources/Private/Language/locallang.xlf:tca.model.vote.object_uid', + 'config' => [ + 'type' => 'input', + ], + ], + 'user' => [ + 'exclude' => 1, + 'label' => 'LLL:EXT:bookmarks_likes_ratings/Resources/Private/Language/locallang.xlf:tca.model.vote.user', + 'config' => [ + 'type' => 'select', + 'renderType' => 'selectSingle', + 'foreign_table' => 'fe_users', + 'foreign_table_where' => 'ORDER BY fe_users.username', + 'items' => [ + [ + '--div--', 0 + ], + ], + 'fieldControl' => [ + 'editPopup' => [ + 'disabled' => false, + ], + 'addRecord' => [ + 'disabled' => false, + 'options' => [ + 'setValue' => 'prepend', + ], + 'listModule' => [ + 'disabled' => false, + ], + ], + ], + ], + ], + 'uid' => [ + 'label' => 'LLL:EXT:bookmarks_likes_ratings/Resources/Private/Language/locallang.xlf:tca.model.vote.uid', + 'config' => [ + 'type' => 'none' + ], + ], + ], + 'types' => [ + '1' => [ + 'showitem' => 'hidden, rating, user, vote' + ], + ], + 'palettes' => [ + '1' => [ + 'showitem' => '' + ], + ], +]; diff --git a/Configuration/TCA/tx_bookmarkslikesratings_domain_model_like.php b/Configuration/TCA/tx_bookmarkslikesratings_domain_model_like.php new file mode 100644 index 0000000..e354aed --- /dev/null +++ b/Configuration/TCA/tx_bookmarkslikesratings_domain_model_like.php @@ -0,0 +1,97 @@ + [ + 'title' => 'LLL:EXT:bookmarks_likes_ratings/Resources/Private/Language/locallang.xlf:tca.model.like.title', + 'label' => 'uid', + 'label_alt' => 'rating,fe_user,vote', + 'label_userFunc' => 'WapplerSystems\\BookmarksLikesRatings\\Userfuncs\\Tca->getVoteRecordTitle', + 'tstamp' => 'tstamp', + 'crdate' => 'crdate', + 'cruser_id' => 'cruser_id', + 'adminOnly' => true, + 'hideTable' => true, + 'editlock' => 'rating', + 'enablecolumns' => [ + 'disabled' => 'hidden', + ], + 'iconfile' => 'EXT:bookmarks_likes_ratings/Resources/Public/Icons/tx_bookmarkslikesratings_domain_model_vote.gif', + ], + 'interface' => [ + 'showRecordFieldList' => 'hidden, rating, voter, vote', + ], + 'columns' => [ + 'pid' => [ + 'exclude' => 1, + 'config' => [ + 'type' => 'none', + ], + ], + 'hidden' => [ + 'exclude' => 1, + 'label' => 'LLL:EXT:lang/Resources/Private/Language/locallang_general.xlf:LGL.hidden', + 'config' => [ + 'type' => 'check', + ], + ], + 'tablename' => [ + 'exclude' => 1, + 'label' => 'LLL:EXT:bookmarks_likes_ratings/Resources/Private/Language/locallang.xlf:tca.model.vote.tablename', + 'config' => [ + 'type' => 'input', + ], + ], + 'object_uid' => [ + 'exclude' => 1, + 'label' => 'LLL:EXT:bookmarks_likes_ratings/Resources/Private/Language/locallang.xlf:tca.model.vote.object_uid', + 'config' => [ + 'type' => 'input', + ], + ], + 'user' => [ + 'exclude' => 1, + 'label' => 'LLL:EXT:bookmarks_likes_ratings/Resources/Private/Language/locallang.xlf:tca.model.vote.user', + 'config' => [ + 'type' => 'select', + 'renderType' => 'selectSingle', + 'foreign_table' => 'fe_users', + 'foreign_table_where' => 'ORDER BY fe_users.username', + 'items' => [ + [ + '--div--', 0 + ], + ], + 'fieldControl' => [ + 'editPopup' => [ + 'disabled' => false, + ], + 'addRecord' => [ + 'disabled' => false, + 'options' => [ + 'setValue' => 'prepend', + ], + 'listModule' => [ + 'disabled' => false, + ], + ], + ], + ], + ], + 'uid' => [ + 'label' => 'LLL:EXT:bookmarks_likes_ratings/Resources/Private/Language/locallang.xlf:tca.model.vote.uid', + 'config' => [ + 'type' => 'none' + ], + ], + ], + 'types' => [ + '1' => [ + 'showitem' => 'hidden, rating, voter, vote' + ], + ], + 'palettes' => [ + '1' => [ + 'showitem' => '' + ], + ], +]; diff --git a/Configuration/TCA/tx_bookmarkslikesratings_domain_model_vote.php b/Configuration/TCA/tx_bookmarkslikesratings_domain_model_vote.php index 325db62..5e39113 100644 --- a/Configuration/TCA/tx_bookmarkslikesratings_domain_model_vote.php +++ b/Configuration/TCA/tx_bookmarkslikesratings_domain_model_vote.php @@ -47,9 +47,9 @@ return [ 'disableNoMatchingValueElement' => 1, ], ], - 'voter' => [ + 'user' => [ 'exclude' => 1, - 'label' => 'LLL:EXT:bookmarks_likes_ratings/Resources/Private/Language/locallang.xlf:tca.model.vote.voter', + 'label' => 'LLL:EXT:bookmarks_likes_ratings/Resources/Private/Language/locallang.xlf:tca.model.vote.user', 'config' => [ 'type' => 'select', 'renderType' => 'selectSingle', diff --git a/Configuration/TypoScript/Ajax/ajax.typoscript b/Configuration/TypoScript/Ajax/ajax.typoscript new file mode 100644 index 0000000..a5144f5 --- /dev/null +++ b/Configuration/TypoScript/Ajax/ajax.typoscript @@ -0,0 +1,104 @@ + + +blrToggleLike = PAGE +blrToggleLike { + typeNum = 874644 + + config { + disableAllHeaderCode = 1 + additionalHeaders = Content-type:application/json + xhtml_cleaning = 0 + admPanel = 0 + debug = 0 + no_cache = 1 + } + + 10 = USER + 10 { + userFunc = TYPO3\CMS\Extbase\Core\Bootstrap->run + extensionName = BookmarksLikesRatings + pluginName = ToggleLike + vendorName = WapplerSystems + controller = Like + action = toggle + } + +} + +blrStatusLike = PAGE +blrStatusLike { + typeNum = 874645 + + config { + disableAllHeaderCode = 1 + additionalHeaders = Content-type:application/json + xhtml_cleaning = 0 + admPanel = 0 + debug = 0 + no_cache = 1 + } + + 10 = USER + 10 { + userFunc = TYPO3\CMS\Extbase\Core\Bootstrap->run + extensionName = BookmarksLikesRatings + pluginName = StatusLike + vendorName = WapplerSystems + controller = Like + action = status + } + +} + + + +blrToggleBookmark = PAGE +blrToggleBookmark { + typeNum = 874654 + + config { + disableAllHeaderCode = 1 + additionalHeaders = Content-type:application/json + xhtml_cleaning = 0 + admPanel = 0 + debug = 0 + no_cache = 1 + } + + 10 = USER + 10 { + userFunc = TYPO3\CMS\Extbase\Core\Bootstrap->run + extensionName = BookmarksLikesRatings + pluginName = ToggleBookmark + vendorName = WapplerSystems + controller = Bookmark + action = toggle + } + +} + +blrStatusBookmark = PAGE +blrStatusBookmark { + typeNum = 874655 + + config { + disableAllHeaderCode = 1 + additionalHeaders = Content-type:application/json + xhtml_cleaning = 0 + admPanel = 0 + debug = 0 + no_cache = 1 + } + + 10 = USER + 10 { + userFunc = TYPO3\CMS\Extbase\Core\Bootstrap->run + extensionName = BookmarksLikesRatings + pluginName = StatusBookmark + vendorName = WapplerSystems + controller = Bookmark + action = status + } + +} + diff --git a/Configuration/TypoScript/setup.typoscript b/Configuration/TypoScript/setup.typoscript index 236045e..dbd1fcd 100644 --- a/Configuration/TypoScript/setup.typoscript +++ b/Configuration/TypoScript/setup.typoscript @@ -1,34 +1,23 @@ plugin.tx_wsbookmarkpages { - view { - templateRootPaths.10 = {$plugin.tx_wsbookmarkpages.view.templateRootPath} - partialRootPaths.10 = {$plugin.tx_wsbookmarkpages.view.partialRootPath} - layoutRootPaths.10 = {$plugin.tx_wsbookmarkpages.view.layoutRootPath} - } - settings { - storeLocal = {$plugin.tx_wsbookmarkpages.settings.storeLocal} - localStorageTTL = {$plugin.tx_wsbookmarkpages.settings.localStorageTTL} - } + view { + templateRootPaths.0 = EXT:bookmarks_likes_ratings/Resources/Private/Templates/ + templateRootPaths.10 = {$plugin.tx_wsbookmarkpages.view.templateRootPath} + partialRootPaths.0 = EXT:bookmarks_likes_ratings/Resources/Private/Partials/ + partialRootPaths.10 = {$plugin.tx_wsbookmarkpages.view.partialRootPath} + layoutRootPaths.0 = EXT:bookmarks_likes_ratings/Resources/Private/Layouts/ + layoutRootPaths.10 = {$plugin.tx_wsbookmarkpages.view.layoutRootPath} + } + + settings { + storeLocal = {$plugin.tx_wsbookmarkpages.settings.storeLocal} + localStorageTTL = {$plugin.tx_wsbookmarkpages.settings.localStorageTTL} + } } page.includeJSFooterlibs { - bookmark_pages_jquery = https://code.jquery.com/jquery-2.2.4.min.js - bookmark_pages_jquery { - excludeFromConcatenation = 1 - disableCompression = 1 - external = 1 - } + + blr = EXT:bookmarks_likes_ratings/Resources/Public/JavaScript/scripts.js + } -tt_content.login.stdWrap.postCObject = TEXT -tt_content.login.stdWrap.postCObject.value ( - -) + diff --git a/Resources/Private/Layouts/Default.html b/Resources/Private/Layouts/Default.html index 6871db9..45baa99 100644 --- a/Resources/Private/Layouts/Default.html +++ b/Resources/Private/Layouts/Default.html @@ -1,23 +1,4 @@ - - - - - - - - - - - - - - - - + + + diff --git a/Resources/Private/Templates/Bookmarks/Index.html b/Resources/Private/Templates/Bookmark/Index.html similarity index 100% rename from Resources/Private/Templates/Bookmarks/Index.html rename to Resources/Private/Templates/Bookmark/Index.html diff --git a/Resources/Private/Templates/Bookmark/PersonalList.html b/Resources/Private/Templates/Bookmark/PersonalList.html new file mode 100644 index 0000000..97526f7 --- /dev/null +++ b/Resources/Private/Templates/Bookmark/PersonalList.html @@ -0,0 +1,21 @@ + + + + + + + + + + + [Löschen] + {bookmark.title} + + + + + + + + diff --git a/Resources/Private/Templates/Dashboard/Widgets/TopLikesWidget.html b/Resources/Private/Templates/Dashboard/Widgets/TopLikesWidget.html new file mode 100644 index 0000000..fd66a8d --- /dev/null +++ b/Resources/Private/Templates/Dashboard/Widgets/TopLikesWidget.html @@ -0,0 +1,24 @@ + + + + + + + + + + {item.title -> f:format.crop(maxCharacters: 180)} + + + {item.number} + + + + + + + + + + + diff --git a/Resources/Public/Icons/Extension.svg b/Resources/Public/Icons/Extension.svg new file mode 100644 index 0000000..8dae94f --- /dev/null +++ b/Resources/Public/Icons/Extension.svg @@ -0,0 +1 @@ + diff --git a/Resources/Public/JavaScript/scripts.js b/Resources/Public/JavaScript/scripts.js new file mode 100644 index 0000000..359e895 --- /dev/null +++ b/Resources/Public/JavaScript/scripts.js @@ -0,0 +1,99 @@ + +let BookmarkLikeRating = function () { + function initButtons() { + $('button[data-blr-type=bookmark]').each(function (n) { + let btn = $(this); + $.ajax({ + cache: false, + method: 'POST', + url: btn.attr('data-status-url'), + success: function (data) { + if (data.status === 'true') { + btn.addClass('active'); + $('*',btn).addClass('active'); + } else { + btn.removeClass('active'); + $('*',btn).removeClass('active'); + } + }, + data: 'tx_bookmarkslikesratings_statusbookmark[objectUid]='+btn.attr('data-uid')+'&tx_bookmarkslikesratings_statusbookmark[tablename]='+btn.attr('data-table') + }); + + $(this).on('click',function() { + let btn = $(this); + $.ajax({ + cache: false, + method: 'POST', + url: btn.attr('data-toggle-url'), + success: function (data) { + if (data.status === 'true') { + btn.addClass('active'); + $('*',btn).addClass('active'); + } else { + btn.removeClass('active'); + $('*',btn).removeClass('active'); + } + }, + data: 'tx_bookmarkslikesratings_togglebookmark[objectUid]='+btn.attr('data-uid')+'&tx_bookmarkslikesratings_togglebookmark[tablename]='+btn.attr('data-table') + }); + + }); + }); + + + $('button[data-blr-type=like]').each(function (n) { + let btn = $(this); + $.ajax({ + cache: false, + method: 'POST', + url: btn.attr('data-status-url'), + success: function (data) { + if (data.status === 'true') { + btn.addClass('active'); + $('*',btn).addClass('active'); + } else { + btn.removeClass('active'); + $('*',btn).removeClass('active'); + } + }, + data: 'tx_bookmarkslikesratings_statuslike[objectUid]='+btn.attr('data-uid')+'&tx_bookmarkslikesratings_statuslike[tablename]='+btn.attr('data-table') + }); + + $(this).on('click',function() { + let btn = $(this); + $.ajax({ + cache: false, + method: 'POST', + url: btn.attr('data-toggle-url'), + success: function (data) { + if (data.status === 'true') { + btn.addClass('active'); + $('*',btn).addClass('active'); + } else { + btn.removeClass('active'); + $('*',btn).removeClass('active'); + } + }, + data: 'tx_bookmarkslikesratings_togglelike[objectUid]='+btn.attr('data-uid')+'&tx_bookmarkslikesratings_togglelike[tablename]='+btn.attr('data-table') + }); + + }); + }); + + } + + function updateStatus() { + + } + + return { + init: function () { + initButtons(); + } + } +}(); + +jQuery(document).ready(function () { + + BookmarkLikeRating.init(); +}); diff --git a/ext_icon.png b/ext_icon.png deleted file mode 100644 index 08329f1..0000000 Binary files a/ext_icon.png and /dev/null differ diff --git a/ext_localconf.php b/ext_localconf.php index e4dc831..af1f90b 100644 --- a/ext_localconf.php +++ b/ext_localconf.php @@ -11,14 +11,72 @@ defined('TYPO3') or die('Access denied.'); (function () { + \TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin( - 'BookmarkPages', - 'Bookmarks', + 'BookmarksLikesRatings', + 'StatusBookmark', [ - \WapplerSystems\BookmarksLikesRatings\Controller\BookmarksController::class => 'index, bookmark, delete, listEntries' + \WapplerSystems\BookmarksLikesRatings\Controller\BookmarkController::class => 'status' ], [ - \WapplerSystems\BookmarksLikesRatings\Controller\BookmarksController::class => 'bookmark, delete, listEntries' + \WapplerSystems\BookmarksLikesRatings\Controller\BookmarkController::class => 'status' + ] + ); + + \TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin( + 'BookmarksLikesRatings', + 'ToggleBookmark', + [ + \WapplerSystems\BookmarksLikesRatings\Controller\BookmarkController::class => 'toggle' + ], + [ + \WapplerSystems\BookmarksLikesRatings\Controller\BookmarkController::class => 'toggle' + ] + ); + + + \TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin( + 'BookmarksLikesRatings', + 'StatusLike', + [ + \WapplerSystems\BookmarksLikesRatings\Controller\LikeController::class => 'status' + ], + [ + \WapplerSystems\BookmarksLikesRatings\Controller\LikeController::class => 'status' + ] + ); + + \TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin( + 'BookmarksLikesRatings', + 'ToggleLike', + [ + \WapplerSystems\BookmarksLikesRatings\Controller\LikeController::class => 'toggle' + ], + [ + \WapplerSystems\BookmarksLikesRatings\Controller\LikeController::class => 'toggle' + ] + ); + + + \TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin( + 'BookmarksLikesRatings', + 'Bookmarks', + [ + \WapplerSystems\BookmarksLikesRatings\Controller\BookmarkController::class => 'index, bookmark, delete, listEntries' + ], + [ + \WapplerSystems\BookmarksLikesRatings\Controller\BookmarkController::class => 'bookmark, delete, listEntries' + ] + ); + + \TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin( + 'BookmarksLikesRatings', + 'PersonalBookmarks', + [ + \WapplerSystems\BookmarksLikesRatings\Controller\BookmarkController::class => 'personalList, delete' + ], + [ + \WapplerSystems\BookmarksLikesRatings\Controller\BookmarkController::class => 'personalList, delete' ] ); diff --git a/ext_tables.sql b/ext_tables.sql index bcc9ddd..98d0e93 100644 --- a/ext_tables.sql +++ b/ext_tables.sql @@ -1,17 +1,3 @@ -# -# Add field to table 'fe_users' -# -CREATE TABLE fe_users -( - tx_bookmarks_pages blob -); - -CREATE TABLE tx_bookmarkslikesratings_model_bookmark -( - -); - - # # Table structure for table 'tx_bookmarkslikesratings_domain_model_ratingobject' # @@ -142,3 +128,46 @@ CREATE TABLE tx_bookmarkslikesratings_domain_model_vote KEY phpunit_dummy (is_dummy_record), INDEX tx_bookmarkslikesratings_domain_model_vote_i1 (rating, voter) ); + + +CREATE TABLE tx_bookmarkslikesratings_domain_model_bookmark +( + uid int(11) unsigned DEFAULT '0' NOT NULL auto_increment, + pid int(11) DEFAULT '0' NOT NULL, + + tablename varchar(250) NOT NULL, + object_uid int(11) NOT NULL, + user int(11) NOT NULL, + seen_on_page int(11) DEFAULT NULL, + + tstamp int(11) unsigned DEFAULT '0' NOT NULL, + crdate int(11) unsigned DEFAULT '0' NOT NULL, + cruser_id int(11) DEFAULT '0' NOT NULL, + deleted tinyint(4) unsigned DEFAULT '0' NOT NULL, + hidden tinyint(4) unsigned DEFAULT '0' NOT NULL, + + PRIMARY KEY (uid), + KEY parent (pid), + INDEX tx_bookmarkslikesratings_domain_model_bookmark_i1 (tablename, object_uid, user) +); + +CREATE TABLE tx_bookmarkslikesratings_domain_model_like +( + uid int(11) unsigned DEFAULT '0' NOT NULL auto_increment, + pid int(11) DEFAULT '0' NOT NULL, + + tablename varchar(250) NOT NULL, + object_uid int(11) NOT NULL, + user int(11) NOT NULL, + seen_on_page int(11) DEFAULT NULL, + + tstamp int(11) unsigned DEFAULT '0' NOT NULL, + crdate int(11) unsigned DEFAULT '0' NOT NULL, + cruser_id int(11) DEFAULT '0' NOT NULL, + deleted tinyint(4) unsigned DEFAULT '0' NOT NULL, + hidden tinyint(4) unsigned DEFAULT '0' NOT NULL, + + PRIMARY KEY (uid), + KEY parent (pid), + INDEX tx_bookmarkslikesratings_domain_model_like_i1 (tablename, object_uid, user) +); diff --git a/ext_typoscript_setup.txt b/ext_typoscript_setup.txt new file mode 100755 index 0000000..0b68276 --- /dev/null +++ b/ext_typoscript_setup.txt @@ -0,0 +1,7 @@ +module.tx_dashboard { + view { + templateRootPaths { + 123131 = EXT:bookmarks_likes_ratings/Resources/Private/Templates/Dashboard/Widgets/ + } + } +}
{item.title -> f:format.crop(maxCharacters: 180)}