361 lines
12 KiB
PHP
361 lines
12 KiB
PHP
<?php
|
|
|
|
namespace SGalinski\Lfeditor\Service;
|
|
|
|
/***************************************************************
|
|
* Copyright notice
|
|
*
|
|
* (c) 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 3 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 SGalinski\Lfeditor\Exceptions\LFException;
|
|
use SGalinski\Lfeditor\Utility\SgLib;
|
|
use SGalinski\Lfeditor\Utility\Typo3Lib;
|
|
use TYPO3\CMS\Core\Core\Environment;
|
|
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
|
|
|
/**
|
|
* FileOverrideService
|
|
*/
|
|
class FileOverrideService extends FileBaseXLFService {
|
|
/**
|
|
* Object which represents original (overridden) language file.
|
|
*
|
|
* @var \SGalinski\Lfeditor\Service\FileService
|
|
*/
|
|
protected $originalFileObject;
|
|
|
|
/**
|
|
* Initialises fileObject of override language file.
|
|
*
|
|
* @param FileService $originalFileObject
|
|
* @return void
|
|
*/
|
|
public function init($originalFileObject, $path, $metaFile) {
|
|
$typo3ExtRelativeFilePath = '';
|
|
$file = $this->session->getDataByKey('languageFileSelection');
|
|
$extensionKey = $this->session->getDataByKey('extkey');
|
|
if ($file !== '' && $extensionKey !== '') {
|
|
$typo3ExtRelativeFilePath = 'EXT:' . $this->cleanSessionExtKey($extensionKey) . '/' . $file;
|
|
}
|
|
if ($typo3ExtRelativeFilePath === '') {
|
|
try {
|
|
$typo3ExtRelativeFilePath = Typo3Lib::transTypo3File($originalFileObject->getAbsFile(), FALSE);
|
|
} catch (\Exception $e) {
|
|
$typo3ExtRelativeFilePath = '';
|
|
}
|
|
}
|
|
|
|
$pathSite = Environment::getPublicPath() . '/';
|
|
$overrideFileAbsolutePath = Typo3Lib::fixFilePath(
|
|
$pathSite . '/' .
|
|
($GLOBALS['TYPO3_CONF_VARS']['SYS']['locallangXMLOverride'][$typo3ExtRelativeFilePath][0] ?? '')
|
|
);
|
|
|
|
if (!is_file($overrideFileAbsolutePath)) {
|
|
$extRelativeFilePath = SgLib::trimPath('EXT:', $typo3ExtRelativeFilePath);
|
|
$extRelativeFilePath = substr($extRelativeFilePath, 0, strrpos($extRelativeFilePath, '.')) . '.xlf';
|
|
|
|
/** @var ConfigurationService $configurationService */
|
|
$configurationService = GeneralUtility::makeInstance(ConfigurationService::class);
|
|
$extConfig = $configurationService->getExtConfig();
|
|
$overrideFileAbsolutePath = $extConfig['pathOverrideFiles']
|
|
. $extRelativeFilePath;
|
|
}
|
|
|
|
$this->originalFileObject = $originalFileObject;
|
|
parent::init(basename($overrideFileAbsolutePath), dirname($overrideFileAbsolutePath), $metaFile);
|
|
}
|
|
|
|
/**
|
|
* Calls the parent function and convert all values from utf-8 to the original charset
|
|
*
|
|
* @return void
|
|
* @throws LFException raised if the parent read file method fails
|
|
*/
|
|
public function readFile() {
|
|
if (is_file($this->absFile)) {
|
|
parent::readFile();
|
|
}
|
|
|
|
$oldXMLFile = $this->getOlderPath($this->absFile);
|
|
if (is_file($oldXMLFile)) {
|
|
$xmlFile = GeneralUtility::makeInstance(FileBaseXMLService::class);
|
|
// i do think we are fine omitting metaFile
|
|
$xmlFile->init(basename($oldXMLFile), dirname($oldXMLFile), '');
|
|
$xmlFile->readFile();
|
|
$this->mergeFileObjectWidthOverrideLangData($xmlFile);
|
|
}
|
|
|
|
$this->originalFileObject->readFile();
|
|
$this->mergeOriginalWidthOverrideLangData();
|
|
}
|
|
|
|
/**
|
|
* when setting session key, we are using the folder, which has
|
|
* a) "-" as delimiter
|
|
* b) "cms-" as prefix for core extension
|
|
*
|
|
* @param string $extkey
|
|
* @return string
|
|
*/
|
|
private function cleanSessionExtKey(string $extkey): string {
|
|
// cant be merged, because cms_ only is in string after we did first replacement
|
|
return str_replace('cms_', '', str_replace('-', '_', $extkey));
|
|
}
|
|
|
|
/**
|
|
* check for possible old files:
|
|
* 1. we do now have cms_ prefix for some reason
|
|
* 2. we only write localLang.xlf
|
|
*
|
|
* @param string $absolutePath
|
|
* @return string
|
|
*/
|
|
public function getOlderPath(string $absolutePath): string {
|
|
return str_replace(['.xlf', 'cms_'], ['.xml', ''], $absolutePath);
|
|
}
|
|
|
|
/**
|
|
* Merges Language data from original and override files, so all data can e presented to user.
|
|
*
|
|
* @return void
|
|
*/
|
|
protected function mergeOriginalWidthOverrideLangData() {
|
|
foreach ($this->originalFileObject->getLocalLang() as $lang => $langData) {
|
|
if (!is_array($langData)) {
|
|
continue;
|
|
}
|
|
|
|
foreach ($langData as $costKey => $constValue) {
|
|
if (isset($this->localLang[$lang][$costKey]) && $this->localLang[$lang][$costKey] !== $constValue) {
|
|
continue;
|
|
}
|
|
|
|
if (!array_key_exists($lang, $this->localLang) || !is_array($this->localLang[$lang])) {
|
|
$this->localLang[$lang] = [];
|
|
}
|
|
|
|
$this->localLang[$lang][$costKey] = $constValue;
|
|
}
|
|
}
|
|
|
|
foreach ($this->originalFileObject->getMeta() as $metaTag => $metaTagValue) {
|
|
if ($metaTag === '@attributes') {
|
|
foreach ($metaTagValue as $attributeKey => $attributeValue) {
|
|
if (isset($this->meta[$metaTag][$attributeKey])
|
|
&& $this->meta[$metaTag][$attributeKey] !== $attributeValue
|
|
) {
|
|
continue;
|
|
}
|
|
$this->meta[$metaTag][$attributeKey] = $attributeValue;
|
|
}
|
|
} else {
|
|
if (isset($this->meta[$metaTag]) && $this->meta[$metaTag] !== $metaTagValue) {
|
|
continue;
|
|
}
|
|
$this->meta[$metaTag] = $metaTagValue;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Merges Language data from original and override files, so all data can e presented to user.
|
|
*
|
|
* @param FileService $fileObject
|
|
* @return void
|
|
*/
|
|
protected function mergeFileObjectWidthOverrideLangData(FileService $fileObject) {
|
|
foreach ($fileObject->getLocalLang() as $lang => $langData) {
|
|
if (!is_array($langData)) {
|
|
continue;
|
|
}
|
|
|
|
foreach ($langData as $costKey => $constValue) {
|
|
if (isset($this->localLang[$lang][$costKey]) && $this->localLang[$lang][$costKey] !== $constValue) {
|
|
continue;
|
|
}
|
|
|
|
if (!array_key_exists($lang, $this->localLang) || !is_array($this->localLang[$lang])) {
|
|
$this->localLang[$lang] = [];
|
|
}
|
|
|
|
$this->localLang[$lang][$costKey] = $constValue;
|
|
}
|
|
}
|
|
|
|
foreach ($fileObject->getMeta() as $metaTag => $metaTagValue) {
|
|
if ($metaTag === '@attributes') {
|
|
foreach ($metaTagValue as $attributeKey => $attributeValue) {
|
|
if (isset($this->meta[$metaTag][$attributeKey])
|
|
&& $this->meta[$metaTag][$attributeKey] !== $attributeValue
|
|
) {
|
|
continue;
|
|
}
|
|
$this->meta[$metaTag][$attributeKey] = $attributeValue;
|
|
}
|
|
} else {
|
|
if (isset($this->meta[$metaTag]) && $this->meta[$metaTag] !== $metaTagValue) {
|
|
continue;
|
|
}
|
|
$this->meta[$metaTag] = $metaTagValue;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Writes language override files.
|
|
*
|
|
* @param array|null $editedLanguages
|
|
* @return void
|
|
* @throws \Exception
|
|
* @throws LFException raised if a file cant be written
|
|
*/
|
|
public function writeFile($editedLanguages = NULL) {
|
|
$this->deleteDuplicates();
|
|
if (!$this->langDataExists() && !is_file($this->absFile)) {
|
|
return;
|
|
}
|
|
|
|
$pathSite = Environment::getPublicPath() . '/';
|
|
try {
|
|
SgLib::createDir($this->absPath, $pathSite);
|
|
} catch (\Exception $exception) {
|
|
throw new LFException('failure.failure', 0, '(' . $exception->getMessage() . ')');
|
|
}
|
|
|
|
$translationFile = basename($this->absFile);
|
|
$translationDir = dirname($this->absFile);
|
|
foreach ($this->localLang as $langKey => $val) {
|
|
if ($langKey !== 'default' && $langKey !== 'trans-unit') {
|
|
$this->originLang[$langKey] = $translationDir . '/' . $langKey . '.' . $translationFile;
|
|
}
|
|
}
|
|
|
|
parent::writeFile();
|
|
|
|
// Set only new values in GlobalConfiguration if something changed
|
|
$originalAbsPath = $this->originalFileObject->getAbsFile();
|
|
$pathSpecsOriginialFile = pathinfo($originalAbsPath);
|
|
$locallangXMLOverride = &$GLOBALS['TYPO3_CONF_VARS']['SYS']['locallangXMLOverride'];
|
|
$file = $this->session->getDataByKey('languageFileSelection');
|
|
$extensionKey = $this->session->getDataByKey('extkey');
|
|
$oldExtensionName = $this->cleanSessionExtKey($extensionKey);
|
|
$typo3ExtRelativeFilePath = 'EXT:' . $oldExtensionName . '/' . $file;
|
|
$relativeOverridePath = str_replace(
|
|
'EXT:' . $oldExtensionName,
|
|
'typo3conf/LFEditor/OverrideFiles/' . $oldExtensionName,
|
|
$typo3ExtRelativeFilePath
|
|
);
|
|
if (array_key_exists($typo3ExtRelativeFilePath, $locallangXMLOverride) &&
|
|
$locallangXMLOverride[$typo3ExtRelativeFilePath][0] === $relativeOverridePath) {
|
|
return;
|
|
}
|
|
|
|
/** @var ConfigurationService $configurationService */
|
|
$configurationService = GeneralUtility::makeInstance(ConfigurationService::class);
|
|
$additionalConfigurationFilePath = $configurationService->getAdditionalConfigurationFilePath();
|
|
|
|
try {
|
|
// what we need:
|
|
$addLine = '$GLOBALS[\'TYPO3_CONF_VARS\'][\'SYS\'][\'locallangXMLOverride\'][\''
|
|
. $typo3ExtRelativeFilePath . '\'][0] = \'' . $relativeOverridePath . '\';';
|
|
Typo3Lib::writeLineToAdditionalConfiguration($addLine, $additionalConfigurationFilePath);
|
|
$GLOBALS['TYPO3_CONF_VARS']['SYS']['locallangXMLOverride'][$typo3ExtRelativeFilePath][0]
|
|
= $relativeOverridePath;
|
|
} catch (\Exception $exception) {
|
|
throw new LFException('failure.failure', 0, '(' . $exception->getMessage() . ')');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Deletes duplicated language data (data that exist in both files - original file and override file),
|
|
* so that only changed data will be saved in override file.
|
|
*
|
|
* @return void
|
|
*/
|
|
public function deleteDuplicates() {
|
|
$defaultLangData = $this->originalFileObject->getLocalLangData('default');
|
|
foreach ($this->localLang as $language => $languageData) {
|
|
if (!is_array($languageData)) {
|
|
continue;
|
|
}
|
|
foreach ($languageData as $constKey => $constValue) {
|
|
$localLangData = $this->originalFileObject->getLocalLangData($language);
|
|
if (array_key_exists($constKey, $localLangData) && SgLib::strCmpIgnoreCR(
|
|
$constValue,
|
|
$localLangData[$constKey]
|
|
)) {
|
|
unset($this->localLang[$language][$constKey]);
|
|
} elseif ($language !== 'default' && $language !== 'trans-unit') {
|
|
// if we are not in default, but we deleted the default key, we have to restore it, else we would
|
|
// not write the correct language content in xlf
|
|
if (!array_key_exists($constKey, $this->localLang['default'])) {
|
|
$this->localLang['default'][$constKey] = $defaultLangData[$constKey] ?? '';
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
foreach ($this->meta as $metaTag => $metaValue) {
|
|
if (SgLib::strCmpIgnoreCR($metaValue, $this->originalFileObject->getMetaData($metaTag))) {
|
|
unset($this->meta[$metaTag]);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Checks is there any lang data (constants in $localLang and meta data).
|
|
*
|
|
* @return bool Returns true if any constant or meta data exist.
|
|
*/
|
|
protected function langDataExists() {
|
|
foreach ($this->meta as $metaTag => $metaValue) {
|
|
if (isset($this->meta[$metaTag]) && $metaTag !== '@attributes') {
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
foreach ($this->localLang as $language => $languageData) {
|
|
if (!is_array($languageData)) {
|
|
continue;
|
|
}
|
|
foreach ($languageData as $constKey => $constValue) {
|
|
if (isset($languageData[$constKey])) {
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
/**
|
|
* Writes generator meta tag.
|
|
*
|
|
* @return void
|
|
*/
|
|
protected function addGeneratorString() {
|
|
if ($this->originalFileObject->getMetaData('generator') !== 'LFEditor') {
|
|
$this->meta['generator'] = 'LFEditor';
|
|
}
|
|
}
|
|
}
|