Skip to content

Instantly share code, notes, and snippets.

@eliashaeussler
Last active September 11, 2019 11:52
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save eliashaeussler/9905c89294470c7a8bdde4e450a3c928 to your computer and use it in GitHub Desktop.
Save eliashaeussler/9905c89294470c7a8bdde4e450a3c928 to your computer and use it in GitHub Desktop.
HideLanguageByRecordOverlayProcessor for TYPO3 CMS – made at @undkonsorten
<?php
declare(strict_types=1);
namespace Undkonsorten\BlockMenu\DataProcessing;
/*
* This file is part of the TYPO3 CMS extension "block_menu".
*
* It is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, either version 2
* of the License, or any later version.
*
* For the full copyright and license information, please read the
* LICENSE.txt file that was distributed with this source code.
*
* The TYPO3 project - inspiring people to share!
*/
use TYPO3\CMS\Core\Database\Connection;
use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\Exception\SiteNotFoundException;
use TYPO3\CMS\Core\SingletonInterface;
use TYPO3\CMS\Core\Site\SiteFinder;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Reflection\ObjectAccess;
use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
use TYPO3\CMS\Frontend\ContentObject\DataProcessorInterface;
/**
* DataProcessor for database record languages.
*
* Use this DataProcessor to hide languages in language menu if the current record on a single view is not available in
* the target language. It can be combined for example together with the MenuProcessor or LanguageMenuProcessor.
*
* Example:
*
* plugin.tx_myplugin = FLUIDTEMPLATE
* plugin.tx_myplugin {
* dataProcessing.10 = TYPO3\CMS\Frontend\DataProcessing\MenuProcessor
* dataProcessing.10 {
* special = language
* special.value = {$plugin.tx_myplugin.languageUids}
* as = menuItems
* addQueryString = 1
* addQueryString.method = GET
*
* dataProcessing.10 = Undkonsorten\BlockMenu\DataProcessing\HideLanguageByRecordOverlayProcessor
* dataProcessing.10 {
* newsSingleView {
* # Specify GET parameter of the records' UID
* parameter = tx_news_pi1[news]
* # Specify database table name where the records are stored
* tableName = tx_news_domain_model_news
* }
* }
* }
* }
*
* @author Felix Althaus <felix.althaus@undkonsorten.com>
* @author Elias Häußler <elias.haeussler@undkonsorten.com>
* @license GPL-2.0-or-later
*/
class HideLanguageByRecordOverlayProcessor implements DataProcessorInterface, SingletonInterface
{
/** @var string Regular expression for parameter normalization */
const PARAMETER_NORMALIZATION_REGEX = '/\\[(\\w+)\\]/';
/** @var string Replacement for paramter normalization */
const PARAMETER_NORMALIZATION_REPLACEMENT = '.${1}';
/**
* Override menu items returned from MenuProcessor with fields defined in TypoScript
*
* @param ContentObjectRenderer $cObj The data of the content element or page
* @param array $contentObjectConfiguration The configuration of Content Object
* @param array $processorConfiguration The configuration of this processor
* @param array $processedData Key/value store of processed data (e.g. to be passed to a Fluid View)
* @return array the processed data as key/value store
*/
public function process(
ContentObjectRenderer $cObj,
array $contentObjectConfiguration,
array $processorConfiguration,
array $processedData
)
{
$menuItem = $processedData;
$languageUid = (int)$menuItem['languageUid'];
// Get default language
try {
$site = GeneralUtility::makeInstance(SiteFinder::class)->getSiteByPageId($menuItem['data']['uid']);
$defaultLanguage = $site->getDefaultLanguage()->getLanguageId();
} catch (SiteNotFoundException $e) {
$defaultLanguage = 0;
}
// @todo Add support for standalone records in non-default language
if (!$menuItem['available'] || $languageUid === $defaultLanguage) {
return $menuItem;
}
$getVariables = GeneralUtility::_GET();
$matchingConfiguration = $this->getMatchingConfiguration($processorConfiguration, $getVariables);
if ($matchingConfiguration) {
if (!isset($matchingConfiguration['tableName'])) {
throw new \InvalidArgumentException('tableName must be set in configuration', 1533235484);
}
$uid = ObjectAccess::getPropertyPath($getVariables, static::normalizeParameterName($matchingConfiguration['parameter']));
$hasLocalization = $this->hasLocalizationForRecord($uid, $matchingConfiguration['tableName'], $languageUid);
if (!$hasLocalization) {
$menuItem['available'] = false;
}
}
return $menuItem;
}
/**
* Check whether a localized record exists in target language
*
* @param int $uid Uid of the original record
* @param string $tableName
* @param int $languageUid
* @return bool
*/
protected function hasLocalizationForRecord(int $uid, string $tableName, int $languageUid): bool
{
$tca = $GLOBALS['TCA'][$tableName];
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($tableName);
return (bool)$queryBuilder
->count('*')
->from($tableName)
->where(
$queryBuilder->expr()->eq($tca['ctrl']['transOrigPointerField'], $queryBuilder->createNamedParameter($uid, Connection::PARAM_INT)),
$queryBuilder->expr()->eq($tca['ctrl']['languageField'], $queryBuilder->createNamedParameter($languageUid, Connection::PARAM_INT))
)
->execute()
->fetchColumn();
}
/**
* Filter all configuration for any configuration matching existing GET variables
*
* @param array $processorConfiguration
* @param $getVariables
* @return mixed
*/
protected function getMatchingConfiguration(array $processorConfiguration, array $getVariables)
{
$matchingConfiguration = array_reduce($processorConfiguration, function ($carry, $config) use ($getVariables) {
$normalizedParameter = static::normalizeParameterName($config['parameter'] ?? '');
return $carry ?: (ObjectAccess::getPropertyPath($getVariables, $normalizedParameter) ? $config : null);
});
return $matchingConfiguration;
}
/**
* Convert parameter notation like tx_news_pi1[news] to dot notation for ObjectAccess (tx_news_pi1.news)
*
* @param string $parameter
* @return null|string|string[]
*/
protected static function normalizeParameterName(string $parameter)
{
return preg_replace(self::PARAMETER_NORMALIZATION_REGEX, self::PARAMETER_NORMALIZATION_REPLACEMENT, $parameter);
}
}
plugin.tx_myplugin = FLUIDTEMPLATE
plugin.tx_myplugin {
dataProcessing.10 = TYPO3\CMS\Frontend\DataProcessing\MenuProcessor
dataProcessing.10 {
special = language
special.value = {$plugin.tx_myplugin.languageUids}
as = menuItems
addQueryString = 1
addQueryString.method = GET
dataProcessing.10 = Undkonsorten\BlockMenu\DataProcessing\HideLanguageByRecordOverlayProcessor
dataProcessing.10 {
newsSingleView {
# Specify GET parameter of the records' UID
parameter = tx_news_pi1[news]
# Specify database table name where the records are stored
tableName = tx_news_domain_model_news
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment