...
 
......@@ -299,9 +299,8 @@ abstract class Element {
$availablesLanguages = $languageRep->getLanguages();
foreach ($availablesLanguages as $language) {
$row = $this->getOverLayRecordForCertainLanguage($language->getUid());
$flagRow = $visibilityFlagRepository->getVisibilityFlag($table, $row['uid'], $language->getUid());
$flagRow = $visibilityFlagRepository->getVisibilityFlag($table, $this->getUid(), $language->getUid());
if ($flagRow === FALSE || $flagRow === NULL) {
$flag = '-';
......
......@@ -37,7 +37,6 @@ use TYPO3\Languagevisibility\Repository\LanguageRepository;
use TYPO3\Languagevisibility\Repository\VisibilityFlagRepository;
use TYPO3\Languagevisibility\Service\BackendServices;
use TYPO3\Languagevisibility\Service\VisibilityService;
use TYPO3\CMS\Frontend\Page\PageRepository;
/**
* Class TceMainHook
......@@ -58,11 +57,8 @@ class TceMainHook {
public function processCmdmap_postProcess(
$command, $table, $identity, $value, $dataHandler, $pasteUpdate, $pasteDatamap
) {
if ($table !== 'pages') {
return;
}
if ($command === 'copy') {
if ($command === 'copy' && $table === 'pages') {
$originalPageId = (int) $identity;
if ($originalPageId <= 0) {
return;
......@@ -81,6 +77,71 @@ class TceMainHook {
} elseif ($command === 'move') {
$this->copyLanguageVisibilityFlagsFromParentPage($identity);
}
if ($command === 'copy' && $table !== 'pages' && in_array(
$table, VisibilityService::getSupportedTables(), TRUE
)) {
$oldId = $identity;
$newId = $dataHandler->copyMappingArray[$table][$identity];
$languageRep = GeneralUtility::makeInstance(LanguageRepository::class);
$visibilityFlagRepository = GeneralUtility::makeInstance(VisibilityFlagRepository::class);
$availableLanguages = $languageRep->getLanguages();
$visibilityFlags = [];
foreach ($availableLanguages as $language) {
$lid = $language->getUid();
$visibilityFlag = $visibilityFlagRepository->getVisibilityFlag($table, $oldId, $lid);
if ($visibilityFlag !== FALSE && $visibilityFlag !== NULL) {
$visibilityFlags[$lid] = $visibilityFlag['flag'];
}
}
foreach ($visibilityFlags as $lid => $flag) {
$visibilityFlagRepository->setVisibilityFlag($flag, $table, $newId, $lid);
}
}
}
/**
* Changes the pid of the visibility flags of a moved record
*
* @param $table
* @param $uid
* @param $destPid
* @param $propArr
* @param $moveRec
* @param $resolvedPid
* @param $recordWasMoved
* @param $dataHandler
*/
public function moveRecord($table, $uid, $destPid, $propArr, $moveRec, $resolvedPid, $recordWasMoved, $dataHandler
) {
if ($table !== 'pages' && in_array(
$table, VisibilityService::getSupportedTables(), TRUE
)) {
$languageRep = GeneralUtility::makeInstance(LanguageRepository::class);
$visibilityFlagRepository = GeneralUtility::makeInstance(VisibilityFlagRepository::class);
$availableLanguages = $languageRep->getLanguages();
foreach ($availableLanguages as $language) {
$lid = $language->getUid();
$visibilityFlag = $visibilityFlagRepository->getVisibilityFlag($table, $uid, $lid);
if ($visibilityFlag !== FALSE && $visibilityFlag !== NULL) {
$flagUid = $visibilityFlag['uid'];
$visibilityFlagRepository->moveVisibilityFlag($flagUid, $resolvedPid);
}
}
}
}
/**
......@@ -102,11 +163,10 @@ class TceMainHook {
return;
}
$parentUid = $parentPage['uid'];
$parentPageUid = $parentPage['uid'];
$languageRep = GeneralUtility::makeInstance(LanguageRepository::class);
$visibilityFlagRepository = GeneralUtility::makeInstance(VisibilityFlagRepository::class);
$pageRepository = GeneralUtility::makeInstance(PageRepository::class);
$availableLanguages = $languageRep->getLanguages();
// clear the existing/automatically copied flags on the copied/inserted/moved page
......@@ -119,17 +179,8 @@ class TceMainHook {
$lid = $language->getUid();
$flagRow = [];
if ($lid > 0) {
$parentOverlay = $pageRepository->getPageOverlay($parentUid, $lid);
$parentOverlayUid = $parentOverlay['_PAGES_OVERLAY_UID'];
if ($parentOverlayUid > 0) {
$flagRow = $visibilityFlagRepository->getVisibilityFlag('pages', $parentOverlayUid, $lid);
}
} else {
$flagRow = $visibilityFlagRepository->getVisibilityFlag('pages', $parentUid, $lid);
}
// get visibility from parent page
$flagRow = $visibilityFlagRepository->getVisibilityFlag('pages', $parentPageUid, $lid);
if ($flagRow !== NULL && isset($flagRow['flag'])) {
$flag = $flagRow['flag'];
......@@ -137,52 +188,26 @@ class TceMainHook {
$flag = '-';
}
$recordUid = 0;
if ($lid > 0) {
$pageOverlay = $pageRepository->getPageOverlay($pageId, $lid);
// if there is no overlay, no need to go further
if (empty($pageOverlay)) {
break;
}
$parentOverlayUid = $pageOverlay['_PAGES_OVERLAY_UID'];
if ($parentOverlayUid > 0) {
$recordUid = $parentOverlayUid;
}
$defaultLanguageRecordUid = $pageId;
} else {
$recordUid = $pageId;
$defaultLanguageRecordUid = 0;
}
if ($recordUid > 0) {
// since the data mapper automatically copies the flag records,
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable(
'tx_languagevisibility_visibility_flag'
);
$queryBuilder
->insert('tx_languagevisibility_visibility_flag')
->values(
[
'pid' => $pageId,
'flag' => $flag,
'record_uid' => 'pages_' . $recordUid,
'default_language_record_uid' => $defaultLanguageRecordUid,
'record_language_uid' => $lid,
'tstamp' => time(),
'crdate' => time(),
'cruser_id' => $GLOBALS['BE_USER']->user['uid'],
'record_table' => 'pages',
]
)
->execute();
// since the data mapper automatically copies the flag records,
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable(
'tx_languagevisibility_visibility_flag'
);
}
$queryBuilder
->insert('tx_languagevisibility_visibility_flag')
->values(
[
'pid' => $pageId,
'flag' => $flag,
'record_uid' => 'pages_' . $pageId,
'record_language_uid' => $lid,
'tstamp' => time(),
'crdate' => time(),
'cruser_id' => $GLOBALS['BE_USER']->user['uid'],
'record_table' => 'pages',
]
)
->execute();
}
}
}
......@@ -266,15 +291,9 @@ class TceMainHook {
$languageId = (int) $incomingFieldArray['record_language_uid'];
}
$recordUid = -1;
if (isset($incomingFieldArray['record_uid'])) {
if ($languageId === 0) {
$recordUid = (int) str_replace($recordTable . '_', '', $incomingFieldArray['record_uid']);
} else {
$recordUid = (int) str_replace(
$recordTable . '_', '', $incomingFieldArray['default_language_record_uid']
);
}
$pid = -1;
if (isset($incomingFieldArray['pid'])) {
$pid = (int) $incomingFieldArray['pid'];
}
$visibilityFlag = '';
......@@ -284,7 +303,7 @@ class TceMainHook {
if ($isPage && $applyRecursive) {
$this->applyVisibilityFlagRecursive(
$recordUid, $languageId, $visibilityFlag, $enableLogging, $dataHandler
$pid, $languageId, $visibilityFlag, $enableLogging, $dataHandler
);
}
......@@ -315,7 +334,7 @@ class TceMainHook {
*/
protected function applyVisibilityFlagRecursive(
int $pageId, int $languageId, string $visibilityFlag, bool $enableLogging, DataHandler $dataHandler
) {
): void {
if ($pageId <= 0 || $languageId < 0 || strlen($visibilityFlag) <= 0) {
return;
......@@ -333,7 +352,7 @@ class TceMainHook {
)
->andWhere(
$queryBuilder->expr()->eq(
'sys_language_uid', $queryBuilder->createNamedParameter($languageId, \PDO::PARAM_INT)
'sys_language_uid', $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT)
)
)
->execute()->fetchAll();
......@@ -345,82 +364,58 @@ class TceMainHook {
foreach ($childPages as $childPage) {
$childPageUid = (int) $childPage['uid'];
$childPageLanguageId = (int) $childPage['sys_language_uid'];
//make sure it's the correct language
if ($childPageLanguageId === $languageId) {
$existingVisibilityFlag = $visibilityFlagRepository->getVisibilityFlag(
'pages', $childPageUid, $childPageLanguageId
);
if (!is_null($existingVisibilityFlag) && $existingVisibilityFlag['uid'] > 0) {
$existingVisibilityFlag = $visibilityFlagRepository->getVisibilityFlag(
'pages', $childPageUid, $languageId
);
//flag already exists and only needs to changed
$flagUid = $existingVisibilityFlag['uid'];
if (!is_null($existingVisibilityFlag) && $existingVisibilityFlag['uid'] > 0) {
//todo: userfunc for custom record title
if ($enableLogging) {
// Prepare the history for logging.
$dataHandler->compareFieldArrayWithCurrentAndUnset(
'tx_languagevisibility_visibility_flag', $flagUid, $existingVisibilityFlag
);
//flag already exists and only needs to changed
$flagUid = $existingVisibilityFlag['uid'];
$dataHandler->updateDB(
'tx_languagevisibility_visibility_flag', $flagUid, ['flag' => $visibilityFlag]
);
} else {
$visibilityFlagRepository->setVisibilityFlag(
$visibilityFlag, 'pages', $childPageUid, $languageId
);
}
if ($enableLogging) {
// Prepare the history for logging.
$dataHandler->compareFieldArrayWithCurrentAndUnset(
'tx_languagevisibility_visibility_flag', $flagUid, $existingVisibilityFlag
);
$dataHandler->updateDB(
'tx_languagevisibility_visibility_flag', $flagUid, ['flag' => $visibilityFlag]
);
} else {
//visibility flag record doesnt exist and needs to be created
$newUid = uniqid('NEW', TRUE);
if ($enableLogging) {
if ($languageId === 0) {
$defaultLanguageRecordUid = 0;
} else {
$defaultLanguageRecordUid = (int) $visibilityFlagRepository->getDefaultLanguageParentUid(
'pages', $childPageUid
);
}
$dataHandler->insertDB(
'tx_languagevisibility_visibility_flag', $newUid,
[
'tstamp' => time(),
'crdate' => time(),
'flag' => $visibilityFlag,
'pid' => $childPageUid,
'record_table' => 'pages',
'record_uid' => 'pages_' . $childPageUid,
'record_language_uid' => $languageId,
'default_language_record_uid' => $defaultLanguageRecordUid,
'cruser_id' => $GLOBALS['BE_USER']->user['uid'],
]
);
} else {
$visibilityFlagRepository->setVisibilityFlag(
$visibilityFlag, 'pages', $childPageUid, $languageId
);
}
$visibilityFlagRepository->setVisibilityFlag(
$visibilityFlag, 'pages', $childPageUid, $languageId
);
}
}
//if the language is not default, we new to fetch the subpages by the default language parent
if ($languageId === 0) {
$recordUid = $childPageUid;
} else {
$recordUid = $visibilityFlagRepository->getDefaultLanguageParentUid('pages', $childPageUid);
//visibility flag record doesnt exist and needs to be created
$newUid = uniqid('NEW', TRUE);
if ($enableLogging) {
$dataHandler->insertDB(
'tx_languagevisibility_visibility_flag', $newUid,
[
'tstamp' => time(),
'crdate' => time(),
'flag' => $visibilityFlag,
'pid' => $childPageUid,
'record_table' => 'pages',
'record_uid' => 'pages_' . $childPageUid,
'record_language_uid' => $languageId,
'cruser_id' => $GLOBALS['BE_USER']->user['uid'],
]
);
} else {
$visibilityFlagRepository->setVisibilityFlag(
$visibilityFlag, 'pages', $childPageUid, $languageId
);
}
}
$this->applyVisibilityFlagRecursive(
$recordUid, $languageId, $visibilityFlag, $enableLogging, $dataHandler
$childPageUid, $languageId, $visibilityFlag, $enableLogging, $dataHandler
);
}
}
......@@ -467,14 +462,6 @@ class TceMainHook {
}
}
/**
* @param DataHandler $dataHandler
*/
public function processCmdmap_afterFinish(DataHandler $dataHandler) {
$visibilityFlagRepository = GeneralUtility::makeInstance(VisibilityFlagRepository::class);
$visibilityFlagRepository->fixAllLanguageParentUids();
}
/**
* Applies the given language data recursive.
*
......
......@@ -29,6 +29,7 @@ use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\Languagevisibility\Manager\CacheManager;
use TYPO3\CMS\Backend\Utility\BackendUtility;
/**
* @author Fabio Stegmeyer <fabio.stegmeyer@sgalinski.de>
......@@ -41,54 +42,6 @@ class VisibilityFlagRepository {
*/
protected static $instance;
/**
* Returns a complete flag row or NULL if none is found, fetched by default language element
*
* @param $table
* @param $recordUid
* @return array|null
*/
public function getVisibilityFlagByLanguageParent($table, $recordUid, $lUid): ?array {
$cacheManager = CacheManager::getInstance();
$cacheData = $cacheManager->get('visibilityFlagRowCache');
$isCacheEnabled = CacheManager::isCacheEnabled();
$cacheKey = $table . '_' . $recordUid . '_' . $lUid;
if (!$isCacheEnabled || !isset($cacheData[$cacheKey])) {
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable(
self::DB_TABLE
);
$row = $queryBuilder->select('*')
->from(self::DB_TABLE)
->where(
$queryBuilder->expr()->eq(
'default_language_record_uid', $queryBuilder->createNamedParameter($recordUid, \PDO::PARAM_INT)
)
)
->andWhere(
$queryBuilder->expr()->eq(
'record_table', $queryBuilder->createNamedParameter($table, \PDO::PARAM_STR)
)
)
->andWhere(
$queryBuilder->expr()->eq(
'record_language_uid', $queryBuilder->createNamedParameter($lUid, \PDO::PARAM_INT)
)
)
->execute()->fetch();
if ($row) {
$cacheData[$cacheKey] = $row;
$cacheManager->set('visibilityFlagRowCache', $cacheData);
}
}
return $cacheData[$cacheKey];
}
/**
* Inserts or updates a flag for a given element
*
......@@ -106,6 +59,16 @@ class VisibilityFlagRepository {
self::DB_TABLE
);
if ($table === 'pages') {
$pid = $recordUid;
} else {
$record = BackendUtility::getRecord($table, $recordUid, $fields = 'pid');
if (!is_null($record)) {
$pid = $record['pid'];
}
}
if (!is_null($existingVisibilityFlag)) {
//flag already exists and only needs to changed
$uid = (int) $existingVisibilityFlag['uid'];
......@@ -118,23 +81,41 @@ class VisibilityFlagRepository {
} else {
//flag doesnt exist and needs to be created
$languageParentUid = (int) $this->getDefaultLanguageParentUid($table, $recordUid);
$queryBuilder
->insert(self::DB_TABLE)
->values(
[
'pid' => $pid,
'flag' => $flag,
'record_table' => $table,
'record_uid' => $table . '_' . $recordUid,
'default_language_record_uid' => $languageParentUid,
'record_language_uid' => $lUid,
'tstamp' => time(),
'crdate' => time(),
'cruser_id' => $GLOBALS['BE_USER']->user['uid'],
]
)
->execute();
}
}
/**
* @param $uid
* @param $destPid
* @return void
*/
public function moveVisibilityFlag($uid, $destPid): void {
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable(
self::DB_TABLE
);
$queryBuilder
->update(self::DB_TABLE)
->where($queryBuilder->expr()->eq('uid', $uid))
->set('pid', $destPid)
->execute();
}
/**
* Returns a complete flag row or NULL if none is found
*
......@@ -187,41 +168,6 @@ class VisibilityFlagRepository {
return $cacheData[$cacheKey];
}
/**
* Returns the uid of the default language parent row for a given element
*
* @param $table
* @param $uid
* @return mixed
*/
public function getDefaultLanguageParentUid($table, $uid) {
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable(
$table
);
$queryBuilder->getRestrictions()
->removeAll();
$row = $queryBuilder->select($GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField'])
->from($table)
->where(
$queryBuilder->expr()->eq(
'uid', $queryBuilder->createNamedParameter($uid, \PDO::PARAM_INT)
)
)
->execute()->fetch();
if ($row['sys_language_uid'] > 0) {
$uid = $row['uid'];
$defaultLanguageParentUid = $this->getDefaultLanguageParentUid($table, $uid);
} else {
$defaultLanguageParentUid = $row[$GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField']];
}
return $defaultLanguageParentUid;
}
/**
* Return the visibility flag
*
......@@ -238,16 +184,6 @@ class VisibilityFlagRepository {
->removeAll()
->add(GeneralUtility::makeInstance(DeletedRestriction::class));
if ($lid > 0) {
$uidWhere = $queryBuilder->expr()->eq(
'default_language_record_uid', $queryBuilder->createNamedParameter($recordUid, \PDO::PARAM_INT)
);
} else {
$uidWhere = $queryBuilder->expr()->eq(
'record_uid', $queryBuilder->createNamedParameter($table . '_' . $recordUid, \PDO::PARAM_STR)
);
}
$result = $queryBuilder
->select('flag')
->from(self::DB_TABLE)
......@@ -261,7 +197,11 @@ class VisibilityFlagRepository {
'record_language_uid', $queryBuilder->createNamedParameter($lid, \PDO::PARAM_INT)
)
)
->andWhere($uidWhere)
->andWhere(
$queryBuilder->expr()->eq(
'record_uid', $queryBuilder->createNamedParameter($table . '_' . $recordUid, \PDO::PARAM_STR)
)
)
->setMaxResults(1)
->execute()->fetch();
......@@ -271,119 +211,6 @@ class VisibilityFlagRepository {
return '';
}
/**
* Returns the flag string
*
* @param string $table
* @param int $recordUid
* @return string|NULL
*/
public function getFlagByTableAndRecordUid($table, $recordUid): ?string {
$cacheManager = CacheManager::getInstance();
$cacheData = $cacheManager->get('visibilityFlagCache');
$isCacheEnabled = CacheManager::isCacheEnabled();
$cacheKey = $table . '_' . $recordUid;
if (!$isCacheEnabled || !isset($cacheData[$cacheKey])) {
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable(
self::DB_TABLE
);
$queryBuilder->getRestrictions()->removeAll()->add(GeneralUtility::makeInstance(DeletedRestriction::class));
$row = $queryBuilder->select('flag')
->from(self::DB_TABLE)
->where(
$queryBuilder->expr()->eq(
'record_uid', $queryBuilder->createNamedParameter($table . '_' . $recordUid, \PDO::PARAM_STR)
),
$queryBuilder->expr()->eq(
'record_table', $queryBuilder->createNamedParameter($table, \PDO::PARAM_STR)
)
)
->execute()->fetch();
if ($row) {
$cacheData[$cacheKey] = $row['flag'];
$cacheManager->set('visibilityFlagCache', $cacheData);
}
}
return $cacheData[$cacheKey];
}
/**
* Returns the whole flag record
*
* @param string $table
* @param int $recordUid
* @return array|NULL
*/
public function getVisibilityFlagRecordByTableAndRecordUid($table, $recordUid): ?array {
$cacheManager = CacheManager::getInstance();
$cacheData = $cacheManager->get('visibilityFlagCache');
$isCacheEnabled = CacheManager::isCacheEnabled();
$cacheKey = $table . '_' . $recordUid;
if (!$isCacheEnabled || !isset($cacheData[$cacheKey])) {
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable(
self::DB_TABLE
);
$queryBuilder->getRestrictions()->removeAll()->add(GeneralUtility::makeInstance(DeletedRestriction::class));
$row = $queryBuilder->select('*')
->from(self::DB_TABLE)
->where(
$queryBuilder->expr()->eq(
'record_uid', $queryBuilder->createNamedParameter($table . '_' . $recordUid, \PDO::PARAM_STR)
),
$queryBuilder->expr()->eq(
'record_table', $queryBuilder->createNamedParameter($table, \PDO::PARAM_STR)
)
)
->execute()->fetch();
if ($row) {
$cacheData[$cacheKey] = $row;
$cacheManager->set('visibilityFlagCache', $cacheData);
}
}
return $cacheData[$cacheKey];
}
/**
* Returns the uid the translation for a default language page
*
* @param $pageId
* @param $lid
* @return mixed
*/
public function getUidOfPageOverlay($pageId, $lid) {
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable(
'pages'
);
$queryBuilder->getRestrictions()->removeAll()->add(GeneralUtility::makeInstance(DeletedRestriction::class));
return $queryBuilder->select('uid')
->from('pages')
->where(
$queryBuilder->expr()->eq(
'pid', $queryBuilder->createNamedParameter($pageId, \PDO::PARAM_INT)
)
)
->AndWhere(
$queryBuilder->expr()->eq(
'sys_language_uid', $queryBuilder->createNamedParameter($lid, \PDO::PARAM_INT)
)
)
->execute()->fetch();
}
/**
* Removes the flags for given table and pid.
*
......@@ -412,47 +239,6 @@ class VisibilityFlagRepository {
->execute();
}
/**
* Iterates over all flag and fixes the language parent uid (is wrong when copied)
*
* @return void
*/
public function fixAllLanguageParentUids(): void {
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable(
self::DB_TABLE
);
$rows = $queryBuilder
->select('*')
->from(self::DB_TABLE)
->execute()->fetchAll();
if (count($rows) > 0) {
foreach ($rows as $row) {
$uid = $row['uid'];
$table = $row['record_table'];
$recordUid = str_replace($table . '_', '', $row['record_uid']);
$currentLanguageParentUid = $row['default_language_record_uid'];
$correctLanguageParentUid = $this->getDefaultLanguageParentUid($table, $recordUid);
if ($correctLanguageParentUid > 0 && $correctLanguageParentUid !== $currentLanguageParentUid) {
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable(
self::DB_TABLE
);
$queryBuilder
->update(self::DB_TABLE)
->where($queryBuilder->expr()->eq('uid', $uid))
->set('default_language_record_uid', $correctLanguageParentUid)
->execute();
}
}
}
}
/**
* This function is called after TceMainHook operation to delete all default-flags
*
......
......@@ -90,7 +90,7 @@ class FrontendServices extends AbstractServices {
return FALSE;
}
// if the visibility Flag isn't straight forward, we use the element-object to resolve the visibility
// if the visibility flag isn't straight forward, we use the element-object to resolve the visibility
$elementfactory = GeneralUtility::makeInstance(ElementFactory::class);
$element = $elementfactory->getElementForTable($table, $row);
$languageRep = GeneralUtility::makeInstance(LanguageRepository::class);
......
......@@ -369,7 +369,7 @@ class VisibilityService implements SingletonInterface {
}
/**
* Create a visiblity object for an element for a given language.
* Create a Visibility object for an element for a given language.
*
* @param Language $language
* @param Element $element
......@@ -382,7 +382,6 @@ class VisibilityService implements SingletonInterface {
$visibility = new Visibility();
$local = $element->getVisibilitySettingForLanguage($language->getUid());
if ($local !== '' && $local !== '-') {
$visibility->setVisibilityString($local)->setVisibilityDescription('local setting ' . $local);
return $visibility;
......
......@@ -7,9 +7,11 @@ use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Install\Updates\DatabaseUpdatedPrerequisite;
use TYPO3\CMS\Core\Registry;
use TYPO3\CMS\Install\Updates\UpgradeWizardInterface;
use TYPO3\Languagevisibility\Repository\LanguageRepository;
use TYPO3\Languagevisibility\Repository\VisibilityFlagRepository;
use TYPO3\Languagevisibility\Service\VisibilityService;
use TYPO3\CMS\Core\Exception;
use TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction;
class VisibilitySettingsMigrationWizard implements UpgradeWizardInterface {
......@@ -56,6 +58,8 @@ class VisibilitySettingsMigrationWizard implements UpgradeWizardInterface {
public function executeUpdate(): bool {
$this->visibilityFlagRepository = GeneralUtility::makeInstance(VisibilityFlagRepository::class);
$languageRep = GeneralUtility::makeInstance(LanguageRepository::class);
$availablesLanguages = $languageRep->getLanguages();
// go through all configured tables
foreach ($GLOBALS['TCA'] as $table => $config) {
......@@ -65,17 +69,11 @@ class VisibilitySettingsMigrationWizard implements UpgradeWizardInterface {
$table, VisibilityService::getSupportedTables(), TRUE
)) {
try {
$transOrigPointerField = $GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField'];
//make sure the query-builder is fresh
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable(
$table
);
try {
// get all uids
$uids = $queryBuilder->select('uid')
->from($table)
->execute()->fetchAll();
$uids = $this->getDefaultLanguageUids($table);
foreach ($uids as $uidRow) {
$uid = $uidRow['uid'];
......@@ -83,47 +81,84 @@ class VisibilitySettingsMigrationWizard implements UpgradeWizardInterface {
if ($uid > 0) {
$row = $this->getRecord($table, $uid);
$defaultLanguageRecordUid = $uid;
$queryBuilderVisibilityFlags = GeneralUtility::makeInstance(
ConnectionPool::class
)->getQueryBuilderForTable(
'tx_languagevisibility_visibility_flag'
$localVisibilitySettings = @unserialize(
$row['tx_languagevisibility_visibility'], ['allowed_classes' => FALSE]
);
$languageParentUid = $this->visibilityFlagRepository->getDefaultLanguageParentUid(
$table, $uid
$translations = $this->getTranslations(
$table, $transOrigPointerField, $defaultLanguageRecordUid
);
// the pid should always be the default language page
if ($table === 'pages') {
if ($row['sys_language_uid'] > 0) {
$pid = $languageParentUid;
foreach ($availablesLanguages as $language) {
$lid = $language->getUid();
$queryBuilderVisibilityFlags = GeneralUtility::makeInstance(
ConnectionPool::class
)->getQueryBuilderForTable(
'tx_languagevisibility_visibility_flag'
);
if (isset($translations[$lid])) {
$translation = $translations[$lid];
$overlayVisibilityArray = @unserialize(
$translation['tx_languagevisibility_visibility'], ['allowed_classes' => FALSE]
);
$overlayVisibility = $overlayVisibilityArray[$lid];
$localVisibility = $localVisibilitySettings[$lid];
// determine visibility setting - taken from getLocalVisibilitySetting previously
if ($overlayVisibility === 'no+' || $localVisibility === 'no+') {
$visibilitySetting = 'no+';
} elseif ($overlayVisibility === 'no') {
$visibilitySetting = $overlayVisibility;
} else {
$visibilitySetting = (string) $localVisibility;
}
} else {
$pid = $uid;
$visibilitySetting = $localVisibilitySettings[$lid];
}
} else {
$pid = $row['pid'];
}
$lid = $row['sys_language_uid'];
$visibilitySetting = $this->getVisibilitySettingByUid($uid, $table);
if ($visibilitySetting) {
$queryBuilderVisibilityFlags
->insert('tx_languagevisibility_visibility_flag')
->values(
[
'pid' => $pid,
'flag' => $visibilitySetting,
'record_table' => $table,
'record_uid' => $table . '_' . $uid,
'default_language_record_uid' => $languageParentUid,
'record_language_uid' => $lid,
'tstamp' => time(),
'crdate' => time(),
]
)
->execute();
if ($visibilitySetting) {
// the pid should always be the default language page
if ($table === 'pages') {
if ($lid > 0) {
$pid = $defaultLanguageRecordUid;
} else {
$pid = $uid;
}
} else {
$pid = $row['pid'];
}
// the record_uid should always be the default language record
if ($lid > 0) {
$recordUid = $table . '_' . $defaultLanguageRecordUid;
} else {
$recordUid = $table . '_' . $uid;
}
$queryBuilderVisibilityFlags
->insert('tx_languagevisibility_visibility_flag')
->values(
[
'pid' => $pid,
'flag' => $visibilitySetting,
'record_table' => $table,
'record_uid' => $recordUid,
'record_language_uid' => $lid,
'tstamp' => time(),
'crdate' => time(),
]
)
->execute();
}
}
}
}
......@@ -133,8 +168,7 @@ class VisibilitySettingsMigrationWizard implements UpgradeWizardInterface {
}
}
// do some fixing and cleanup
$this->visibilityFlagRepository->fixAllLanguageParentUids();
// cleanup
$this->visibilityFlagRepository->deleteDefaultFlags();
//mark wizard as done in registry
......@@ -148,57 +182,57 @@ class VisibilitySettingsMigrationWizard implements UpgradeWizardInterface {
}
/**
* @param $uid
* @param $table
* @return mixed|string
* @return mixed
*/
protected function getVisibilitySettingByUid($uid, $table) {
$visibilitySetting = '';
$row = $this->getRecord($table, $uid);
protected function getDefaultLanguageUids($table) {
if (is_array($row)) {
$lid = $row['sys_language_uid'];
if ($lid > 0) {
//when the language in non-default, we need to determine the active flag according to the old element logic
$transOrigPointerField = $GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField'];
$defaultLanguageRecordUid = $row[$transOrigPointerField];
$defaultLanguageRecord = $this->getRecord($table, $defaultLanguageRecordUid);
$overlayVisibilityArray = @unserialize(
$row['tx_languagevisibility_visibility'], ['allowed_classes' => FALSE]
);
$overlayVisibility = $overlayVisibilityArray[$lid];
// get visibility setting from default language record
$localVisibilityArray = @unserialize(
$defaultLanguageRecord['tx_languagevisibility_visibility'], ['allowed_classes' => FALSE]
);
$localVisibility = $localVisibilityArray[$lid];
// todo: does this make sense? or should we always use the overlayVisibility when present?
// e.g. "yes" flags aren't saved this way, but on the other side its the same logic as used to determine the setting used in translated elements previously
// determine visibility setting - taken from getLocalVisibilitySetting previously
if ($overlayVisibility === 'no+' || $localVisibility === 'no+') {
$visibilitySetting = 'no+';
} elseif ($overlayVisibility === 'no') {
$visibilitySetting = $overlayVisibility;
} else {
$visibilitySetting = (string) $localVisibility;
}
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable(
$table
);
} else {
// if default language, get the settings directly from the record
$localVisibilitySetting = @unserialize(
$row['tx_languagevisibility_visibility'], ['allowed_classes' => FALSE]
);
$visibilitySetting = $localVisibilitySetting[0];
}
if ($GLOBALS['TCA'][$table]['ctrl']['enable_columns']) {
//remove restrictions so that hidden records also get migrated
$queryBuilder
->getRestrictions()
->removeAll()
->add(GeneralUtility::makeInstance(DeletedRestriction::class));
// get all default_language_record uids
$uids = $queryBuilder->select('uid')
->from($table)
->where(
$queryBuilder->expr()->eq(
'sys_language_uid', $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT)
)
)
->execute()->fetchAll();
} else {
// fallback for tables with dynamically generated enable columns
//remove restrictions so that hidden records also get migrated
$queryBuilder
->getRestrictions()
->removeAll();
// get all default_language_record uids
$uids = $queryBuilder->select('uid')
->from($table)
->where(
$queryBuilder->expr()->eq(
'sys_language_uid', $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT)
)
)
->andWhere(
$queryBuilder->expr()->eq(
'deleted', $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT)
)
)
->execute()->fetchAll();
}
return $visibilitySetting;
return $uids;
}
/**
......@@ -213,15 +247,107 @@ class VisibilitySettingsMigrationWizard implements UpgradeWizardInterface {
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable(
$table
);
if ($GLOBALS['TCA'][$table]['ctrl']['enable_columns']) {
//remove restrictions so that hidden records also get migrated
$queryBuilder
->getRestrictions()
->removeAll()
->add(GeneralUtility::makeInstance(DeletedRestriction::class));
return $queryBuilder->select('*')
->from($table)
->where(
$queryBuilder->expr()->eq('uid', $queryBuilder->createNamedParameter($uid))
)
->setMaxResults(1)
->execute()->fetch();
}
// fallback for tables with dynamically generated enable columns
//remove restrictions so that hidden records also get migrated
$queryBuilder
->getRestrictions()
->removeAll();
return $queryBuilder->select('*')
->from($table)
->where(
$queryBuilder->expr()->eq('uid', $queryBuilder->createNamedParameter($uid))
)
->andWhere(
$queryBuilder->expr()->eq(
'deleted', $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT)
)
)
->setMaxResults(1)
->execute()->fetch();
}
/**
* @param $table
* @param $field
* @param $uid
* @return array
*/
protected function getTranslations($table, $field, $uid) {
//make sure the query-builder is fresh
$queryBuilder = GeneralUtility::makeInstance(
ConnectionPool::class
)->getQueryBuilderForTable(
$table
);
if ($GLOBALS['TCA'][$table]['ctrl']['enable_columns']) {
//remove restrictions so that hidden records also get migrated
$queryBuilder
->getRestrictions()
->removeAll()
->add(GeneralUtility::makeInstance(DeletedRestriction::class));
$translationsRows = $queryBuilder->select('*')
->from($table)
->where(
$queryBuilder->expr()->eq(
$field,
$queryBuilder->createNamedParameter($uid, \PDO::PARAM_INT)
)
)
->execute()->fetchAll();
} else {
$queryBuilder
->getRestrictions()
->removeAll();
$translationsRows = $queryBuilder->select('*')
->from($table)
->where(
$queryBuilder->expr()->eq(
$field,
$queryBuilder->createNamedParameter($uid, \PDO::PARAM_INT)
)
)
->andWhere(
$queryBuilder->expr()->eq(
'deleted', $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT)
)
)
->execute()->fetchAll();
}
$translations = [];
foreach ($translationsRows as $translationRow) {
$translations[$translationRow['uid']] = $translationRow;
}
return $translations;
}
/**
* Is an update necessary?
*
......
......@@ -147,19 +147,16 @@ class FieldVisibilityUserFunction {
$this->visibilityFlagRepository = GeneralUtility::makeInstance(VisibilityFlagRepository::class);
$visibility = GeneralUtility::makeInstance(VisibilityService::class);
$visibilityString = '';
$infosStruct = [];
$recordUid = $changeableElement->getTable() . '_' . $changeableElement->getUid();
/** @var Language $language */
foreach ($languageList as $language) {
if ($language->getUid() < 0) {
continue;
}
if (!$changeableElement->hasTranslation($language->getUid())) {
continue;
}
try {
$infoitem = [
'languageTitle' => $language->getTitle($this->pageId),
......@@ -173,84 +170,76 @@ class FieldVisibilityUserFunction {
continue;
}
// if there is no access to language - and localsettings exist, then do not show select box
// this is to not be able as a translator to override languagesetting
$currentSetting = $changeableElement->getVisibilitySettingForLanguage($language->getUid());
$currentOptionsForUserAndLanguage = BackendServices::getAvailableOptionsForLanguage(
$language, $isOverlay, $changeableElement
);
// overlay here just means the default language record or a localization of the record for the given language
$overlay = $changeableElement->getOverLayRecordForCertainLanguage($language->getUid());
// if there is no overlay for the language, there is no point in displaying the visibility settings for the given language, since we can't know the uid of the translated element yet
if (is_array($overlay) && count($overlay) > 0) {
$overlayUid = $overlay['uid'];
//check if a flag for this localization/overlay has already been set
$visbilityFlag = $this->visibilityFlagRepository->getVisibilityFlag(
$changeableElement->getTable(), $overlayUid, $language->getUid()
);
if (!is_null($visbilityFlag)) {
$visibilityFlagUid = $visbilityFlag['uid'];
$currentVisibilityFlag = $visbilityFlag['flag'];
} else {
$visibilityFlagUid = uniqid('NEW', TRUE);
$currentVisibilityFlag = '-';
}
//build array with names and values for hidden input
$nameBase = 'data[tx_languagevisibility_visibility_flag][' . $visibilityFlagUid . ']';
$nameArray = [
'record_language_uid' => [
'name' => $nameBase . '[record_language_uid]',
'value' => $language->getUid()
],
'record_table' => [
'name' => $nameBase . '[record_table]',
'value' => $changeableElement->getTable()
],
'record_uid' => [
'name' => $nameBase . '[record_uid]',
'value' => $changeableElement->getTable() . '_' . $overlay['uid']
],
'default_language_record_uid' => [
'name' => $nameBase . '[default_language_record_uid]',
'value' => $overlay[$GLOBALS['TCA'][$changeableElement->getTable(
)]['ctrl']['transOrigPointerField']]
],
'flag' => [
'name' => $nameBase . '[flag]',
'value' => $currentVisibilityFlag,
],
'pid' => [
'name' => $nameBase . '[pid]',
'value' => $changeableElement->getTable() === 'pages' ? $overlay['uid'] : $overlay['pid'],
],
];
//check if a flag for this localization/overlay has already been set
$visbilityFlag = $this->visibilityFlagRepository->getVisibilityFlag(
$changeableElement->getTable(), $changeableElement->getUid(), $language->getUid()
);
$defaultSelect = $changeableElement->getVisibilitySettingForLanguage($language->getUid());
if (!is_null($visbilityFlag)) {
$visibilityFlagUid = $visbilityFlag['uid'];
$currentVisibilityFlag = $visbilityFlag['flag'];
} else {
$visibilityFlagUid = uniqid('NEW', TRUE);
$currentVisibilityFlag = '-';
}
$visibilityString = $currentOptionsForUserAndLanguage[$currentVisibilityFlag];
if ($changeableElement->getTable() === 'pages') {
$pid = $changeableElement->getUid();
} else {
$pid = $changeableElement->getPid();
}
if ($this->isNewElement && $defaultSelect === ''
&& $this->modTSconfig['language.'][$language->getUid() . '.']['defaultVisibilityOnCreate'] !== ''
) {
$defaultSelect = $this->modTSconfig['language.'][$language->getUid() .
'.']['defaultVisibilityOnCreate'];
}
$selectBox = $this->getSelectBoxAndHiddenInputs(
$language->getUid(), $currentOptionsForUserAndLanguage, $currentVisibilityFlag, $nameArray
);
//build array with names and values for hidden input
$nameBase = 'data[tx_languagevisibility_visibility_flag][' . $visibilityFlagUid . ']';
$nameArray = [
'record_language_uid' => [
'name' => $nameBase . '[record_language_uid]',
'value' => $language->getUid()
],
'record_table' => [
'name' => $nameBase . '[record_table]',
'value' => $changeableElement->getTable()
],
'record_uid' => [
'name' => $nameBase . '[record_uid]',
'value' => $recordUid
],
'flag' => [
'name' => $nameBase . '[flag]',
'value' => $currentVisibilityFlag,
],
'pid' => [
'name' => $nameBase . '[pid]',
'value' => $pid,
],
];
$defaultSelect = $changeableElement->getVisibilitySettingForLanguage($language->getUid());
$visibilityString = $currentOptionsForUserAndLanguage[$currentVisibilityFlag];
//todo: we still need this?
if ($this->isNewElement && $defaultSelect === ''
&& $this->modTSconfig['language.'][$language->getUid() . '.']['defaultVisibilityOnCreate'] !== ''
) {
$defaultSelect = $this->modTSconfig['language.'][$language->getUid() .
'.']['defaultVisibilityOnCreate'];
}
$selectBox = $this->getSelectBoxAndHiddenInputs(
$language->getUid(), $currentOptionsForUserAndLanguage, $currentVisibilityFlag, $nameArray
);
$infoitem['visibilityOptions'] = $selectBox;
$infoitem['visibilityCurrently'] = $visibilityString;
$infoitem['visibilityOptions'] = $selectBox;
$infoitem['visibilityCurrently'] = $visibilityString;
$alertText = 'Be careful, when using the recursive function. This can destroy the whole frontend!';
$recursiveId = $nameBase . '-applyRecursive-' . $language->getUid();
$infoitem['applyRecursiveCheckbox'] = '<div class="checkbox checkbox-type-icon-toggle">
$alertText = 'Be careful, when using the recursive function. This can destroy the whole frontend!';
$recursiveId = $nameBase . '-applyRecursive-' . $language->getUid();
$infoitem['applyRecursiveCheckbox'] = '<div class="checkbox checkbox-type-icon-toggle">
<input type="checkbox"
class="checkbox-input"
value="1"
......@@ -261,28 +250,27 @@ class FieldVisibilityUserFunction {
<span class="checkbox-label-icon">
<span class="checkbox-label-icon-checked">
' . GeneralUtility::makeInstance(IconFactory::class)->getIcon(
'actions-check', Icon::SIZE_SMALL
)->render('inline') . '
'actions-check', Icon::SIZE_SMALL
)->render('inline') . '
</span>
<span class="checkbox-label-icon-unchecked">
' . GeneralUtility::makeInstance(IconFactory::class)->getIcon(
'empty-empty', Icon::SIZE_SMALL
)->render('inline') . '
'empty-empty', Icon::SIZE_SMALL
)->render('inline') . '
</span>
</span>
</label>
</div>';
// the enable logging info is required for each language now, therefore an hidden field is added for each language which is changed by the main enableLogging Checkbox
$hiddenEnableLoggingClass = 'contentElement-' . $changeableElement->getUid(
) . '-hiddenEnableLoggingInput';
$infoitem['hiddenEnableLoggingInput'] = '<input type="hidden"
// the enable logging info is required for each language now, therefore an hidden field is added for each language which is changed by the main enableLogging Checkbox
$hiddenEnableLoggingClass = 'contentElement-' . $changeableElement->getUid() . '-hiddenEnableLoggingInput';
$infoitem['hiddenEnableLoggingInput'] = '<input type="hidden"
value="1"
name="' . $nameBase . '[enableLogging]"
class="' . $hiddenEnableLoggingClass . '" />';
$enableLoggingId = $nameBase . '-enableLogging';
$infoitem['enableLoggingCheckbox'] = '<div class="checkbox checkbox-type-icon-toggle">
$enableLoggingId = $nameBase . '-enableLogging';
$infoitem['enableLoggingCheckbox'] = '<div class="checkbox checkbox-type-icon-toggle">
<input type="checkbox"
class="checkbox-input"
value="1"
......@@ -294,21 +282,21 @@ class FieldVisibilityUserFunction {
<span class="checkbox-label-icon">
<span class="checkbox-label-icon-checked">
' . GeneralUtility::makeInstance(IconFactory::class)->getIcon(
'actions-check', Icon::SIZE_SMALL
)->render('inline') . '
'actions-check', Icon::SIZE_SMALL
)->render('inline') . '
</span>
<span class="checkbox-label-icon-unchecked">
' . GeneralUtility::makeInstance(IconFactory::class)->getIcon(
'empty-empty', Icon::SIZE_SMALL
)->render('inline') . '
'empty-empty', Icon::SIZE_SMALL
)->render('inline') . '
</span>
</span>
<span class="checkbox-label-text">' . $this->getLLL('enableLogging') . '</span>
</label>
</div>';
$infosStruct[] = $infoitem;
}
$infosStruct[] = $infoitem;
}
return $infosStruct;
......@@ -334,7 +322,6 @@ class FieldVisibilityUserFunction {
$content .= '<input type="hidden" name="' . $nameArray['record_table']['name'] . '" value="' . $nameArray['record_table']['value'] . '" />';
$content .= '<input type="hidden" name="' . $nameArray['record_uid']['name'] . '" value="' . $nameArray['record_uid']['value'] . '" />';
$content .= '<input type="hidden" name="' . $nameArray['record_language_uid']['name'] . '" value="' . $nameArray['record_language_uid']['value'] . '" />';
$content .= '<input type="hidden" name="' . $nameArray['default_language_record_uid']['name'] . '" value="' . $nameArray['default_language_record_uid']['value'] . '" />';
$content .= '<input type="hidden" name="' . $nameArray['pid']['name'] . '" value="' . $nameArray['pid']['value'] . '" />';
$content .= '<select class="form-control' . $addClassName . '" name="' . $nameArray['flag']['name'] . '">';
......
<?php
use TYPO3\Languagevisibility\Service\VisibilityService;
return [
'ctrl' => [
'label_userFunc' => 'TYPO3\\Languagevisibility\\UserFunction\\Tca->customTitle',
......@@ -21,7 +24,7 @@ return [
'config' => [
'type' => 'group',
'internal_type' => 'db',
'allowed' => 'pages,tt_content',
'allowed' => implode(',', VisibilityService::getSupportedTables()),
'foreign_table' => 'tt_content',
'maxitems' => 1,
'minitems' => 0,
......
......@@ -183,9 +183,6 @@
<trans-unit id="tx_languagevisibility_visibility_flag.record_language_uid">
<target>Sprache</target>
</trans-unit>
<trans-unit id="tx_languagevisibility_visibility_flag.default_language_record_uid">
<target>Standard-Sprache-Eltern-Element</target>
</trans-unit>
<trans-unit id="tx_languagevisibility_visibility_flag.record_flag">
<target>Einstellung</target>
</trans-unit>
......
......@@ -142,9 +142,6 @@
<trans-unit id="tx_languagevisibility_visibility_flag.record_language_uid">
<source>Language</source>
</trans-unit>
<trans-unit id="tx_languagevisibility_visibility_flag.default_language_record_uid">
<source>Parent-Element</source>
</trans-unit>
<trans-unit id="tx_languagevisibility_visibility_flag.record_flag">
<source>Flag</source>
</trans-unit>
......
......@@ -33,6 +33,9 @@ call_user_func(
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['GLOBAL']['extTablesInclusion-PostProcessing'][$extKey] =
\TYPO3\Languagevisibility\Hook\TcaHook::class;
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['moveRecordClass'][$extKey] =
\TYPO3\Languagevisibility\Hook\TceMainHook::class;
// overriding option because this is done by languagevisibility and will not work if set
$GLOBALS['TYPO3_CONF_VARS']['FE']['hidePagesIfNotTranslatedByDefault'] = 0;
......
......@@ -38,6 +38,5 @@ CREATE TABLE tx_languagevisibility_visibility_flag (
record_uid text DEFAULT '' NOT NULL,
record_language_uid int(11) DEFAULT '0' NOT NULL,
flag text NOT NULL,
default_language_record_uid int(11) DEFAULT '0' NOT NULL,
PRIMARY KEY (uid)
);