Files
oai-symfony/typo3conf/ext/news/Classes/Service/AccessControlService.php
2026-07-03 17:53:31 +02:00

172 lines
6.6 KiB
PHP

<?php
namespace GeorgRinger\News\Service;
/**
* This file is part of the "news" Extension for TYPO3 CMS.
*
* For the full copyright and license information, please read the
* LICENSE.txt file that was distributed with this source code.
*/
use GeorgRinger\News\Domain\Model\Dto\EmConfiguration;
use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\Database\Query\Restriction\EndTimeRestriction;
use TYPO3\CMS\Core\Database\Query\Restriction\HiddenRestriction;
use TYPO3\CMS\Core\Database\Query\Restriction\StartTimeRestriction;
use TYPO3\CMS\Core\Utility\GeneralUtility;
/**
* Service for access control related stuff
*/
class AccessControlService
{
/**
* Check if a user has access to all categories of a news record
*
* @param array $newsRecord
* @return bool
*/
public static function userHasCategoryPermissionsForRecord(array $newsRecord): bool
{
$settings = GeneralUtility::makeInstance(EmConfiguration::class);
if (!$settings->getCategoryBeGroupTceFormsRestriction()) {
return true;
}
if (self::getBackendUser()->isAdmin()) {
// an admin may edit all news
return true;
}
// If there are any categories with denied access, the user has no permission
if (count(self::getAccessDeniedCategories($newsRecord))) {
return false;
}
return true;
}
/**
* Get an array with the uid and title of all categories the user doesn't have access to
*
* @param array $newsRecord
* @return array
*/
public static function getAccessDeniedCategories(array $newsRecord): array
{
if (self::getBackendUser()->isAdmin()) {
// an admin may edit all news so no categories without access
return [];
}
// no category mounts set means access to all
$backendUserCategories = self::getBackendUser()->getCategoryMountPoints();
if ($backendUserCategories === []) {
return [];
}
$catService = GeneralUtility::makeInstance(CategoryService::class);
$subCategories = $catService::getChildrenCategories(implode(',', $backendUserCategories));
if (!empty($subCategories)) {
$backendUserCategories = explode(',', $subCategories);
}
$newsRecordCategories = self::getCategoriesForNewsRecord($newsRecord);
// Remove categories the user has access to
foreach ($newsRecordCategories as $key => $newsRecordCategory) {
if (in_array($newsRecordCategory['uid'], $backendUserCategories)) {
unset($newsRecordCategories[$key]);
}
}
return $newsRecordCategories;
}
/**
* Get all categories for a news record respecting l10n_mode
*
* @param array $newsRecord
* @return array
*/
public static function getCategoriesForNewsRecord($newsRecord): array
{
// determine localization overlay mode to select categories either from parent or localized record
if ($newsRecord['sys_language_uid'] > 0 && $newsRecord['l10n_parent'] > 0) {
// localized version of a news record
$categoryL10nMode = $GLOBALS['TCA']['tx_news_domain_model_news']['columns']['categories']['l10n_mode'];
if ($categoryL10nMode === 'mergeIfNotBlank') {
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
->getQueryBuilderForTable('sys_category_record_mm');
$newsRecordCategoriesCount = $queryBuilder->count('*')
->from('sys_category_record_mm')
->where(
$queryBuilder->expr()->eq('uid_foreign', $queryBuilder->createNamedParameter($newsRecord['uid'], \PDO::PARAM_INT)),
$queryBuilder->expr()->eq('tablenames', $queryBuilder->createNamedParameter('tx_news_domain_model_news', \PDO::PARAM_STR)),
$queryBuilder->expr()->eq('fieldname', $queryBuilder->createNamedParameter('categories', \PDO::PARAM_STR))
)
->execute()
->fetchColumn(0);
if ($newsRecordCategoriesCount > 0) {
// take categories from localized version
$newsRecordUid = $newsRecord['uid'];
} else {
// inherit categories from parent
$newsRecordUid = $newsRecord['l10n_parent'];
}
} elseif ($categoryL10nMode === 'exclude') {
// exclude: The localized version inherits the categories of the parent
$newsRecordUid = $newsRecord['l10n_parent'];
} else {
// noCopy/prefixLangTitle: no inheritance
$newsRecordUid = $newsRecord['uid'];
}
} else {
$newsRecordUid = $newsRecord['uid'];
}
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
->getQueryBuilderForTable('sys_category');
$queryBuilder->getRestrictions()
->removeByType(StartTimeRestriction::class)
->removeByType(HiddenRestriction::class)
->removeByType(EndTimeRestriction::class);
$res = $queryBuilder
->select('sys_category_record_mm.uid_local', 'sys_category.title')
->from('sys_category')
->leftJoin(
'sys_category',
'sys_category_record_mm',
'sys_category_record_mm',
$queryBuilder->expr()->eq('sys_category_record_mm.uid_local', $queryBuilder->quoteIdentifier('sys_category.uid'))
)
->where(
$queryBuilder->expr()->eq('sys_category_record_mm.tablenames', $queryBuilder->createNamedParameter('tx_news_domain_model_news', \PDO::PARAM_STR)),
$queryBuilder->expr()->eq('sys_category_record_mm.fieldname', $queryBuilder->createNamedParameter('categories', \PDO::PARAM_STR)),
$queryBuilder->expr()->eq('sys_category_record_mm.uid_foreign', $queryBuilder->createNamedParameter($newsRecordUid, \PDO::PARAM_INT))
)
->execute();
$categories = [];
while ($row =$res->fetch()) {
$categories[] = [
'uid' => $row['uid_local'],
'title' => $row['title']
];
}
return $categories;
}
/**
* Returns the current BE user.
*
* @return \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
*/
protected static function getBackendUser(): \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
{
return $GLOBALS['BE_USER'];
}
}