...
 
Commits (6)
......@@ -27,7 +27,7 @@ namespace TYPO3\Languagevisibility\Element;
/**
*
* @author Daniel Poetzinger <poetzinger@aoemedia.de>
* @author Daniel Poetzinger <poetzinger@aoemedia.de>
* @coauthor Tolleiv Nietsch <nietsch@aoemedia.de>
* @coauthor Timo Schmidt <schmidt@aoemedia.de>
*/
......@@ -39,7 +39,7 @@ class ContentElement extends RecordElement {
* (non-PHPdoc)
* @see classes/tx_languagevisibility_element#initialisations()
*/
protected function initialisations() {
protected function initialisations(): void {
}
/**
......
......@@ -26,14 +26,20 @@ namespace TYPO3\Languagevisibility\Element;
* This copyright notice MUST APPEAR in all copies of the script!
***************************************************************/
use Doctrine\DBAL\DBALException;
use ReflectionClass;
use ReflectionException;
use TYPO3\CMS\Backend\Utility\BackendUtility;
use TYPO3\CMS\Core\Cache\Exception\NoSuchCacheException;
use TYPO3\CMS\Core\Cache\Frontend\VariableFrontend;
use TYPO3\CMS\Core\Context\Context;
use TYPO3\CMS\Core\Context\Exception\AspectNotFoundException;
use TYPO3\CMS\Core\Site\Entity\SiteLanguage;
use TYPO3\CMS\Core\Site\SiteFinder;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Utility\LocalizationUtility;
use TYPO3\Languagevisibility\Exception\InvalidRowException;
use TYPO3\Languagevisibility\Manager\CacheManager;
use TYPO3\Languagevisibility\Repository\LanguageRepository;
use TYPO3\Languagevisibility\Repository\VisibilityFlagRepository;
/**
......@@ -61,17 +67,16 @@ abstract class Element {
protected $globalVisibilitySettings = [];
/**
* @var \TYPO3\CMS\Core\Cache\Frontend\VariableFrontend
* @var VariableFrontend
*/
protected $cache;
/**
* @param array $row
* @param string $tablename
* @return Element
* @throws \ReflectionException
* @throws \TYPO3\CMS\Core\Cache\Exception\NoSuchCacheException
* @throws InvalidRowException
* @throws ReflectionException
* @throws NoSuchCacheException
* @throws InvalidRowException|DBALException
*/
public function __construct(array $row, string $tablename = '') {
$this->table = $tablename;
......@@ -107,7 +112,7 @@ abstract class Element {
* @param string $table
* @return void
*/
public function setTable(string $table) {
public function setTable(string $table): void {
$this->table = $table;
}
......@@ -121,35 +126,23 @@ abstract class Element {
}
/**
* @return array
*/
public function getRow(): array {
return $this->row;
}
/**
* @param array $row
*/
public function setRow(array $row): void {
$this->row = $row;
}
/**
* Method to deternmine that an Element will not be instanciated with
* Method to determine that an Element will not be instantiated with
* data of an overlay.
*
* @param array $row
* @return bool
*/
protected function isRowOriginal(array $row) {
protected function isRowOriginal(array $row): bool {
return !isset($row[$GLOBALS['TCA'][$this->table]['ctrl']['transOrigPointerField']]) ||
$row[$GLOBALS['TCA'][$this->table]['ctrl']['transOrigPointerField']] === 0;
}
/**
* possibility to add inits in subclasses
*
* @return void
**/
protected function initialisations() {
protected function initialisations(): void {
}
/**
......@@ -200,18 +193,22 @@ abstract class Element {
public function getInformativeDescription(): string {
if ($this->isMonolithicTranslated()) {
return LocalizationUtility::translate('backend.contentElement.notDefault', 'languagevisibility');
} elseif ($this->isLanguageSetToAll()) {
}
if ($this->isLanguageSetToAll()) {
return LocalizationUtility::translate('backend.contentElement.languageSetToAll', 'languagevisibility');
} elseif ($this->isLanguageSetToDefault()) {
}
if ($this->isLanguageSetToDefault()) {
return LocalizationUtility::translate('backend.contentElement.normal', 'languagevisibility');
} else {
return LocalizationUtility::translate('backend.contentElement.translated', 'languagevisibility');
}
return LocalizationUtility::translate('backend.contentElement.translated', 'languagevisibility');
}
/**
* This method is used to determine the visibility of the element. Technically it merges the visibility of
* the default language record and the overlay record and returns the visibility. The visibility in the overlayrecord
* the default language record and the overlay record and returns the visibility. The visibility in the overlayRecord
* can overwrite the visibility of its own language.
* This method is only need to display the visibility setting in the backend.
*
......@@ -242,7 +239,6 @@ abstract class Element {
* This method is only need to display the visibility setting in the backend.
*
* @param int $languageid
* @param int $languageid
* @return string
* @return string|null
* @deprecated
......@@ -285,6 +281,7 @@ abstract class Element {
* fetches and sets the global / default language visibility settings for the element
*
* @return array
* @throws DBALException
*/
public function fetchGlobalVisibilitySettings(): array {
......@@ -292,14 +289,29 @@ abstract class Element {
$table = $this->getTable();
$languageRep = GeneralUtility::makeInstance(LanguageRepository::class);
$visibilityFlagRepository = GeneralUtility::makeInstance(VisibilityFlagRepository::class);
$availablesLanguages = $languageRep->getLanguages();
$siteFinder = GeneralUtility::makeInstance(SiteFinder::class);
if ($table === 'pages') {
$pid = $this->getUid();
} else {
$pid = $this->getPid();
}
try {
$rootLine = BackendUtility::BEgetRootLine($pid);
$site = $siteFinder->getSiteByPageId($pid, $rootLine);
} catch (\Exception $e) {
return [];
}
$availablesLanguages = $site->getAllLanguages();
foreach ($availablesLanguages as $language) {
$flagRow = $visibilityFlagRepository->getVisibilityFlag($table, $this->getUid(), $language->getUid());
$flagRow = $visibilityFlagRepository->getVisibilityFlag(
$table, $this->getUid(), $language->getLanguageId()
);
if ($flagRow === FALSE || $flagRow === NULL) {
$flag = '-';
......@@ -307,7 +319,7 @@ abstract class Element {
$flag = $flagRow['flag'];
}
$globalVisibilitySettings[$language->getUid()] = $flag;
$globalVisibilitySettings[$language->getLanguageId()] = $flag;
}
return $globalVisibilitySettings;
......@@ -316,11 +328,11 @@ abstract class Element {
/**
* Receive relevant fallbackOrder
*
* @param Language $language
* @param SiteLanguage $language
* @return array
*/
public function getFallbackOrder(Language $language): array {
return $language->getFallbackOrder($this);
public function getFallbackOrder(SiteLanguage $language): array {
return $language->getFallbackLanguageIds();
}
/**
......@@ -342,7 +354,7 @@ abstract class Element {
}
/**
* Checks if the current record is set to language all (that is typically used to indicate that per default this element is visible in all langauges)
* Checks if the current record is set to language all (that is typically used to indicate that per default this element is visible in all languages)
*
* @return bool
*/
......@@ -362,11 +374,11 @@ abstract class Element {
/**
* Compare element-language and foreign language.
*
* @param Language $language
* @param SiteLanguage $language
* @return bool
*/
public function languageEquals(Language $language): bool {
return (int) $this->row['sys_language_uid'] === $language->getUid();
public function languageEquals(SiteLanguage $language): bool {
return (int) $this->row['sys_language_uid'] === $language->getLanguageId();
}
/**
......@@ -380,14 +392,10 @@ abstract class Element {
$result = FALSE;
if (!is_numeric($languageid)) {
$result = FALSE;
} else {
if ($languageid === 0) {
$result = TRUE;
} else {
if ($this->_hasOverlayRecordForLanguage($languageid)) {
$result = TRUE;
}
}
} else if ($languageid === 0) {
$result = TRUE;
} else if ($this->_hasOverlayRecordForLanguage($languageid)) {
$result = TRUE;
}
return $result;
......@@ -414,7 +422,7 @@ abstract class Element {
}
/**
* Method to get a short description of the elementtype.
* Method to get a short description of the elementType.
* An extending class should overwrite this method.
*
* @return string
......@@ -423,20 +431,11 @@ abstract class Element {
return 'TYPO3 Element';
}
/**
* By default no element supports inheritance
*
* @return bool
*/
public function supportsInheritance(): bool {
return FALSE;
}
/**
* Gets the cache
*
* @return VariableFrontend
* @throws \TYPO3\CMS\Core\Cache\Exception\NoSuchCacheException
* @throws NoSuchCacheException
*/
protected function getCache(): VariableFrontend {
if (!$this->cache) {
......@@ -478,7 +477,7 @@ abstract class Element {
*
* @param array $row
* @return bool
* @throws \TYPO3\CMS\Core\Context\Exception\AspectNotFoundException
* @throws AspectNotFoundException
*/
protected function getEnableFieldResult(array $row): bool {
$ctrl = $GLOBALS['TCA'][$this->table]['ctrl'];
......
......@@ -26,15 +26,14 @@ namespace TYPO3\Languagevisibility\Element;
* This copyright notice MUST APPEAR in all copies of the script!
***************************************************************/
use TYPO3\CMS\Backend\Utility\BackendUtility;
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\Languagevisibility\Service\FrontendServices;
use TYPO3\Languagevisibility\Exception\TableNotSupportedException;
/**
* Class tx_languagevisibility_elementFactory
* Class ElementFactory
*/
class ElementFactory {
......@@ -43,13 +42,13 @@ class ElementFactory {
*
* @param string $table table
* @param array $row identifier
* @param bool $overlay_ids boolean parameter to overlay uids if the user is in workspace context
* @throws \UnexpectedValueException
* @param bool $overlay_ids boolean parameter to overlay UIDs if the user is in workspace context
* @return Element
* @throws TableNotSupportedException
*/
public function getElementForTable(string $table, array $row, bool $overlay_ids = TRUE): Element {
if (!FrontendServices::isSupportedTable($table)) {
throw new \UnexpectedValueException($table . ' not supported ', 1195039394);
throw new TableNotSupportedException($table . ' not supported ', 1195039394);
}
if (
......@@ -94,7 +93,7 @@ class ElementFactory {
} elseif (isset($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['languagevisibility']['recordElementSupportedTables'][$table])) {
$element = $this->getElementInstance(RecordElement::class, $row);
} else {
throw new UnexpectedValueException($table . ' not supported ', 1195039394);
throw new TableNotSupportedException($table . ' not supported ', 1195039394);
}
break;
}
......@@ -104,85 +103,11 @@ class ElementFactory {
return $element;
}
/**
* This method is used to retrieve all parent elements (an parent elements needs to
* have the flag 'tx_languagevisibility_inheritanceflag_original' or
* needs to be orverlayed with a record, that has the field 'tx_languagevisibility_inheritanceflag_overlayed'
* configured or is the first element of the rootline
*
* @param Element $element
* @param Language $language
* @return array $elements (collection of tx_languagevisibility_element)
* @throws \TYPO3\CMS\Core\Cache\Exception\NoSuchCacheException
*/
public function getParentElementsFromElement(Element $element, $language) {
$parentPage = $this->getElementForTable('pages', $element->getRow());
return $this->getParentElementsFromElement($parentPage, $language);
}
/**
* This method is needed because the getRootline method from t3lib_pageSelect causes an error when
* getRootline is called be cause getRootline internally uses languagevisibility to determine the
* visibility during the rootline calculation. This results in an unlimited recursion.
*
* @todo The rooline can be build in a smarter way, once the rootline for a page has been created
* same parts of the rootline not have to be calculated twice.
* @param $uid
* @param $languageid
* @return array
* @internal param \The $integer page uid for which to seek back to the page tree root.
*/
protected function getOverlayedRootLine($uid, $languageid) {
$cacheManager = CacheManager::getInstance();
$cacheData = $cacheManager->get('overlayedRootline');
$isCacheEnabled = CacheManager::isCacheEnabled();
if (!$isCacheEnabled || !isset($cacheData[$uid][$languageid])) {
$uid = (int) $uid;
// Initialize:
$selFields = GeneralUtility::uniqueList('pid,uid,t3ver_oid,t3ver_wsid,t3ver_state,title,alias,nav_title,media,layout,hidden,starttime,endtime,fe_group,extendToSubpages,doktype,TSconfig,is_siteroot,mount_pid,mount_pid_ol,fe_login_mode,' . $GLOBALS['TYPO3_CONF_VARS']['FE']['addRootLineFields']);
$loopCheck = 0;
$theRowArray = Array();
while ($uid !== 0 && $loopCheck < 20) { // Max 20 levels in the page tree.
$row = BackendUtility::getRecordWSOL('pages', $uid, $selFields, ' AND pages.doktype!=255');
if (!$row) {
// broken rootline
return [];
}
BackendUtility::fixVersioningPid('pages', $row);
if (is_array($row)) {
// Mount Point page types are allowed ONLY a) if they are the outermost record in rootline and b) if the overlay flag is not set:
$uid = $row['pid']; // Next uid
}
// Add row to rootline with language overlaid:
$langvisHook = $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_page.php']['getPageOverlay']['languagevisility'];
unset($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_page.php']['getPageOverlay']['languagevisility']);
$theRowArray[] = BackendUtility::getRecordLocalization('pages', $uid, $languageid);
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_page.php']['getPageOverlay']['languagevisility'] = $langvisHook;
$loopCheck++;
}
// Create output array (with reversed order of numeric keys):
$output = Array();
$c = count($theRowArray);
foreach ($theRowArray as $key => $val) {
$c--;
$output[$c] = $val;
}
$cacheData[$uid][$languageid] = $output;
$cacheManager->set('overlayedRootline', $cacheData);
}
return $cacheData[$uid][$languageid];
}
/**
* Gets instance depending on TYPO3 version
*
* @param string $name name of the class
* @param array $row row that is used to initialaze element instance
* @param array $row row that is used to initialize element instance
* @return Object
*/
private function getElementInstance($name, $row) {
......
<?php
namespace TYPO3\Languagevisibility\Element;
/***************************************************************
* Copyright notice
*
* (c) 2007 AOE media (dev@aoemedia.de)
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
***************************************************************/
use TYPO3\CMS\Backend\Utility\BackendUtility;
use TYPO3\CMS\Backend\Utility\IconUtility;
use TYPO3\CMS\Core\Core\Environment;
use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\Imaging\Icon;
use TYPO3\CMS\Core\Imaging\IconFactory;
use TYPO3\CMS\Core\Site\SiteFinder;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Utility\LocalizationUtility;
/**
*
* @author Daniel Poetzinger <poetzinger@aoemedia.de>
* @coauthor Tolleiv Nietsch <nietsch@aoemedia.de>
* @coauthor Timo Schmidt <schmidt@aoemedia.de>
*/
class Language {
/**
* @var array
*/
private $row;
/**
* @var array
*/
protected static $flagCache;
/**
* Holds the exploded fallBackOrderArray
*
* @var array
*/
protected $defaultFallBackOrderArray;
/**
* Holds the exploded elementFallBackOrderArray
*
* @var array
*/
protected $elementFallBackOrderArray;
/**
* @var string holds the lg_iso_2 isocode
*/
protected $lg_iso_2;
/**
* @param array $row
*/
public function setData(array $row) {
$this->row = $row;
}
/**
* Returns the fallback order of this language as array.
*
* @param Element $contextElement
* @return array
*/
public function getFallbackOrder(Element $contextElement): array {
// determine and explode only once
if (!isset($this->defaultFallBackOrderArray)) {
$siteFinder = GeneralUtility::makeInstance(SiteFinder::class);
if ($contextElement->getTable() === 'pages') {
$pid = $contextElement->getUid();
} else {
$pid = $contextElement->getPid();
}
try {
$site = $siteFinder->getSiteByPageId($pid);
} catch (\Exception $e) {
return [];
}
$siteLanguage = $site->getLanguageById($this->getUid());
$fallbackLanguageIds = $siteLanguage->getFallbackLanguageIds();
$this->defaultFallBackOrderArray = $fallbackLanguageIds;
}
return $this->triggerFallbackHooks('getFallbackOrder', $this->defaultFallBackOrderArray, $contextElement);
}
/**
* Returns the fallback order for this language for elements
*
* @param Element $contextElement
* @return array
*/
public function getFallbackOrderElement(Element $contextElement): array {
// determine and explode only once
if (!isset($this->elementFallBackOrderArray)) {
$this->elementFallBackOrderArray = $this->getFallbackOrder($contextElement);
}
return $this->triggerFallbackHooks(
'getFallbackOrderElement', $this->elementFallBackOrderArray, $contextElement
);
}
/**
*
* @param string $key
* @param array $fallbackorder
* @param Element $contextElement
* @return array
*/
protected function triggerFallbackHooks($key, $fallbackorder, Element $contextElement): array {
$result = [
'priority' => 10,
'fallbackorder' => $fallbackorder,
];
$fallback = $result;
if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['languagevisibility']['$key'])) {
foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['languagevisibility'][$key] as $classRef) {
$hookObj = GeneralUtility::makeInstance($classRef);
if (method_exists($hookObj, $key)) {
$result = $hookObj->$key($this, $fallback, $contextElement);
if ($result['priority'] > $fallback['priority']) {
$fallback = $result;
}
}
}
}
return $fallback['fallbackorder'];
}
/**
* Method to read the defaultVisibility setting of pages.
*
* @param Element $contextElement
* @return string
*/
public function getDefaultVisibilityForPage(Element $contextElement): string {
return $this->triggerDefaultVisibilityHooks(
'getDefaultVisibilityForPage', $this->row['tx_languagevisibility_defaultvisibility'] ?? '', $contextElement
);
}
/**
* Method to read the defaultVisibility for elements
*
* @param Element $contextElement
* @return string
*/
public function getDefaultVisibilityForElement(Element $contextElement): string {
return $this->triggerDefaultVisibilityHooks(
'getDefaultVisibilityForElement', $this->row['tx_languagevisibility_defaultvisibilityel'] ?? '',
$contextElement
);
}
/**
* @param string $key
* @param string $visibilityDefault
* @param Element $contextElement
* @return string
*/
protected function triggerDefaultVisibilityHooks(string $key, string $visibilityDefault, Element $contextElement
): string {
$result = [
'priority' => 10,
'visibility' => $visibilityDefault,
];
$visibility = $result;
if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['languagevisibility'][$key])) {
foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['languagevisibility'][$key] as $classRef) {
$hookObj = GeneralUtility::makeInstance($classRef);
if (method_exists($hookObj, $key)) {
$result = $hookObj->$key($this, $visibility, $contextElement);
if ($result['priority'] > $visibility['priority']) {
$visibility = $result;
}
}
}
}
return $visibility['visibility'];
}
/**
* Method to get the primary key of the language record.
*
* @return int
*/
public function getUid(): int {
return (int) $this->row['uid'];
}
/**
* Method to determine the lg_iso_2 code from the static languages record.
*
* @return string
*/
public function getIsoCode(): string {
if (!isset($this->lg_iso_2)) {
// Finding the ISO code:
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
->getQueryBuilderForTable('static_languages');
$row = $queryBuilder->select('lg_iso_2')
->from('static_languages')
->where(
$queryBuilder->expr()->eq(
'uid', $queryBuilder->createNamedParameter($this->row['static_lang_isocode'], \PDO::PARAM_INT)
)
)
->execute()->fetch();
$this->lg_iso_2 = $row['lg_iso_2'];
}
return $this->lg_iso_2;
}
/**
* Returns the title of the language.
*
* @param int $pidForDefault
* @return string
*/
public function getTitle(int $pidForDefault = 0): string {
if ($this->getUid() === 0) {
if ($pidForDefault === 0) {
$pidForDefault = $this->_guessCurrentPid();
}
$sharedTSconfig['properties'] = BackendUtility::getPagesTSconfig($pidForDefault)['mod.']['SHARED.'] ?? [];
if ($sharedTSconfig['properties']['defaultLanguageLabel'] !== '' &&
$sharedTSconfig['properties']['defaultLanguageLabel'] !== NULL
) {
if (GeneralUtility::isFirstPartOfStr($sharedTSconfig['properties']['defaultLanguageLabel'], 'LLL:')) {
return (string) LocalizationUtility::translate(
$sharedTSconfig['properties']['defaultLanguageLabel']
);
}
return (string) $sharedTSconfig['properties']['defaultLanguageLabel'];
}
return 'Default';
}
return (string) $this->row['title'];
}
/**
* @return int
*/
protected function _guessCurrentPid(): int {
return (int) GeneralUtility::_GP('id');
}
/**
* @param int $pidForDefault Optional the pid of the page. This can be used to get the correct flag for default language (which is set in tsconfig)
*
* @return string
*/
public function getFlagImg(int $pidForDefault = 0): string {
$cache_key = 'pid:' . $pidForDefault . 'uid:' . $this->getUid();
if (!isset(self::$flagCache[$cache_key])) {
/** @var IconFactory $iconFactory */
$iconFactory = GeneralUtility::makeInstance(IconFactory::class);
self::$flagCache[$cache_key] = $iconFactory->getIcon(
$this->getFlagName($pidForDefault), Icon::SIZE_SMALL
)->render();
}
return self::$flagCache[$cache_key];
}
/**
* @param int $pidForDefault
* @return string
*/
protected function getFlagName(int $pidForDefault = 0): string {
if ($this->getUid() === 0) {
$sharedTSconfig['properties'] = BackendUtility::getPagesTSconfig($pidForDefault)['mod.']['SHARED.'] ?? [];
$flag = $sharedTSconfig['properties']['defaultLanguage.']['flag'];
} else {
$flag = $this->row['flag'];
}
return 'flags-' . $flag;
}
/**
* @param int $pidForDefault Optional the pid of the page. This can be used to get the correct flagpath for default language (which is set in tsconfig)
* @param string $BACK_PATH
* @return string|null
*/
public function getFlagImgPath(int $pidForDefault = 0, string $BACK_PATH = ''): ?string {
$flagAbsPath = GeneralUtility::getFileAbsFileName(
$GLOBALS['TCA']['sys_language']['columns']['flag']['config']['fileFolder']
);
$flagIconPath = $BACK_PATH . '../' . substr($flagAbsPath, strlen(Environment::getPublicPath() . '/'));
if ($this->getUid() === 0) {
if ($pidForDefault === 0) {
$pidForDefault = $this->_guessCurrentPid();
}
$sharedTSconfig['properties'] = BackendUtility::getPagesTSconfig($pidForDefault)['mod.']['SHARED.'] ?? [];
$path = $sharedTSconfig['properties']['defaultLanguageFlag'] !== '' && @is_file(
$flagAbsPath . $sharedTSconfig['properties']['defaultLanguageFlag']
) ? $flagIconPath . $sharedTSconfig['properties']['defaultLanguageFlag'] : NULL;
} else {
$path = $flagIconPath . $this->row['flag'];
}
return $path;
}
/**
* checks if the given languageid is part of the fallback of this language
* (used for permission options in the backend)
*
* @param int uid
* @param Element $el
* @return bool
*/
public function isLanguageUidInFallbackOrder(int $uid, Element $el): bool {
$fallbacks = $this->getFallbackOrder($el);
return in_array($uid, $fallbacks, TRUE);
}
}
......@@ -12,7 +12,7 @@ class PageElement extends RecordElement {
/**
* Returns which field in the language should be used to read the default visibility
*
*@return string (blank=default / page=page)
* @return string (blank=default / page=page)
**/
public function getFieldToUseForDefaultVisibility(): string {
return 'page';
......
......@@ -25,23 +25,21 @@ namespace TYPO3\Languagevisibility\Element;
* This copyright notice MUST APPEAR in all copies of the script!
***************************************************************/
use TYPO3\CMS\Core\Context\Exception\AspectNotFoundException;
use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction;
use TYPO3\CMS\Core\Utility\GeneralUtility;
/**
* Class RecordElement
*
* @author Daniel Poetzinger <poetzinger@aoemedia.de>
* @author Daniel Poetzinger <poetzinger@aoemedia.de>
* @coauthor Tolleiv Nietsch <nietsch@aoemedia.de>
* @coauthor Timo Schmidt <schmidt@aoemedia.de>
*/
class RecordElement extends Element {
/**
* Returns a formal description of the record element.
*
* (non-PHPdoc)
* @see classes/tx_languagevisibility_element#getElementDescription()
* @return string
*/
public function getElementDescription(): string {
......@@ -56,11 +54,11 @@ class RecordElement extends Element {
* @see classes/tx_languagevisibility_element#getOverLayRecordForCertainLanguageImplementation($languageId)
* @param $languageId
* @return array|mixed
* @throws \TYPO3\CMS\Core\Context\Exception\AspectNotFoundException
* @throws AspectNotFoundException
*/
protected function getOverLayRecordForCertainLanguageImplementation($languageId): array {
if (empty($this->table)) {
return array();
return [];
}
$ctrl = $GLOBALS['TCA'][$this->table]['ctrl'];
......@@ -72,13 +70,20 @@ class RecordElement extends Element {
->from($this->table)
->where(
$queryBuilder->expr()->andX(
$queryBuilder->expr()->eq('pid', $queryBuilder->createNamedParameter($this->getPid(), \PDO::PARAM_INT)),
$queryBuilder->expr()->eq($ctrl['languageField'], $queryBuilder->createNamedParameter($languageId, \PDO::PARAM_INT))
$queryBuilder->expr()->eq(
'pid', $queryBuilder->createNamedParameter($this->getPid(), \PDO::PARAM_INT)
),
$queryBuilder->expr()->eq(
$ctrl['languageField'], $queryBuilder->createNamedParameter($languageId, \PDO::PARAM_INT)
)
)
);
if ($languageId > 0) {
$queryBuilder->andWhere(
$queryBuilder->expr()->eq($ctrl['transOrigPointerField'], $queryBuilder->createNamedParameter($this->getUid(), \PDO::PARAM_INT))
$queryBuilder->expr()->eq(
$ctrl['transOrigPointerField'],
$queryBuilder->createNamedParameter($this->getUid(), \PDO::PARAM_INT)
)
);
} else {
$queryBuilder->andWhere(
......@@ -95,16 +100,4 @@ class RecordElement extends Element {
return $olrow;
}
/**
* Returns the fallback order of an record element.
*
* (non-PHPdoc)
* @see classes/tx_languagevisibility_element#getFallbackOrder($language)
* @param Language $language
* @return array
*/
public function getFallbackOrder(Language $language): array {
return $language->getFallbackOrderElement($this);
}
}
......@@ -24,6 +24,7 @@ namespace TYPO3\Languagevisibility\Element;
*
* This copyright notice MUST APPEAR in all copies of the script!
***************************************************************/
/**
* A visibility object represents the visibility of an element.
* It contains a visibilityString(-,yes,no,f,t) and a visibility
......@@ -42,7 +43,7 @@ class Visibility {
protected $visibilityString = '';
/**
* Holds a description for the visiblitiy.
* Holds a description for the visibility.
*
* @var string
*/
......
......@@ -27,7 +27,7 @@ namespace TYPO3\Languagevisibility\Exception;
/**
*
* @author Daniel Poetzinger <poetzinger@aoemedia.de>
* @author Daniel Poetzinger <poetzinger@aoemedia.de>
* @coauthor Tolleiv Nietsch <nietsch@aoemedia.de>
* @coauthor Timo Schmidt <schmidt@aoemedia.de>
*/
......
<?php
namespace TYPO3\Languagevisibility\Exception;
/***************************************************************
* Copyright notice
*
* (c) 2020 sgalinski Internet Services (https://www.sgalinski.de)
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
***************************************************************/
/**
*
* @author Fabio Stegmeyer <fabio.stegmeyer@sgalinski.de>
*/
class TableNotSupportedException extends \Exception {
}
......@@ -25,35 +25,39 @@ namespace TYPO3\Languagevisibility\Hook;
* This copyright notice MUST APPEAR in all copies of the script!
***************************************************************/#
use Exception;
use TYPO3\CMS\Backend\Controller\EditDocumentController;
use TYPO3\CMS\Backend\Form\FormDataProvider\DatabaseUserPermissionCheck;
use TYPO3\CMS\Backend\Utility\BackendUtility;
use TYPO3\Languagevisibility\Service\BackendServices;
/**
* Class/Function which manipulates the item-array for the listing (see piFlexform).
*
* @author Fabrizio Brance
* @author Timo Schmidt
* @author Fabrizio Brance
* @author Timo Schmidt
*/
class AlternativeDocumentHook {
/**
* @param array $params
* @param DatabaseUserPermissionCheck $permissionCheck
* @param EditDocumentController $ref
* @param EditDocumentController|null $ref
* @return bool
* @throws Exception
*/
public function makeEditForm_accessCheck(
array $params, DatabaseUserPermissionCheck $permissionCheck, EditDocumentController $ref = NULL
) {
): bool {
if ($params['hasAccess']) {
return TRUE;
}
// user wants to edit/create page record but has no access to default language
// user wants to edit/create page record but has no access to default language
$hasAccess = FALSE;
if ($params['table'] === 'pages' && !$GLOBALS['BE_USER']->checkLanguageAccess(0)) {
if (BackendServices::hasUserAccessToPageRecord((int) $params['uid'], $params['cmd'])) {
$row = BackendUtility::getRecord($params['table'], $params['uid']);
if ($row !== NULL && BackendServices::hasUserAccessToPageRecord($row, $params['cmd'])) {
$hasAccess = TRUE;
}
}
......
......@@ -25,15 +25,16 @@ namespace TYPO3\Languagevisibility\Hook;
* This copyright notice MUST APPEAR in all copies of the script!
***************************************************************/
use Exception;
use TYPO3\CMS\Core\Context\Context;
use TYPO3\CMS\Core\Context\Exception\AspectNotFoundException;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Frontend\ContentObject\Menu\AbstractMenuContentObject;
use TYPO3\CMS\Frontend\ContentObject\Menu\AbstractMenuFilterPagesHookInterface;
use TYPO3\Languagevisibility\Service\FrontendServices;
use TYPO3\Languagevisibility\Service\VisibilityService;
/**
* Class tx_languagevisibility_hooks_tslib_menu
* Class MenuHook
*
* @package AOE\Languagevisibility\Hooks
*/
......@@ -47,12 +48,17 @@ class MenuHook implements AbstractMenuFilterPagesHookInterface {
* @param $spacer
* @param AbstractMenuContentObject $obj
* @return bool
* @throws AspectNotFoundException
* @throws Exception
*/
public function tslib_menu_filterMenuPagesHook(array &$data, array $banUidArray, $spacer, AbstractMenuContentObject $obj) {
public function tslib_menu_filterMenuPagesHook(
array &$data, array $banUidArray, $spacer, AbstractMenuContentObject $obj
): bool {
if (!FrontendServices::checkVisiblityForElement(
$data,
'pages',
GeneralUtility::makeInstance(Context::class)->getPropertyFromAspect('language', 'id'))
GeneralUtility::makeInstance(Context::class)->getPropertyFromAspect('language', 'id')
)
) {
return FALSE;
}
......@@ -68,8 +74,9 @@ class MenuHook implements AbstractMenuFilterPagesHookInterface {
* @param bool $spacer
* @param AbstractMenuContentObject $obj
* @return bool
* @throws AspectNotFoundException
*/
public function processFilter(array &$data, array $banUidArray, $spacer, AbstractMenuContentObject $obj) {
public function processFilter(array &$data, array $banUidArray, $spacer, AbstractMenuContentObject $obj): bool {
return $this->tslib_menu_filterMenuPagesHook($data, $banUidArray, $spacer, $obj);
}
}
......@@ -25,7 +25,11 @@ namespace TYPO3\Languagevisibility\Hook;
* This copyright notice MUST APPEAR in all copies of the script!
***************************************************************/
use Exception;
use ReflectionException;
use TYPO3\CMS\Core\Cache\Exception\NoSuchCacheException;
use TYPO3\CMS\Core\Context\Context;
use TYPO3\CMS\Core\Context\Exception\AspectNotFoundException;
use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction;
use TYPO3\CMS\Core\Utility\GeneralUtility;
......@@ -33,10 +37,11 @@ use TYPO3\CMS\Frontend\Page\PageRepository;
use TYPO3\CMS\Frontend\Page\PageRepositoryGetPageOverlayHookInterface;
use TYPO3\CMS\Frontend\Page\PageRepositoryGetRecordOverlayHookInterface;
use TYPO3\Languagevisibility\Exception\InvalidRowException;
use TYPO3\Languagevisibility\Exception\TableNotSupportedException;
use TYPO3\Languagevisibility\Service\FrontendServices;
/**
* Class tx_languagevisibility_hooks_t3lib_page
* Class PageHook
*
* @package Aoe\Languagevisibility\Hooks
*/
......@@ -49,18 +54,18 @@ class PageHook implements PageRepositoryGetPageOverlayHookInterface, PageReposit
* 2) $lUid == null
* is relevant if we did the overlay ourselfs and the processing within getPageOverlay function is not relevant anymore
* 3) $lUid changed
* is relevant if we just changed the target-languge but require getPageOverlay to proceed with the overlay-chrunching
* is relevant if we just changed the target-languge but require getPageOverlay to proceed with the overlay-crunching
* 4) $lUid changed to 0 (which may be the case for forced fallbacks to default). Please check Core Setting hideIfNotTranslated in this case to be sure the page can be shown in this case
*
* @param mixed $pageInput
* @param integer $lUid Passed ad reference!
* @param PageRepository $parent
* @return void
* @throws \ReflectionException
* @throws \TYPO3\CMS\Core\Cache\Exception\NoSuchCacheException
* @throws \TYPO3\CMS\Core\Context\Exception\AspectNotFoundException
* @throws NoSuchCacheException
* @throws AspectNotFoundException|TableNotSupportedException
* @throws Exception
*/
public function getPageOverlay_preProcess(&$pageInput, &$lUid, PageRepository $parent) {
public function getPageOverlay_preProcess(&$pageInput, &$lUid, PageRepository $parent): void {
if (is_int($pageInput)) {
$pageId = $pageInput;
} elseif (is_array($pageInput) && isset($pageInput['uid'])) {
......@@ -93,7 +98,7 @@ class PageHook implements PageRepositoryGetPageOverlayHookInterface, PageReposit
}
// call service to know if element is visible and which overlay language to use
$overlayLanguage = FrontendServices::getOverlayLanguageIdForElementRecord($row, 'pages', $lUid);
$overlayLanguage = FrontendServices::getOverlayLanguageIdForElementRecord($row, 'pages', $languageUid);
if ($overlayLanguage === FALSE) {
if ($pageInputIsArray) {
$pageInput['_NOTVISIBLE'] = TRUE;
......@@ -106,25 +111,25 @@ class PageHook implements PageRepositoryGetPageOverlayHookInterface, PageReposit
/**
* The flow in t3lib_page is:
* - call preProcess
* - if uid and pid > then overlay if langauge != 0
* - if uid and pid > then overlay if language != 0
* - after this postProcess is called - which only corrects the overlay row for certain elements
*
* @param string $table
* @param array $row
* @param integer $sys_language_content
* @param integer|bool $sys_language_content
* @param string $OLmode
* @param PageRepository $parent
* @return void
*/
public function getRecordOverlay_preProcess($table, &$row, &$sys_language_content, $OLmode, PageRepository $parent
) {
if (!FrontendServices::isSupportedTable($table)
|| (!is_array($row))
|| (!isset($row['uid']))) {
): void {
if ((!is_array($row))
|| (!isset($row['uid']))
|| !FrontendServices::isSupportedTable($table)) {
return;
}
// Set the uid to the original record uid. Solves an error, where a content elment within a content element is
// Set the uid to the original record uid. Solves an error, where a content element within a content element is
// not rendered.
if (
$table === 'tt_content' &&
......@@ -141,7 +146,7 @@ class PageHook implements PageRepositoryGetPageOverlayHookInterface, PageReposit
$row['uid'] = 0;
$row['pid'] = 0;
return;
} catch (\Exception $e) {
} catch (Exception $e) {
return;
}
......@@ -149,8 +154,10 @@ class PageHook implements PageRepositoryGetPageOverlayHookInterface, PageReposit
$row['uid'] = 0;
$row['pid'] = 0;
return;
} elseif (!$element->isMonolithicTranslated()) {
// for monolytic elements the tx_languagevisibility_feservices::getOverlayLanguageIdForElement return 0 to "tell" us that no overlay is required
}
if (!$element->isMonolithicTranslated()) {
// for monolithic elements the FrontendServices::getOverlayLanguageIdForElement return 0 to "tell" us that no overlay is required
// but since the TYPO3 Core interprets a language with id 0 to not return anything we need to leave the $sys_language_content untouched for MonolithicTranslated elements
$sys_language_content = $overlayLanguage;
}
......@@ -159,30 +166,31 @@ class PageHook implements PageRepositoryGetPageOverlayHookInterface, PageReposit
/**
*
* @param string $table
* @param array $row
* @param array|bool $row
* @param integer $sys_language_content
* @param string $OLmode
* @param PageRepository $parent
* @return void
*/
public function getRecordOverlay_postProcess($table, &$row, &$sys_language_content, $OLmode, PageRepository $parent
) {
): void {
if (is_array($row) && $row['uid'] === 0 && $row['pid'] === 0) {
$row = FALSE;
return;
}
if (!FrontendServices::isSupportedTable($table)
|| (!is_array($row))
if ((!is_array($row))
|| (!isset($row['uid']))
|| ($sys_language_content == 0)) {
|| ($sys_language_content === 0)
|| !FrontendServices::isSupportedTable($table)) {
return;
}
try {
$element = FrontendServices::getElement($row, $table);
// todo: remove?
$overlayLanguage = FrontendServices::getOverlayLanguageIdForElement($element, $sys_language_content);
} catch (\Exception $e) {
} catch (Exception $e) {
return;
}
}
......@@ -194,12 +202,12 @@ class PageHook implements PageRepositoryGetPageOverlayHookInterface, PageReposit
* @param $structurePath
* @param $pObj
*/
public function _callback_checkXMLFieldsForFallback($dsArr, $dataValue, $PA, $structurePath, $pObj) {
if ($dsArr['TCEforms']['l10n_mode'] == 'exclude') {
public function _callback_checkXMLFieldsForFallback($dsArr, $dataValue, $PA, $structurePath, $pObj): void {
if ($dsArr['TCEforms']['l10n_mode'] === 'exclude') {
$pObj->setArrayValueByPath($structurePath, $this->_callbackVar_overlayXML, $dataValue);
} elseif ($dataValue != '' && $dsArr['TCEforms']['l10n_mode'] == 'mergeIfNotBlank') {
} elseif ($dataValue !== '' && $dsArr['TCEforms']['l10n_mode'] === 'mergeIfNotBlank') {
$overlayValue = $pObj->getArrayValueByPath($structurePath, $this->_callbackVar_overlayXML);
if ($overlayValue == '') {
if ($overlayValue === '') {
$pObj->setArrayValueByPath($structurePath, $this->_callbackVar_overlayXML, $dataValue);
}
}
......
......@@ -26,22 +26,28 @@ namespace TYPO3\Languagevisibility\Hook;
* This copyright notice MUST APPEAR in all copies of the script!
***************************************************************/
use Doctrine\DBAL\DBALException;
use Exception;
use InvalidArgumentException;
use TYPO3\CMS\Backend\Utility\BackendUtility;
use TYPO3\CMS\Core\Cache\Exception\NoSuchCacheException;
use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction;
use TYPO3\CMS\Core\DataHandling\DataHandler;
use TYPO3\CMS\Core\Site\SiteFinder;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\Languagevisibility\Element\ElementFactory;
use TYPO3\Languagevisibility\Manager\CacheManager;
use TYPO3\Languagevisibility\Repository\LanguageRepository;
use TYPO3\Languagevisibility\Repository\VisibilityFlagRepository;
use TYPO3\Languagevisibility\Service\BackendServices;
use TYPO3\Languagevisibility\Service\VisibilityService;
/**
* Class TceMainHook
*
* @coauthor Fabio Stegmeyer <fabio.stegmeyer@sgalinski.de>
*/
class TceMainHook {
/**
* Hook method after table data are modified.
*
......@@ -53,56 +59,75 @@ class TceMainHook {
* @param mixed $pasteUpdate
* @param mixed $pasteDatamap
* @return void
* @throws DBALException
*/
public function processCmdmap_postProcess(
$command, $table, $identity, $value, $dataHandler, $pasteUpdate, $pasteDatamap
) {
): void {
if ($command === 'copy' && $table === 'pages') {
$originalPageId = (int) $identity;
if ($originalPageId <= 0) {
return;
}
if ($table === 'pages') {
if ($command === 'copy') {
$originalPageId = (int) $identity;
if ($originalPageId <= 0) {
return;
}
if (!isset($dataHandler->copyMappingArray['pages'])) {
return;
}
if (!isset($dataHandler->copyMappingArray['pages'])) {
return;
}
$newPageId = (int) $dataHandler->copyMappingArray['pages'][$originalPageId];
if ($newPageId <= 0) {
return;
$newPageId = (int) $dataHandler->copyMappingArray['pages'][$originalPageId];
if ($newPageId <= 0) {
return;
}
$this->copyLanguageVisibilityFlagsFromParentPage($newPageId);
} elseif ($command === 'move') {
$this->copyLanguageVisibilityFlagsFromParentPage($identity);
}
} else {
if ($command === 'copy' && in_array(
$table, VisibilityService::getSupportedTables(), TRUE
)) {
$this->copyLanguageVisibilityFlagsFromParentPage($newPageId);
} elseif ($command === 'move') {
$this->copyLanguageVisibilityFlagsFromParentPage($identity);
}
$oldId = $identity;
$newId = $dataHandler->copyMappingArray[$table][$identity];
if ($command === 'copy' && $table !== 'pages' && in_array(
$table, VisibilityService::getSupportedTables(), TRUE
)) {
// get the pid of the new record
$newRecord = BackendUtility::getRecord($table, $newId);
if ($newRecord !== NULL) {
$newPid = $newRecord['pid'];
} else {
return;
}
$oldId = $identity;
$newId = $dataHandler->copyMappingArray[$table][$identity];
$visibilityFlagRepository = GeneralUtility::makeInstance(VisibilityFlagRepository::class);
$visibilityFlagRepository->flushFlagCache();
$languageRep = GeneralUtility::makeInstance(LanguageRepository::class);
$visibilityFlagRepository = GeneralUtility::makeInstance(VisibilityFlagRepository::class);
$availableLanguages = $languageRep->getLanguages();
$siteFinder = GeneralUtility::makeInstance(SiteFinder::class);
try {
$site = $siteFinder->getSiteByPageId($newPid);
} catch (Exception $e) {
return;
}
$visibilityFlags = [];
$availableLanguages = $site->getAllLanguages();
$visibilityFlags = [];
foreach ($availableLanguages as $language) {
$lid = $language->getUid();
foreach ($availableLanguages as $language) {
$lid = $language->getLanguageId();
$visibilityFlag = $visibilityFlagRepository->getVisibilityFlag($table, $oldId, $lid);
$visibilityFlag = $visibilityFlagRepository->getVisibilityFlag($table, $oldId, $lid);
if ($visibilityFlag !== FALSE && $visibilityFlag !== NULL) {
$visibilityFlags[$lid] = $visibilityFlag['flag'];
if ($visibilityFlag !== FALSE && $visibilityFlag !== NULL) {
$visibilityFlags[$lid] = $visibilityFlag['flag'];
}
}
}
foreach ($visibilityFlags as $lid => $flag) {
$visibilityFlagRepository->setVisibilityFlag($flag, $table, $newId, $lid);
foreach ($visibilityFlags as $lid => $flag) {
$visibilityFlagRepository->setVisibilityFlag($flag, $table, $newId, $lid);
}
}
}
}
......@@ -118,21 +143,37 @@ class TceMainHook {
* @param $resolvedPid
* @param $recordWasMoved
* @param $dataHandler
* @throws DBALException
*/
public function moveRecord($table, $uid, $destPid, $propArr, $moveRec, $resolvedPid, $recordWasMoved, $dataHandler
) {
): void {
if ($table !== 'pages' && in_array(
$table, VisibilityService::getSupportedTables(), TRUE
)) {
$languageRep = GeneralUtility::makeInstance(LanguageRepository::class);
$visibilityFlagRepository = GeneralUtility::makeInstance(VisibilityFlagRepository::class);
$availableLanguages = $languageRep->getLanguages();
$siteFinder = GeneralUtility::makeInstance(SiteFinder::class);
if ($table === 'pages') {
$pid = $uid;
} else {
$pid = $resolvedPid;
}
try {
$site = $siteFinder->getSiteByPageId($pid);
} catch (Exception $e) {
return;
}
$availableLanguages = $site->getAllLanguages();
foreach ($availableLanguages as $language) {
$lid = $language->getUid();
$lid = $language->getLanguageId();
$visibilityFlagRepository->flushFlagCache();
$visibilityFlag = $visibilityFlagRepository->getVisibilityFlag($table, $uid, $lid);
if ($visibilityFlag !== FALSE && $visibilityFlag !== NULL) {
......@@ -148,8 +189,9 @@ class TceMainHook {
* Copy languagevisibility settings from parent page.
*
* @param $pageId
* @throws DBALException
*/
protected function copyLanguageVisibilityFlagsFromParentPage($pageId) {
protected function copyLanguageVisibilityFlagsFromParentPage($pageId): void {
$page = BackendUtility::getRecord('pages', $pageId);
if (!$page
......@@ -165,19 +207,28 @@ class TceMainHook {
$parentPageUid = $parentPage['uid'];
$languageRep = GeneralUtility::makeInstance(LanguageRepository::class);
$visibilityFlagRepository = GeneralUtility::makeInstance(VisibilityFlagRepository::class);
$availableLanguages = $languageRep->getLanguages();
$siteFinder = GeneralUtility::makeInstance(SiteFinder::class);
try {
$rootline = BackendUtility::BEgetRootLine($pageId);
$site = $siteFinder->getSiteByPageId($pageId, $rootline);
} catch (Exception $e) {
return;
}
$availableLanguages = $site->getAllLanguages();
// clear the existing/automatically copied flags on the copied/inserted/moved page
$visibilityFlagRepository = GeneralUtility::makeInstance(VisibilityFlagRepository::class);
$visibilityFlagRepository->removeFlagsByTableAndPid('pages', $pageId);
$visibilityFlagRepository->flushFlagCache();
if ($availableLanguages && count($availableLanguages) > 0) {
// collect the flags of the parent page and its overlay
foreach ($availableLanguages as $language) {
$lid = $language->getUid();
$lid = $language->getLanguageId();
// get visibility from parent page
$flagRow = $visibilityFlagRepository->getVisibilityFlag('pages', $parentPageUid, $lid);
......@@ -218,11 +269,11 @@ class TceMainHook {
* @param array $data
* @param integer $res (but only 0 and 1 is relevant so it's boolean technically)
* @param $tcemain
* @return integer
* @throws \Exception
* @return integer|NULL
* @throws Exception
* @internal param object $this
*/
public function checkRecordUpdateAccess($table, $id, $data, $res, $tcemain) {
public function checkRecordUpdateAccess($table, $id, $data, $res, $tcemain): ?int {
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($table);
$queryBuilder->getRestrictions()->removeAll()->add(GeneralUtility::makeInstance(DeletedRestriction::class));
$row = $queryBuilder->select('*')
......@@ -254,12 +305,13 @@ class TceMainHook {
* @param string $table
* @param int $id
* @param DataHandler $dataHandler
* @throws \InvalidArgumentException
* @throws \TYPO3\CMS\Core\Cache\Exception\NoSuchCacheException
* @throws InvalidArgumentException
* @throws NoSuchCacheException
* @throws DBALException
*/
public function processDatamap_preProcessFieldArray(
&$incomingFieldArray, $table, $id, DataHandler $dataHandler
) {
): void {
$data = $incomingFieldArray;
if (!is_array($data)) {
return;
......@@ -310,9 +362,6 @@ class TceMainHook {
// flush all caches
CacheManager::getInstance()->flushAllCaches();
GeneralUtility::makeInstance(VisibilityFlagRepository::class)
->deleteDefaultFlags();
// Flush TYPO3 Caching Framework caches
GeneralUtility::makeInstance(\TYPO3\CMS\Core\Cache\CacheManager::class)
->getCache('tx_languagevisibility')
......@@ -330,7 +379,7 @@ class TceMainHook {
* @param boolean $enableLogging
* @param DataHandler $dataHandler
* @return void
* @throws \InvalidArgumentException
* @throws InvalidArgumentException|DBALException
*/
protected function applyVisibilityFlagRecursive(
int $pageId, int $languageId, string $visibilityFlag, bool $enableLogging, DataHandler $dataHandler
......@@ -365,6 +414,7 @@ class TceMainHook {
$childPageUid = (int) $childPage['uid'];
$visibilityFlagRepository->flushFlagCache();
$existingVisibilityFlag = $visibilityFlagRepository->getVisibilityFlag(
'pages', $childPageUid, $languageId
);
......@@ -428,11 +478,11 @@ class TceMainHook {
* @param string $id
* @param array $fieldArray
* @param DataHandler $reference
* @throws \TYPO3\CMS\Core\Cache\Exception\NoSuchCacheException
* @throws NoSuchCacheException|DBALException
*/
public function processDatamap_afterDatabaseOperations(
$status, $table, $id, $fieldArray, &$reference
) {
): void {
if (in_array($table, VisibilityService::getSupportedTables(), TRUE)) {
......@@ -463,65 +513,12 @@ class TceMainHook {
}
/**
* Applies the given language data recursive.
* Removes the default flags after all database operations
*
* @param int $pageId
* @param array $languageData
* @param array $applyRecursive
* @param boolean $enableLogging
* @param DataHandler $dataHandler
* @return void
* @throws \InvalidArgumentException
* @param $dataHandler
*/
protected function applyLanguageDataRecursive(
$pageId, array $languageData, array $applyRecursive, $enableLogging, DataHandler $dataHandler
) {
$pageId = (int) $pageId;
if ($pageId <= 0 || count($languageData) <= 0 || count($applyRecursive) <= 0) {
return;
}
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('pages');
$queryBuilder->getRestrictions()->removeAll()->add(GeneralUtility::makeInstance(DeletedRestriction::class));
$childPages = $queryBuilder->select('*')
->from('pages')
->where(
$queryBuilder->expr()->eq('pid', $queryBuilder->createNamedParameter($pageId, \PDO::PARAM_INT))
)->execute()->fetchAll();
if (count($childPages) <= 0) {
return;
}
foreach ($childPages as $childPage) {
$childLanguageData = unserialize($childPage['tx_languagevisibility_visibility'], [FALSE]);
foreach ($applyRecursive as $languageId => $value) {
$childLanguageData[$languageId] = $languageData[$languageId];
}
$uid = (int) $childPage['uid'];
$serializeLanguageData = serialize($childLanguageData);
if ($enableLogging) {
// Update the field. Must be a string.
$childPage['tx_languagevisibility_visibility'] = $serializeLanguageData;
// Prepare the history for logging.
$dataHandler->compareFieldArrayWithCurrentAndUnset('pages', $uid, $childPage);
$dataHandler->updateDB(
'pages', $uid, ['tx_languagevisibility_visibility' => $serializeLanguageData]
);
} else {
$queryBuilder->update('pages')
->where(
$queryBuilder->expr()->eq('uid', $queryBuilder->createNamedParameter($uid, \PDO::PARAM_INT))
)
->set('tx_languagevisibility_visibility', $serializeLanguageData, TRUE)
->execute();
}
// Check recursive...
$this->applyLanguageDataRecursive($uid, $languageData, $applyRecursive, $enableLogging, $dataHandler);
}
public function processCmdmap_afterFinish($dataHandler): void {
GeneralUtility::makeInstance(VisibilityFlagRepository::class)
->deleteDefaultFlags();
}
}
......@@ -25,15 +25,16 @@ namespace TYPO3\Languagevisibility\Hook;
* This copyright notice MUST APPEAR in all copies of the script!
***************************************************************/
use Exception;
use TYPO3\Languagevisibility\Service\BackendServices;
/**
* Class UserAuthGroupHook
*
* @author Tolleiv