Initial commit - Typo3 11.5.41
This commit is contained in:
@@ -0,0 +1,236 @@
|
||||
<?php
|
||||
|
||||
namespace SGalinski\Lfeditor\Controller;
|
||||
|
||||
/***************************************************************
|
||||
* 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 TYPO3\CMS\Backend\Template\ModuleTemplate;
|
||||
use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Extbase\Mvc\View\ViewInterface;
|
||||
use TYPO3\CMS\Extbase\Utility\LocalizationUtility;
|
||||
|
||||
/**
|
||||
* Abstract Backend Controller
|
||||
*/
|
||||
abstract class AbstractBackendController extends AbstractController {
|
||||
/**
|
||||
* @var BackendUserAuthentication
|
||||
*/
|
||||
protected $backendUser;
|
||||
|
||||
/**
|
||||
* @var ?ModuleTemplate
|
||||
*/
|
||||
protected $moduleTemplate = NULL;
|
||||
|
||||
/**
|
||||
* Initializes any action
|
||||
*
|
||||
* @return void
|
||||
* @throws \SGalinski\Lfeditor\Exceptions\DirectoryAccessRightsException
|
||||
*/
|
||||
public function initializeAction() {
|
||||
parent::initializeAction();
|
||||
|
||||
if (\TYPO3\CMS\Core\Http\ApplicationType::fromRequest($GLOBALS['TYPO3_REQUEST'])->isBackend()) {
|
||||
$this->backendUser = $GLOBALS['BE_USER'];
|
||||
}
|
||||
|
||||
$editingMode = $this->session->getDataByKey('editingMode');
|
||||
$availableEditingModes = $this->configurationService->getAvailableEditingModes();
|
||||
if ($this->backendUser->isAdmin()) {
|
||||
if (!\array_key_exists($editingMode, $availableEditingModes)) {
|
||||
$firstAvailableEditMode = \key($availableEditingModes);
|
||||
$this->session->setDataByKey('editingMode', $firstAvailableEditMode);
|
||||
}
|
||||
$canChangeEditingModes = \count($availableEditingModes) > 0;
|
||||
} else {
|
||||
$canChangeEditingModes = \count($availableEditingModes) > 0
|
||||
&& $this->backendUser->user['lfeditor_change_editing_modes'] !== 0;
|
||||
if (!$canChangeEditingModes || !\array_key_exists($editingMode, $availableEditingModes)) {
|
||||
$lastAvailableEditMode = array_key_last($availableEditingModes);
|
||||
$this->session->setDataByKey('editingMode', $lastAvailableEditMode);
|
||||
}
|
||||
}
|
||||
|
||||
$this->session->setDataByKey('defaultLanguagePermission', $this->backendUser->checkLanguageAccess(0));
|
||||
$this->session->setDataByKey('canChangeEditingModes', $canChangeEditingModes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the the last called controller/action pair into the backend user
|
||||
* configuration if available
|
||||
*
|
||||
* @param bool $saveWithRedirectPair
|
||||
* @return void
|
||||
*/
|
||||
protected function setLastCalledControllerActionPair($saveWithRedirectPair = TRUE) {
|
||||
if (!$this->backendUser) {
|
||||
return;
|
||||
}
|
||||
|
||||
$extensionKey = $this->request->getControllerExtensionKey();
|
||||
$pair = [
|
||||
'action' => $this->request->getControllerActionName(),
|
||||
'controller' => $this->request->getControllerName(),
|
||||
];
|
||||
|
||||
$this->backendUser->uc[$extensionKey . 'State']['LastActionControllerPair'] = $pair;
|
||||
if ($saveWithRedirectPair) {
|
||||
$this->backendUser->uc[$extensionKey . 'State']['LastActionControllerPairForRedirect'] = $pair;
|
||||
}
|
||||
$this->backendUser->writeUC($this->backendUser->uc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the last called controller/action pair combination from the
|
||||
* backend user session
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function resetLastCalledControllerActionPair() {
|
||||
if (!$this->backendUser) {
|
||||
return;
|
||||
}
|
||||
|
||||
$extensionKey = $this->request->getControllerExtensionKey();
|
||||
$this->backendUser->uc[$extensionKey . 'State']['LastActionControllerPair'] = [];
|
||||
$this->backendUser->uc[$extensionKey . 'State']['LastActionControllerPairForRedirect'] = [];
|
||||
$this->backendUser->writeUC($this->backendUser->uc);
|
||||
|
||||
if ($this->view instanceof ViewInterface) {
|
||||
$this->view->assign('lastCalledControllerActionPair', NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the last called controller/action pair from the backend user session
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getLastCalledControllerActionPair() {
|
||||
if (!$this->backendUser) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$extensionKey = $this->request->getControllerExtensionKey();
|
||||
$state = $this->backendUser->uc[$extensionKey . 'State']['LastActionControllerPair'];
|
||||
return (!\is_array($state) ? [] : $state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the last called controller/action pair from the backend user session
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getLastCalledControllerActionPairForRedirect() {
|
||||
if (!$this->backendUser) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$extensionKey = $this->request->getControllerExtensionKey();
|
||||
return $this->backendUser->uc[$extensionKey . 'State']['LastActionControllerPairForRedirect'] ?? [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Redirects to the last called controller/action pair saved inside the
|
||||
* backend user session
|
||||
*
|
||||
* @return \TYPO3\CMS\Extbase\Http\ForwardResponse|null
|
||||
* @throws \TYPO3\CMS\Extbase\Mvc\Exception\StopActionException
|
||||
*/
|
||||
protected function redirectToLastCalledControllerActionPair(): ?\TYPO3\CMS\Extbase\Http\ForwardResponse {
|
||||
$state = $this->getLastCalledControllerActionPairForRedirect();
|
||||
if (\count($state) && \trim($state['action']) !== '' && \trim($state['controller']) !== '') {
|
||||
$currentAction = $this->request->getControllerActionName();
|
||||
$currentController = $this->request->getControllerName();
|
||||
if (!($currentController === $state['controller'] && $currentAction === $state['action'])) {
|
||||
$extensionName = $this->request->getControllerExtensionName();
|
||||
$moduleSignature = $this->request->getPluginName();
|
||||
$extensionConfig = $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['extbase']['extensions'][$extensionName];
|
||||
$availableControllers = $extensionConfig['modules'][$moduleSignature]['controllers'];
|
||||
$controllerExists = isset($availableControllers[$state['controller']]);
|
||||
if ($controllerExists) {
|
||||
$actionExists = \in_array(
|
||||
$state['action'],
|
||||
$availableControllers[$state['controller']]['actions'],
|
||||
TRUE
|
||||
);
|
||||
if ($actionExists) {
|
||||
if (version_compare(
|
||||
\TYPO3\CMS\Core\Utility\VersionNumberUtility::getCurrentTypo3Version(),
|
||||
'11.0.0',
|
||||
'<'
|
||||
)) {
|
||||
$this->forward($state['action'], $state['controller']);
|
||||
}
|
||||
|
||||
return (new \TYPO3\CMS\Extbase\Http\ForwardResponse($state['action']))->withControllerName(
|
||||
$state['controller']
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets last called controller-action pair and assigns common view variables.
|
||||
* This function should be called at the end of actions which render view
|
||||
* (and does not do redirection or forwarding at the end)
|
||||
*/
|
||||
protected function commonViewRenderingActionSettings() {
|
||||
$this->setLastCalledControllerActionPair();
|
||||
$this->view->assign('editingMode', $this->session->getDataByKey('editingMode'));
|
||||
$this->view->assign('editingModeOptions', $this->configurationService->getAvailableEditingModes());
|
||||
$this->view->assign('adminUser', $this->backendUser->isAdmin());
|
||||
$this->view->assign('defaultLanguagePermission', $this->session->getDataByKey('defaultLanguagePermission'));
|
||||
$this->view->assign('canChangeEditingModes', $this->session->getDataByKey('canChangeEditingModes'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Since we cannot use constructor Injection, we do have to get one dynamically. If we want to use
|
||||
* our ModuleTemplate, call GetModuleTemplate before, which will init one if there is none for some reason
|
||||
*/
|
||||
protected function getModuleTemplate() {
|
||||
if ($this->moduleTemplate === NULL) {
|
||||
$moduleTemplateFactory = GeneralUtility::makeInstance(
|
||||
\TYPO3\CMS\Backend\Template\ModuleTemplateFactory::class
|
||||
);
|
||||
$this->moduleTemplate = $moduleTemplateFactory->create($this->request);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Use the ModuleTemplateResponse to create a response object for the backend
|
||||
*
|
||||
* @return \Psr\Http\Message\ResponseInterface
|
||||
*/
|
||||
protected function createBackendResponse(): \Psr\Http\Message\ResponseInterface {
|
||||
return $this->htmlResponse($this->view->render());
|
||||
}
|
||||
}
|
||||
317
typo3conf/ext/lfeditor/Classes/Controller/AbstractController.php
Normal file
317
typo3conf/ext/lfeditor/Classes/Controller/AbstractController.php
Normal file
@@ -0,0 +1,317 @@
|
||||
<?php
|
||||
|
||||
namespace SGalinski\Lfeditor\Controller;
|
||||
|
||||
/***************************************************************
|
||||
* 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\Service\BackupService;
|
||||
use SGalinski\Lfeditor\Service\ConfigurationService;
|
||||
use SGalinski\Lfeditor\Session\PhpSession;
|
||||
use TYPO3\CMS\Core\Cache\CacheManager;
|
||||
use TYPO3\CMS\Core\Messaging\AbstractMessage;
|
||||
use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
|
||||
use TYPO3\CMS\Extbase\Utility\LocalizationUtility;
|
||||
|
||||
/**
|
||||
* Abstract Controller
|
||||
*/
|
||||
abstract class AbstractController extends ActionController {
|
||||
/**
|
||||
* @var \SGalinski\Lfeditor\Session\PhpSession
|
||||
*/
|
||||
protected $session;
|
||||
|
||||
/**
|
||||
*
|
||||
* @var ConfigurationService
|
||||
*/
|
||||
protected $configurationService;
|
||||
|
||||
/**
|
||||
* Inject the ConfigurationService
|
||||
*
|
||||
* @param ConfigurationService $configurationService
|
||||
*/
|
||||
public function injectConfigurationService(ConfigurationService $configurationService) {
|
||||
$this->configurationService = $configurationService;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @var BackupService
|
||||
*/
|
||||
protected $backupService;
|
||||
|
||||
/**
|
||||
* Inject the BackupService
|
||||
*
|
||||
* @param BackupService $backupService
|
||||
*/
|
||||
public function injectBackupService(BackupService $backupService) {
|
||||
$this->backupService = $backupService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the actions.
|
||||
* - Initializes the session object.
|
||||
* - Fetches configuration.
|
||||
*
|
||||
* @return void
|
||||
* @throws \SGalinski\Lfeditor\Exceptions\DirectoryAccessRightsException
|
||||
*/
|
||||
public function initializeAction() {
|
||||
parent::initializeAction();
|
||||
if (!($this->session instanceof PhpSession)) {
|
||||
$this->session = GeneralUtility::makeInstance(PhpSession::class);
|
||||
$this->session->setSessionKey('tx_lfeditor_sessionVariables');
|
||||
}
|
||||
$this->configurationService->prepareConfig();
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves in session currently selected values of select tags.
|
||||
*
|
||||
* @param string $extensionSelection
|
||||
* @param string $languageFileSelection
|
||||
* @param string $referenceLanguageSelection
|
||||
* @param string $constantSelection
|
||||
* @param string $languageSelection
|
||||
* @param string $constantTypeSelection
|
||||
* @param string $bottomReferenceLanguageSelection
|
||||
* @param string $numSiteConstsSelection
|
||||
* @param string $extkey
|
||||
* @return void
|
||||
*/
|
||||
protected function saveSelectionsInSession(
|
||||
$extensionSelection = NULL,
|
||||
$languageFileSelection = NULL,
|
||||
$referenceLanguageSelection = NULL,
|
||||
$constantSelection = NULL,
|
||||
$languageSelection = NULL,
|
||||
$constantTypeSelection = NULL,
|
||||
$bottomReferenceLanguageSelection = NULL,
|
||||
$numSiteConstsSelection = NULL,
|
||||
$extkey = NULL
|
||||
) {
|
||||
/* Extension/language file select box can't be unselected.
|
||||
Only situation when $extensionSelection === NULL is when the form is submitted by
|
||||
selection change of some other box. That is because <f:be.menus.actionMenu> with 'optgroup' tags is used */
|
||||
if ($extensionSelection) {
|
||||
$this->session->setDataByKey('extensionSelection', $extensionSelection);
|
||||
}
|
||||
if ($languageFileSelection) {
|
||||
$this->session->setDataByKey('languageFileSelection', $languageFileSelection);
|
||||
}
|
||||
if ($referenceLanguageSelection) {
|
||||
$this->session->setDataByKey('referenceLanguageSelection', $referenceLanguageSelection);
|
||||
}
|
||||
if ($constantSelection) {
|
||||
$this->session->setDataByKey('constantSelection', $constantSelection);
|
||||
}
|
||||
if ($languageSelection) {
|
||||
$this->session->setDataByKey('languageSelection', $languageSelection);
|
||||
}
|
||||
if ($constantTypeSelection) {
|
||||
$this->session->setDataByKey('constantTypeSelection', $constantTypeSelection);
|
||||
}
|
||||
if ($bottomReferenceLanguageSelection) {
|
||||
$this->session->setDataByKey('bottomReferenceLanguageSelection', $bottomReferenceLanguageSelection);
|
||||
}
|
||||
if ($numSiteConstsSelection) {
|
||||
$this->session->setDataByKey('numSiteConstsSelection', $numSiteConstsSelection);
|
||||
}
|
||||
if ($extkey) {
|
||||
$this->session->setDataByKey('extkey', $extkey);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns view width menu options and default menu selection which is fetched from session.
|
||||
*
|
||||
* @param string $menuName Name of the menu, which will be used as prefix of view keys for menu options and menu selection.
|
||||
* Example: menuName 'extension' will produce view keys 'extensionOptions' and 'extensionSelection'
|
||||
* @param array $options menu options to be assigned to view
|
||||
* @return void
|
||||
*/
|
||||
protected function assignViewWidthMenuVariables($menuName, $options) {
|
||||
$this->view->assign($menuName . 'Options', $options);
|
||||
|
||||
$selection = $this->checkMenuSelection($menuName, $options);
|
||||
$this->view->assign($menuName . 'Selection', $selection);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks does selection exists in session or among menu options and if it does not,
|
||||
* first option becomes selected.
|
||||
*
|
||||
* @param string $menuName Name of the menu, which will be used as prefix of view keys for menu options and menu selection.
|
||||
* Example: menuName 'extension' will produce view keys 'extensionOptions' and 'extensionSelection'
|
||||
* @param array $options menu options to be checked upon.
|
||||
* @return string
|
||||
*/
|
||||
protected function checkMenuSelection($menuName, array $options) {
|
||||
$selection = $this->session->getDataByKey($menuName . 'Selection');
|
||||
if (!\array_key_exists($selection, $options)) {
|
||||
$selection = NULL;
|
||||
}
|
||||
if ($selection === NULL && !empty($options)) {
|
||||
$selection = array_key_first($options);
|
||||
$this->session->setDataByKey($menuName . 'Selection', $selection);
|
||||
return $selection;
|
||||
}
|
||||
return $selection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets FlashMessage from LFException.
|
||||
*
|
||||
* @param LFException $lFException
|
||||
* @return void
|
||||
*/
|
||||
public function addLFEFlashMessage(LFException $lFException) {
|
||||
if ($lFException->getCode() === 0) {
|
||||
$this->addFlashMessage(
|
||||
$lFException->getMessage(),
|
||||
LocalizationUtility::translate('failure.failure', 'lfeditor'),
|
||||
AbstractMessage::ERROR
|
||||
);
|
||||
} elseif ($lFException->getCode() === 1) {
|
||||
$this->addFlashMessage(
|
||||
$lFException->getMessage(),
|
||||
'',
|
||||
AbstractMessage::NOTICE
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares language file select options for each extension and sets combined data in view.
|
||||
*
|
||||
* @return void
|
||||
* @throws \TYPO3\CMS\Core\Cache\Exception\NoSuchCacheException
|
||||
* @throws LFException
|
||||
*/
|
||||
protected function prepareExtensionAndLangFileOptions() {
|
||||
/** @var CacheManager $cacheManager */
|
||||
$cacheManager = GeneralUtility::makeInstance(CacheManager::class);
|
||||
$extensions = $cacheManager->getCache('lfeditor_select_options_cache')->get('extensionAndLangFileOptions');
|
||||
if (!is_array($extensions)) {
|
||||
$extensions = [];
|
||||
$extensionOptions = $this->configurationService->menuExtList();
|
||||
$extensionGroupCount = 0;
|
||||
foreach ($extensionOptions as $extAddress => $extLabel) {
|
||||
$extension['extKey'] = $extLabel;
|
||||
((int) ExtensionManagementUtility::isLoaded(basename($extLabel))) ?
|
||||
$state = LocalizationUtility::translate('ext.loaded', 'lfeditor') :
|
||||
$state = LocalizationUtility::translate('ext.notLoaded', 'lfeditor');
|
||||
$extension['extLabel'] = $extLabel . ' [' . $state . ']';
|
||||
|
||||
$extension['languageFileOptions'] = [];
|
||||
$isExtensionGroupStart = $extAddress === '###extensionGroup###' . $extLabel;
|
||||
try {
|
||||
if (!$isExtensionGroupStart) {
|
||||
$extension['languageFileOptions'] = $this->configurationService->menuLangFileList($extAddress);
|
||||
if (empty($extension['languageFileOptions'])) {
|
||||
continue;
|
||||
}
|
||||
} elseif (++$extensionGroupCount > 1) {
|
||||
$extensions[$extAddress . 'EmptySpaceBefore'] = [
|
||||
'extLabel' => '',
|
||||
'languageFileOptions' => [],
|
||||
];
|
||||
}
|
||||
} catch (LFException $e) {
|
||||
continue;
|
||||
}
|
||||
$extensions[$extAddress] = $extension;
|
||||
|
||||
if ($isExtensionGroupStart) {
|
||||
$extensions[$extAddress . 'DelimiterAfter'] = [
|
||||
'extLabel' => '======',
|
||||
'languageFileOptions' => [],
|
||||
];
|
||||
}
|
||||
}
|
||||
$cacheManager->getCache('lfeditor_select_options_cache')->set('extensionAndLangFileOptions', $extensions);
|
||||
}
|
||||
$this->checkExtensionAndLangFileSelection($extensions);
|
||||
$extensionSelection = $this->session->getDataByKey('extensionSelection');
|
||||
|
||||
$this->view->assign('extensions', $extensions);
|
||||
$this->view->assign('extensionSelection', $extensionSelection);
|
||||
$this->view->assign('extensionLabel', $extensions[$extensionSelection]['extLabel'] ?? '');
|
||||
$this->view->assign('languageFileSelection', $this->session->getDataByKey('languageFileSelection'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks do extensionSelection and languageFileSelection exist in session or among menu options and if it does not,
|
||||
* first language file and belonging extension become selected and saved to session.
|
||||
*
|
||||
* @param array $extensions
|
||||
* @return void
|
||||
*/
|
||||
protected function checkExtensionAndLangFileSelection(array $extensions) {
|
||||
$extensionSelection = $this->session->getDataByKey('extensionSelection');
|
||||
$languageFileSelection = $this->session->getDataByKey('languageFileSelection');
|
||||
|
||||
$selectFirstLanguageFileAndBelongingExtension = !$extensionSelection || !$languageFileSelection ||
|
||||
!(array_key_exists($extensionSelection, $extensions) && array_key_exists(
|
||||
$languageFileSelection,
|
||||
$extensions[$extensionSelection]['languageFileOptions']
|
||||
));
|
||||
if ($selectFirstLanguageFileAndBelongingExtension) {
|
||||
foreach ($extensions as $extAddress => $extension) {
|
||||
if (empty($extension['languageFileOptions'])) {
|
||||
continue;
|
||||
}
|
||||
$languageFileSelection = array_key_first($extension['languageFileOptions']);
|
||||
$this->session->setDataByKey('languageFileSelection', $languageFileSelection);
|
||||
$this->session->setDataByKey('extensionSelection', $extAddress);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears cache used for storing select options.
|
||||
* If $identifier is set, it clears only that entry in cache,
|
||||
* otherwise it clears whole select options cache.
|
||||
*
|
||||
* @param string $identifier
|
||||
* @throws \TYPO3\CMS\Core\Cache\Exception\NoSuchCacheException
|
||||
*/
|
||||
protected function clearSelectOptionsCache($identifier = NULL) {
|
||||
/** @var CacheManager $cacheManager */
|
||||
$cacheManager = GeneralUtility::makeInstance(CacheManager::class);
|
||||
if ($identifier !== NULL) {
|
||||
$cacheManager->getCache('lfeditor_select_options_cache')->set($identifier, NULL);
|
||||
} else {
|
||||
$cacheManager->getCache('lfeditor_select_options_cache')->flush();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,176 @@
|
||||
<?php
|
||||
|
||||
namespace SGalinski\Lfeditor\Controller;
|
||||
|
||||
/***************************************************************
|
||||
* 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 TYPO3\CMS\Core\Messaging\AbstractMessage;
|
||||
use TYPO3\CMS\Extbase\Mvc\Exception\UnsupportedRequestTypeException;
|
||||
use TYPO3\CMS\Extbase\Utility\LocalizationUtility;
|
||||
|
||||
/**
|
||||
* AddConstant controller. It contains extbase actions for AddConstant page.
|
||||
*/
|
||||
class AddConstantController extends AbstractBackendController {
|
||||
/**
|
||||
* Opens addConstant view.
|
||||
* It is called in 2 cases:
|
||||
* - on selection of addConstant option in main menu,
|
||||
* - after redirection from action which must not change the view.
|
||||
*
|
||||
*/
|
||||
public function addConstantAction(): ?\Psr\Http\Message\ResponseInterface {
|
||||
try {
|
||||
$this->view->assign('controllerName', 'AddConstant');
|
||||
|
||||
$this->prepareExtensionAndLangFileOptions();
|
||||
$this->prepareAddConstantViewMainSectionContent();
|
||||
} catch (LFException $e) {
|
||||
$this->addLFEFlashMessage($e);
|
||||
}
|
||||
$this->commonViewRenderingActionSettings();
|
||||
|
||||
if (version_compare(\TYPO3\CMS\Core\Utility\VersionNumberUtility::getCurrentTypo3Version(), '11.0.0', '<')) {
|
||||
$this->view->assign('V11', FALSE);
|
||||
return NULL;
|
||||
} else {
|
||||
$this->view->assign('V11', TRUE);
|
||||
return $this->createBackendResponse();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This action saves in session currently selected options from selection menus in addConstant view.
|
||||
* It is called on change of selection of any select menu in addConstant view.
|
||||
*
|
||||
* @param string $extensionSelection
|
||||
* @param string $languageFileSelection
|
||||
* @param string $extKey
|
||||
* @throws \TYPO3\CMS\Extbase\Mvc\Exception\StopActionException
|
||||
*/
|
||||
public function changeSelectionAction($extensionSelection = NULL, $languageFileSelection = NULL, $extKey = ''): ?\Psr\Http\Message\ResponseInterface {
|
||||
$this->saveSelectionsInSession(
|
||||
$extensionSelection,
|
||||
$languageFileSelection,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
$extKey
|
||||
);
|
||||
|
||||
if (version_compare(\TYPO3\CMS\Core\Utility\VersionNumberUtility::getCurrentTypo3Version(), '11.0.0', '<')) {
|
||||
$this->redirect('addConstant');
|
||||
return NULL;
|
||||
} else {
|
||||
return $this->redirect('addConstant');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the changes made in main section of addConstant view.
|
||||
*
|
||||
* @param string $nameOfConstant
|
||||
* @param array $addConstTextArea
|
||||
* @return \Psr\Http\Message\ResponseInterface|null
|
||||
* @throws \TYPO3\CMS\Core\Cache\Exception\NoSuchCacheException
|
||||
* @throws \TYPO3\CMS\Extbase\Mvc\Exception\StopActionException
|
||||
*/
|
||||
public function addConstantSaveAction($nameOfConstant, array $addConstTextArea): ?\Psr\Http\Message\ResponseInterface {
|
||||
try {
|
||||
if (empty($nameOfConstant)) {
|
||||
throw new LFException('failure.select.noConstDefined');
|
||||
}
|
||||
$extConfig = $this->configurationService->getExtConfig();
|
||||
|
||||
$this->configurationService->initFileObject(
|
||||
$this->session->getDataByKey('languageFileSelection'),
|
||||
$this->session->getDataByKey('extensionSelection')
|
||||
);
|
||||
|
||||
$langData = $this->configurationService->getFileObj()->getLocalLangData();
|
||||
|
||||
$constExists = !empty($langData['default'][$nameOfConstant])
|
||||
|| !empty($langData[$extConfig['defaultLanguage']][$nameOfConstant]);
|
||||
if ($constExists) {
|
||||
throw new LFException('failure.langfile.constExists');
|
||||
}
|
||||
|
||||
$newConstLanguages = [];
|
||||
foreach ($addConstTextArea as $lang => $value) {
|
||||
$newConstLanguages[$lang][$nameOfConstant] = $value;
|
||||
}
|
||||
|
||||
$this->configurationService->execWrite($newConstLanguages);
|
||||
$this->session->setDataByKey('constantSelection', $nameOfConstant);
|
||||
|
||||
$this->addFlashMessage(
|
||||
LocalizationUtility::translate('lang.file.write.success', 'lfeditor'),
|
||||
'',
|
||||
$severity = AbstractMessage::OK,
|
||||
$storeInSession = TRUE
|
||||
);
|
||||
} catch (LFException $e) {
|
||||
$this->addLFEFlashMessage($e);
|
||||
}
|
||||
if (version_compare(\TYPO3\CMS\Core\Utility\VersionNumberUtility::getCurrentTypo3Version(), '11.0.0', '<')) {
|
||||
$this->redirect('addConstant');
|
||||
return NULL;
|
||||
} else {
|
||||
return $this->redirect('addConstant');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears extensionAndLangFileOptions cache, and in that way refreshes list of language file options in select box.
|
||||
*
|
||||
*/
|
||||
public function refreshLanguageFileListAction(): ?\Psr\Http\Message\ResponseInterface {
|
||||
$this->clearSelectOptionsCache('extensionAndLangFileOptions');
|
||||
if (version_compare(\TYPO3\CMS\Core\Utility\VersionNumberUtility::getCurrentTypo3Version(), '11.0.0', '<')) {
|
||||
$this->redirect('addConstant');
|
||||
return NULL;
|
||||
} else {
|
||||
return $this->redirect('addConstant');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares main section content of addConstant view.
|
||||
*
|
||||
* @throws LFException
|
||||
* @return void
|
||||
*/
|
||||
protected function prepareAddConstantViewMainSectionContent() {
|
||||
$extConfig = $this->configurationService->getExtConfig();
|
||||
$langArray = $this->configurationService->getLangArray($this->backendUser);
|
||||
|
||||
$this->view->assign('languages', $langArray);
|
||||
$this->view->assign('numTextAreaRows', $extConfig['numTextAreaRows']);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,189 @@
|
||||
<?php
|
||||
|
||||
namespace SGalinski\Lfeditor\Controller;
|
||||
|
||||
/***************************************************************
|
||||
* 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\Service\FileOverrideService;
|
||||
use SGalinski\Lfeditor\Utility\Functions;
|
||||
use TYPO3\CMS\Core\Messaging\AbstractMessage;
|
||||
use TYPO3\CMS\Extbase\Mvc\Exception\UnsupportedRequestTypeException;
|
||||
use TYPO3\CMS\Extbase\Utility\LocalizationUtility;
|
||||
|
||||
/**
|
||||
* DeleteConstant controller. It contains extbase actions for DeleteConstant page.
|
||||
*/
|
||||
class DeleteConstantController extends AbstractBackendController {
|
||||
/**
|
||||
* Opens deleteConstant view.
|
||||
* It is called in 2 cases:
|
||||
* - on selection of deleteConstant option in main menu,
|
||||
* - after redirection from action which must not change the view.
|
||||
*
|
||||
*/
|
||||
public function deleteConstantAction(): ?\Psr\Http\Message\ResponseInterface {
|
||||
try {
|
||||
$this->view->assign('controllerName', 'DeleteConstant');
|
||||
|
||||
$this->prepareExtensionAndLangFileOptions();
|
||||
$this->configurationService->initFileObject(
|
||||
$this->session->getDataByKey('languageFileSelection'),
|
||||
$this->session->getDataByKey('extensionSelection')
|
||||
);
|
||||
$fileObject = $this->configurationService->getFileObj();
|
||||
if ($this->session->getDataByKey('editingMode') === 'override') {
|
||||
/** @var FileOverrideService $overrideFileObject */
|
||||
$overrideFileObject = $fileObject;
|
||||
$overrideFileObject->deleteDuplicates();
|
||||
}
|
||||
|
||||
$langData = $fileObject->getLocalLangData();
|
||||
$constantOptions = $this->configurationService->menuConstList(
|
||||
$langData,
|
||||
LocalizationUtility::translate('select.nothing', 'lfeditor')
|
||||
);
|
||||
$this->assignViewWidthMenuVariables('constant', $constantOptions);
|
||||
$this->prepareDeleteConstantViewMainSectionContent();
|
||||
} catch (LFException $e) {
|
||||
$this->addLFEFlashMessage($e);
|
||||
}
|
||||
$this->commonViewRenderingActionSettings();
|
||||
if (version_compare(\TYPO3\CMS\Core\Utility\VersionNumberUtility::getCurrentTypo3Version(), '11.0.0', '<')) {
|
||||
$this->view->assign('V11', FALSE);
|
||||
return NULL;
|
||||
} else {
|
||||
$this->view->assign('V11', TRUE);
|
||||
return $this->createBackendResponse();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This action saves in session currently selected options from selection menus in deleteConstant view.
|
||||
* It is called on change of selection of any select menu in deleteConstant view.
|
||||
*
|
||||
* @param string $extensionSelection
|
||||
* @param string $languageFileSelection
|
||||
* @param string $constantSelection
|
||||
* @param string $extKey
|
||||
* @throws \TYPO3\CMS\Extbase\Mvc\Exception\StopActionException
|
||||
*/
|
||||
public function changeSelectionAction(
|
||||
$extensionSelection = NULL,
|
||||
$languageFileSelection = NULL,
|
||||
$constantSelection = NULL,
|
||||
$extKey = ''
|
||||
): ?\Psr\Http\Message\ResponseInterface {
|
||||
$this->saveSelectionsInSession(
|
||||
$extensionSelection,
|
||||
$languageFileSelection,
|
||||
NULL,
|
||||
$constantSelection,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
$extKey
|
||||
);
|
||||
|
||||
if (version_compare(\TYPO3\CMS\Core\Utility\VersionNumberUtility::getCurrentTypo3Version(), '11.0.0', '<')) {
|
||||
$this->redirect('deleteConstant');
|
||||
return NULL;
|
||||
} else {
|
||||
return $this->redirect('deleteConstant');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the changes made in main section of deleteConstant view.
|
||||
*
|
||||
* @return \Psr\Http\Message\ResponseInterface|null
|
||||
* @throws \TYPO3\CMS\Core\Cache\Exception\NoSuchCacheException
|
||||
* @throws \TYPO3\CMS\Extbase\Mvc\Exception\StopActionException
|
||||
*/
|
||||
public function deleteConstantSaveAction(): ?\Psr\Http\Message\ResponseInterface {
|
||||
try {
|
||||
$constantSelection = $this->session->getDataByKey('constantSelection');
|
||||
$langArray = Functions::buildLangArray();
|
||||
|
||||
// build modArray
|
||||
$newLang = [];
|
||||
foreach ($langArray as $lang) {
|
||||
$newLang[$lang][$constantSelection] = '';
|
||||
}
|
||||
|
||||
$this->configurationService->execWrite($newLang, [], TRUE);
|
||||
|
||||
$this->addFlashMessage(
|
||||
LocalizationUtility::translate('lang.file.write.success', 'lfeditor'),
|
||||
'',
|
||||
$severity = AbstractMessage::OK,
|
||||
$storeInSession = TRUE
|
||||
);
|
||||
} catch (LFException $e) {
|
||||
$this->addLFEFlashMessage($e);
|
||||
}
|
||||
|
||||
if (version_compare(\TYPO3\CMS\Core\Utility\VersionNumberUtility::getCurrentTypo3Version(), '11.0.0', '<')) {
|
||||
$this->redirect('deleteConstant');
|
||||
return NULL;
|
||||
} else {
|
||||
return $this->redirect('deleteConstant');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears extensionAndLangFileOptions cache, and in that way refreshes list of language file options in select box.
|
||||
*
|
||||
* @return \Psr\Http\Message\ResponseInterface|null
|
||||
* @throws \TYPO3\CMS\Core\Cache\Exception\NoSuchCacheException
|
||||
* @throws \TYPO3\CMS\Extbase\Mvc\Exception\StopActionException
|
||||
*/
|
||||
public function refreshLanguageFileListAction(): ?\Psr\Http\Message\ResponseInterface {
|
||||
$this->clearSelectOptionsCache('extensionAndLangFileOptions');
|
||||
|
||||
if (version_compare(\TYPO3\CMS\Core\Utility\VersionNumberUtility::getCurrentTypo3Version(), '11.0.0', '<')) {
|
||||
$this->redirect('deleteConstant');
|
||||
return NULL;
|
||||
} else {
|
||||
return $this->redirect('deleteConstant');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares main section content of deleteConstant view.
|
||||
*
|
||||
* @throws LFException
|
||||
* @return void
|
||||
*/
|
||||
protected function prepareDeleteConstantViewMainSectionContent() {
|
||||
$constantSelection = $this->session->getDataByKey('constantSelection');
|
||||
if (empty($constantSelection) || $constantSelection == '###default###') {
|
||||
throw new LFException('failure.select.noConst', 1);
|
||||
}
|
||||
|
||||
$this->view->assign('constantSelection', $constantSelection);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,204 @@
|
||||
<?php
|
||||
|
||||
namespace SGalinski\Lfeditor\Controller;
|
||||
|
||||
/***************************************************************
|
||||
* 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 TYPO3\CMS\Core\Messaging\AbstractMessage;
|
||||
use TYPO3\CMS\Extbase\Utility\LocalizationUtility;
|
||||
|
||||
/**
|
||||
* EditConstant controller. It contains extbase actions for EditConstant page.
|
||||
*/
|
||||
class EditConstantController extends AbstractBackendController {
|
||||
/**
|
||||
* Opens editConstant view.
|
||||
* It is called in 2 cases:
|
||||
* - on selection of editConstant option in main menu,
|
||||
* - after redirection from action which must not change the view.
|
||||
*
|
||||
* @return \Psr\Http\Message\ResponseInterface|null
|
||||
* @throws \TYPO3\CMS\Core\Cache\Exception\NoSuchCacheException
|
||||
*/
|
||||
public function editConstantAction(): ?\Psr\Http\Message\ResponseInterface {
|
||||
try {
|
||||
$this->view->assign('controllerName', 'EditConstant');
|
||||
|
||||
$this->prepareExtensionAndLangFileOptions();
|
||||
$this->configurationService->initFileObject(
|
||||
$this->session->getDataByKey('languageFileSelection'),
|
||||
$this->session->getDataByKey('extensionSelection')
|
||||
);
|
||||
|
||||
$langData = $this->configurationService->getFileObj()->getLocalLangData();
|
||||
$constantOptions = $this->configurationService->menuConstList(
|
||||
$langData,
|
||||
LocalizationUtility::translate('select.nothing', 'lfeditor')
|
||||
);
|
||||
$this->assignViewWidthMenuVariables('constant', $constantOptions);
|
||||
|
||||
$this->prepareEditConstantViewMainSectionContent($langData);
|
||||
} catch (LFException $e) {
|
||||
$this->addLFEFlashMessage($e);
|
||||
}
|
||||
|
||||
$this->commonViewRenderingActionSettings();
|
||||
|
||||
if (version_compare(\TYPO3\CMS\Core\Utility\VersionNumberUtility::getCurrentTypo3Version(), '11.0.0', '<')) {
|
||||
$this->view->assign('V11', FALSE);
|
||||
return NULL;
|
||||
} else {
|
||||
$this->view->assign('V11', TRUE);
|
||||
return $this->createBackendResponse();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This action saves in session currently selected options from selection menus in editConstant view.
|
||||
* It is called on change of selection of any select menu in editConstant view.
|
||||
*
|
||||
* @param string $extensionSelection
|
||||
* @param string $languageFileSelection
|
||||
* @param string $constantSelection
|
||||
* @param string $extKey
|
||||
* @throws \TYPO3\CMS\Extbase\Mvc\Exception\StopActionException
|
||||
*/
|
||||
public function changeSelectionAction(
|
||||
$extensionSelection = NULL,
|
||||
$languageFileSelection = NULL,
|
||||
$constantSelection = NULL,
|
||||
$extKey = ''
|
||||
): ?\Psr\Http\Message\ResponseInterface {
|
||||
$this->saveSelectionsInSession(
|
||||
$extensionSelection,
|
||||
$languageFileSelection,
|
||||
NULL,
|
||||
$constantSelection,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
$extKey
|
||||
);
|
||||
|
||||
if (version_compare(\TYPO3\CMS\Core\Utility\VersionNumberUtility::getCurrentTypo3Version(), '11.0.0', '<')) {
|
||||
$this->redirect('editConstant');
|
||||
return NULL;
|
||||
} else {
|
||||
return $this->redirect('editConstant');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the changes made in main section of editConstant view.
|
||||
*
|
||||
* @param array $editConstTextArea
|
||||
* @return \Psr\Http\Message\ResponseInterface|null
|
||||
* @throws \TYPO3\CMS\Core\Cache\Exception\NoSuchCacheException
|
||||
* @throws \TYPO3\CMS\Extbase\Mvc\Exception\StopActionException
|
||||
*/
|
||||
public function editConstantSaveAction(array $editConstTextArea): ?\Psr\Http\Message\ResponseInterface {
|
||||
try {
|
||||
$this->configurationService->execWrite($editConstTextArea);
|
||||
|
||||
$this->addFlashMessage(
|
||||
LocalizationUtility::translate('lang.file.write.success', 'lfeditor'),
|
||||
'',
|
||||
$severity = AbstractMessage::OK,
|
||||
$storeInSession = TRUE
|
||||
);
|
||||
} catch (LFException $e) {
|
||||
$this->addLFEFlashMessage($e);
|
||||
}
|
||||
|
||||
if (version_compare(\TYPO3\CMS\Core\Utility\VersionNumberUtility::getCurrentTypo3Version(), '11.0.0', '<')) {
|
||||
$this->redirect('editConstant');
|
||||
return NULL;
|
||||
} else {
|
||||
return $this->redirect('editConstant');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears extensionAndLangFileOptions cache, and in that way refreshes list of language file options in select box.
|
||||
*
|
||||
* @return \Psr\Http\Message\ResponseInterface|null
|
||||
* @throws \TYPO3\CMS\Core\Cache\Exception\NoSuchCacheException
|
||||
* @throws \TYPO3\CMS\Extbase\Mvc\Exception\StopActionException
|
||||
*/
|
||||
public function refreshLanguageFileListAction(): ?\Psr\Http\Message\ResponseInterface {
|
||||
$this->clearSelectOptionsCache('extensionAndLangFileOptions');
|
||||
if (version_compare(\TYPO3\CMS\Core\Utility\VersionNumberUtility::getCurrentTypo3Version(), '11.0.0', '<')) {
|
||||
$this->redirect('editConstant');
|
||||
return NULL;
|
||||
} else {
|
||||
return $this->redirect('editConstant');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares main section content of editConstant view.
|
||||
*
|
||||
* @param array $langData
|
||||
* @throws LFException
|
||||
* @return void
|
||||
*/
|
||||
protected function prepareEditConstantViewMainSectionContent(array $langData = NULL) {
|
||||
$extConfig = $this->configurationService->getExtConfig();
|
||||
$langArray = $this->configurationService->getLangArray($this->backendUser);
|
||||
|
||||
$constantSelection = $this->session->getDataByKey('constantSelection');
|
||||
if (empty($constantSelection) || $constantSelection == '###default###') {
|
||||
throw new LFException('failure.select.noConst', 1);
|
||||
}
|
||||
|
||||
$languages = [];
|
||||
foreach ($langArray as $lang) {
|
||||
if (array_key_exists($lang, $langData) && array_key_exists($constantSelection, $langData[$lang])) {
|
||||
$languages[$lang] = $langData[$lang][$constantSelection];
|
||||
} else {
|
||||
$languages[$lang] = '';
|
||||
}
|
||||
}
|
||||
|
||||
$this->view->assign('constantSelection', $constantSelection);
|
||||
$this->view->assign('languages', $languages);
|
||||
$this->view->assign('numTextAreaRows', $extConfig['numTextAreaRows']);
|
||||
$this->view->assign('defaultLanguage', $extConfig['defaultLanguage']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets chosen constant and redirects to editConstant view.
|
||||
*
|
||||
* @param string $constantKey
|
||||
* @return void
|
||||
*/
|
||||
protected function prepareEditConstantAction($constantKey) {
|
||||
$this->session->setDataByKey('constantSelection', $constantKey);
|
||||
|
||||
$this->redirect('editConstant', 'EditConstant');
|
||||
}
|
||||
}
|
||||
365
typo3conf/ext/lfeditor/Classes/Controller/EditFileController.php
Normal file
365
typo3conf/ext/lfeditor/Classes/Controller/EditFileController.php
Normal file
@@ -0,0 +1,365 @@
|
||||
<?php
|
||||
|
||||
namespace SGalinski\Lfeditor\Controller;
|
||||
|
||||
/***************************************************************
|
||||
* 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 TYPO3\CMS\Core\Messaging\AbstractMessage;
|
||||
use TYPO3\CMS\Extbase\Utility\LocalizationUtility;
|
||||
|
||||
/**
|
||||
* EditFile controller. It contains extbase actions of EditFile page.
|
||||
*/
|
||||
class EditFileController extends AbstractBackendController {
|
||||
/**
|
||||
* Opens editFile view.
|
||||
* It is called in 2 cases:
|
||||
* - on selection of editFile option in main menu,
|
||||
* - after redirection from action which must not change the view.
|
||||
*
|
||||
* @param integer $buttonType :
|
||||
* -1 - cancel,
|
||||
* 0 - no button clicked,
|
||||
* 1 - back,
|
||||
* 2 - next,
|
||||
* 3 - save.
|
||||
* @throws \TYPO3\CMS\Core\Cache\Exception\NoSuchCacheException
|
||||
*/
|
||||
public function editFileAction(int $buttonType = 0): ?\Psr\Http\Message\ResponseInterface {
|
||||
try {
|
||||
$this->view->assign('controllerName', 'EditFile');
|
||||
|
||||
$this->prepareExtensionAndLangFileOptions();
|
||||
$this->configurationService->initFileObject(
|
||||
$this->session->getDataByKey('languageFileSelection'),
|
||||
$this->session->getDataByKey('extensionSelection')
|
||||
);
|
||||
$langData = $this->configurationService->getFileObj()->getLocalLangData();
|
||||
|
||||
$languageOptions = $this->configurationService->menuLangList($langData, '', $this->backendUser);
|
||||
$this->assignViewWidthMenuVariables('language', $languageOptions);
|
||||
|
||||
$referenceLanguageOptions = $this->configurationService->menuLangList(
|
||||
$langData,
|
||||
LocalizationUtility::translate('select.nothing', 'lfeditor'),
|
||||
$this->backendUser
|
||||
);
|
||||
$this->assignViewWidthMenuVariables('referenceLanguage', $referenceLanguageOptions);
|
||||
|
||||
$bottomReferenceLanguageOptions = $this->configurationService->menuLangList(
|
||||
$langData,
|
||||
'',
|
||||
$this->backendUser,
|
||||
TRUE
|
||||
);
|
||||
$this->assignViewWidthMenuVariables('bottomReferenceLanguage', $bottomReferenceLanguageOptions);
|
||||
|
||||
$constantTypeOptions = $this->getConstantTypeOptions();
|
||||
$this->assignViewWidthMenuVariables('constantType', $constantTypeOptions);
|
||||
|
||||
$extConfig = $this->configurationService->getExtConfig();
|
||||
$this->assignViewWidthMenuVariables('numSiteConsts', $extConfig['numSiteConstsOptions']);
|
||||
|
||||
$this->prepareEditFileViewMainSectionContent($langData, $buttonType);
|
||||
} catch (LFException $e) {
|
||||
$this->addLFEFlashMessage($e);
|
||||
}
|
||||
$this->commonViewRenderingActionSettings();
|
||||
if (version_compare(\TYPO3\CMS\Core\Utility\VersionNumberUtility::getCurrentTypo3Version(), '11.0.0', '<')) {
|
||||
$this->view->assign('V11', FALSE);
|
||||
return NULL;
|
||||
} else {
|
||||
$this->view->assign('V11', TRUE);
|
||||
return $this->createBackendResponse();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This action saves in session currently selected options from selection menus in editFile view.
|
||||
* It is called on change of selection of any select menu in editFile view.
|
||||
*
|
||||
* @param string $extensionSelection
|
||||
* @param string $languageFileSelection
|
||||
* @param string $languageSelection
|
||||
* @param string $referenceLanguageSelection
|
||||
* @param string $constantTypeSelection
|
||||
* @param string $bottomReferenceLanguageSelection
|
||||
* @param string $numSiteConstsSelection
|
||||
* @param string $extKey
|
||||
* @throws \TYPO3\CMS\Extbase\Mvc\Exception\StopActionException
|
||||
*/
|
||||
public function changeSelectionAction(
|
||||
$extensionSelection = NULL,
|
||||
$languageFileSelection = NULL,
|
||||
$languageSelection = NULL,
|
||||
$referenceLanguageSelection = NULL,
|
||||
$constantTypeSelection = NULL,
|
||||
$bottomReferenceLanguageSelection = NULL,
|
||||
$numSiteConstsSelection = NULL,
|
||||
$extKey = ''
|
||||
): ?\Psr\Http\Message\ResponseInterface {
|
||||
$this->saveSelectionsInSession(
|
||||
$extensionSelection,
|
||||
$languageFileSelection,
|
||||
$referenceLanguageSelection,
|
||||
NULL,
|
||||
$languageSelection,
|
||||
$constantTypeSelection,
|
||||
$bottomReferenceLanguageSelection,
|
||||
$numSiteConstsSelection,
|
||||
$extKey
|
||||
);
|
||||
|
||||
if (version_compare(\TYPO3\CMS\Core\Utility\VersionNumberUtility::getCurrentTypo3Version(), '11.0.0', '<')) {
|
||||
$this->redirect('editFile', NULL, NULL, ['buttonType' => 0]);
|
||||
return NULL;
|
||||
} else {
|
||||
return $this->redirect('editFile', NULL, NULL, ['buttonType' => 0]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears extensionAndLangFileOptions cache, and in that way refreshes list of language file options in select box.
|
||||
*
|
||||
*/
|
||||
public function refreshLanguageFileListAction(): ?\Psr\Http\Message\ResponseInterface {
|
||||
$this->clearSelectOptionsCache('extensionAndLangFileOptions');
|
||||
if (version_compare(\TYPO3\CMS\Core\Utility\VersionNumberUtility::getCurrentTypo3Version(), '11.0.0', '<')) {
|
||||
$this->redirect('editFile', NULL, NULL, ['buttonType' => 0]);
|
||||
return NULL;
|
||||
} else {
|
||||
return $this->redirect('editFile', NULL, NULL, ['buttonType' => 0]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares main section content of editFile view.
|
||||
* Structure of the content:
|
||||
* $constValues[$constant]['edit'],
|
||||
* $constValues[$constant]['pattern'],
|
||||
* $constValues[$constant][$extConfig['defaultLanguage']].
|
||||
*
|
||||
* @param array $langData
|
||||
* @param integer $buttonType :
|
||||
* -1 - cancel,
|
||||
* 0 - no button clicked,
|
||||
* 1 - back,
|
||||
* 2 - next,
|
||||
* 3 - save.
|
||||
* @throws LFException
|
||||
* @return void
|
||||
*/
|
||||
protected function prepareEditFileViewMainSectionContent(array $langData, int $buttonType) {
|
||||
$extConfig = $this->configurationService->getExtConfig();
|
||||
$numConstantsPerPage = $this->session->getDataByKey('numSiteConstsSelection');
|
||||
|
||||
$langList = $this->session->getDataByKey('languageSelection');
|
||||
$patternList = $this->session->getDataByKey('referenceLanguageSelection');
|
||||
$constTypeList = $this->session->getDataByKey('constantTypeSelection');
|
||||
$parallelEdit = $patternList !== '###default###' && $patternList != $langList;
|
||||
|
||||
$langEdit = (array_key_exists($langList, $langData) && is_array($langData[$langList])) ? $langData[$langList] : [];
|
||||
$langPattern = (array_key_exists($patternList, $langData) && is_array($langData[$patternList])) ? $langData[$patternList] : [];
|
||||
$bottomReferenceLanguageSelection = $this->session->getDataByKey('bottomReferenceLanguageSelection');
|
||||
$bottomReferenceLanguage = is_array($langData[$bottomReferenceLanguageSelection])
|
||||
? $langData[$bottomReferenceLanguageSelection] : [];
|
||||
if (empty($bottomReferenceLanguage)) {
|
||||
$bottomReferenceLanguage = is_array($langData['default']) ? $langData['default'] : [];
|
||||
}
|
||||
|
||||
$langDataSessionContinued = $buttonType !== 3;
|
||||
if ($buttonType === 0) {
|
||||
$this->session->setDataByKey('sessionLangDataConstantsIterator', 0);
|
||||
$this->session->setDataByKey('numberLastPageConstants', 0);
|
||||
}
|
||||
$sessionLangDataConstantsIterator = $this->session->getDataByKey('sessionLangDataConstantsIterator');
|
||||
$numberLastPageConstants = $this->session->getDataByKey('numberLastPageConstants');
|
||||
|
||||
// new translation
|
||||
if (!$langDataSessionContinued || $buttonType <= 0) {
|
||||
// adjust number of session constants
|
||||
if ($constTypeList === 'untranslated' || $constTypeList === 'translated' ||
|
||||
$constTypeList === 'unknown' || $buttonType <= 0
|
||||
) {
|
||||
$sessionLangDataConstantsIterator = 0;
|
||||
} elseif (!$langDataSessionContinued) { // session written to file
|
||||
$sessionLangDataConstantsIterator -= $numberLastPageConstants;
|
||||
}
|
||||
|
||||
// delete old data in session
|
||||
$this->session->setDataByKey('langfileEditNewLangData', NULL);
|
||||
$this->session->setDataByKey('langfileEditConstantsList', NULL);
|
||||
|
||||
// get language data
|
||||
if ($constTypeList === 'untranslated') {
|
||||
$myLangData = array_diff_key($bottomReferenceLanguage, $langEdit);
|
||||
} elseif ($constTypeList === 'unknown') {
|
||||
$myLangData = array_diff_key($langEdit, $bottomReferenceLanguage);
|
||||
} elseif ($constTypeList === 'translated') {
|
||||
$myLangData = array_intersect_key($bottomReferenceLanguage, $langEdit);
|
||||
} else {
|
||||
$myLangData = $bottomReferenceLanguage;
|
||||
}
|
||||
$this->session->setDataByKey('langfileEditConstantsList', array_keys($myLangData));
|
||||
} elseif ($buttonType === 1) { // back button
|
||||
$sessionLangDataConstantsIterator -= ($numConstantsPerPage + $numberLastPageConstants);
|
||||
}
|
||||
|
||||
// get language constants
|
||||
$langData = $this->session->getDataByKey('langfileEditConstantsList');
|
||||
$numConsts = is_countable($langData) ? count($langData) : 0;
|
||||
if (!(is_countable($langData) ? count($langData) : 0)) {
|
||||
throw new LFException('failure.select.emptyLangDataArray', 1);
|
||||
}
|
||||
$langfileEditNewLangData = $this->session->getDataByKey('langfileEditNewLangData');
|
||||
if ($langfileEditNewLangData === '') {
|
||||
$langfileEditNewLangData = [];
|
||||
}
|
||||
|
||||
// prepare constant list for this page
|
||||
$numberLastPageConstants = 0;
|
||||
$constValues = [];
|
||||
do {
|
||||
// check number of session constants
|
||||
if ($sessionLangDataConstantsIterator >= $numConsts) {
|
||||
break;
|
||||
}
|
||||
++$numberLastPageConstants;
|
||||
|
||||
// set constant value (maybe already changed in this session)
|
||||
$constant = $langData[$sessionLangDataConstantsIterator];
|
||||
$editLangVal = $langEdit[$constant] ?? '';
|
||||
if (!isset($langfileEditNewLangData[$langList][$constant])) {
|
||||
$langfileEditNewLangData[$langList][$constant] = $editLangVal;
|
||||
} else {
|
||||
$editLangVal = $langfileEditNewLangData[$langList][$constant];
|
||||
}
|
||||
|
||||
// set constant value (maybe already changed in this session)
|
||||
$editPatternVal = $langPattern[$constant] ?? '';
|
||||
if (!isset($langfileEditNewLangData[$patternList][$constant])) {
|
||||
$langfileEditNewLangData[$patternList][$constant] = $editPatternVal;
|
||||
} else {
|
||||
$editPatternVal =
|
||||
$langfileEditNewLangData[$patternList][$constant];
|
||||
}
|
||||
|
||||
// save information about the constant
|
||||
$constValues[$constant]['edit'] = $editLangVal;
|
||||
$constValues[$constant]['pattern'] = $editPatternVal;
|
||||
$constValues[$constant]['default'] = $bottomReferenceLanguage[$constant];
|
||||
} while (++$sessionLangDataConstantsIterator % $numConstantsPerPage);
|
||||
|
||||
$this->session->setDataByKey('langfileEditNewLangData', $langfileEditNewLangData);
|
||||
$this->session->setDataByKey('sessionLangDataConstantsIterator', $sessionLangDataConstantsIterator);
|
||||
$this->session->setDataByKey('numberLastPageConstants', $numberLastPageConstants);
|
||||
|
||||
$this->view->assign('numTextAreaRows', $extConfig['numTextAreaRows']);
|
||||
$this->view->assign('defaultLanguage', $extConfig['defaultLanguage']);
|
||||
$this->view->assign('parallelEdit', $parallelEdit);
|
||||
$this->view->assign('displayBackButton', $sessionLangDataConstantsIterator > $numConstantsPerPage);
|
||||
$this->view->assign('displayNextButton', $sessionLangDataConstantsIterator < $numConsts);
|
||||
|
||||
$this->view->assign('constValues', $constValues);
|
||||
$this->view->assign('curConsts', $sessionLangDataConstantsIterator);
|
||||
$this->view->assign('totalConsts', $numConsts);
|
||||
$this->view->assign('numSiteConstsSelection', $numConstantsPerPage);
|
||||
}
|
||||
|
||||
/**
|
||||
* Used for the constant type selector
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function getConstantTypeOptions(): array {
|
||||
$constantTypeOptions = [];
|
||||
$constantTypeOptions['all'] = LocalizationUtility::translate('const.type.all', 'lfeditor');
|
||||
$constantTypeOptions['translated'] = LocalizationUtility::translate('const.type.translated', 'lfeditor');
|
||||
$constantTypeOptions['unknown'] = LocalizationUtility::translate('const.type.unknown', 'lfeditor');
|
||||
$constantTypeOptions['untranslated'] = LocalizationUtility::translate('const.type.untranslated', 'lfeditor');
|
||||
return $constantTypeOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the changes made in main section of editFile view.
|
||||
*
|
||||
* @param integer $buttonType
|
||||
* @param array $editFileTextArea editFileTextArea[{languageSelection}][{constKey}]
|
||||
* @return \Psr\Http\Message\ResponseInterface|null
|
||||
* @throws \TYPO3\CMS\Core\Cache\Exception\NoSuchCacheException
|
||||
* @throws \TYPO3\CMS\Extbase\Mvc\Exception\StopActionException
|
||||
*/
|
||||
public function editFileSaveAction(int $buttonType, array $editFileTextArea): ?\Psr\Http\Message\ResponseInterface {
|
||||
try {
|
||||
$languageSelection = $this->session->getDataByKey('languageSelection');
|
||||
$referenceLanguageSelection = $this->session->getDataByKey('referenceLanguageSelection');
|
||||
$langDataSessionContinued = $buttonType !== 3;
|
||||
|
||||
$langfileEditNewLangData = $this->session->getDataByKey('langfileEditNewLangData');
|
||||
$langfileEditNewLangData[$languageSelection] =
|
||||
array_merge(
|
||||
$langfileEditNewLangData[$languageSelection],
|
||||
$editFileTextArea[$languageSelection]
|
||||
);
|
||||
|
||||
// parallel edit mode?
|
||||
if ($referenceLanguageSelection !== '###default###' && $referenceLanguageSelection != $languageSelection) {
|
||||
$langfileEditNewLangData[$referenceLanguageSelection] =
|
||||
array_merge(
|
||||
$langfileEditNewLangData[$referenceLanguageSelection],
|
||||
$editFileTextArea[$referenceLanguageSelection] ?? []
|
||||
);
|
||||
}
|
||||
$this->session->setDataByKey('langfileEditNewLangData', $langfileEditNewLangData);
|
||||
|
||||
// write if no session continued
|
||||
if (!$langDataSessionContinued) {
|
||||
// Making array of languages that were changed, so only that language files will be edited.
|
||||
$editedLanguages = [$languageSelection];
|
||||
if ($languageSelection !== $referenceLanguageSelection) {
|
||||
$editedLanguages[] = $referenceLanguageSelection;
|
||||
}
|
||||
|
||||
$this->configurationService->execWrite($langfileEditNewLangData, [], FALSE, $editedLanguages);
|
||||
$this->addFlashMessage(
|
||||
LocalizationUtility::translate('lang.file.write.success', 'lfeditor'),
|
||||
'',
|
||||
$severity = AbstractMessage::OK,
|
||||
$storeInSession = TRUE
|
||||
);
|
||||
}
|
||||
} catch (LFException $e) {
|
||||
$this->addLFEFlashMessage($e);
|
||||
}
|
||||
|
||||
if (version_compare(\TYPO3\CMS\Core\Utility\VersionNumberUtility::getCurrentTypo3Version(), '11.0.0', '<')) {
|
||||
$this->redirect('editFile', NULL, NULL, ['buttonType' => $buttonType]);
|
||||
return NULL;
|
||||
} else {
|
||||
return $this->redirect('editFile', NULL, NULL, ['buttonType' => $buttonType]);
|
||||
}
|
||||
}
|
||||
}
|
||||
302
typo3conf/ext/lfeditor/Classes/Controller/GeneralController.php
Normal file
302
typo3conf/ext/lfeditor/Classes/Controller/GeneralController.php
Normal file
@@ -0,0 +1,302 @@
|
||||
<?php
|
||||
|
||||
namespace SGalinski\Lfeditor\Controller;
|
||||
|
||||
/***************************************************************
|
||||
* 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\Functions;
|
||||
use SGalinski\Lfeditor\Utility\SgLib;
|
||||
use TYPO3\CMS\Core\Messaging\AbstractMessage;
|
||||
use TYPO3\CMS\Extbase\Mvc\Exception\UnsupportedRequestTypeException;
|
||||
use TYPO3\CMS\Extbase\Utility\LocalizationUtility;
|
||||
|
||||
/**
|
||||
* General controller. It contains extbase actions for general page.
|
||||
*/
|
||||
class GeneralController extends AbstractBackendController {
|
||||
/** Code for normal split operation */
|
||||
public const NORMAL_SPLIT = 1;
|
||||
|
||||
/** Code for merge operation */
|
||||
public const MERGE = 2;
|
||||
|
||||
/**
|
||||
* Renders last-opened page. This action ai called upon opening LFEditor.
|
||||
*
|
||||
* @param bool $doStateRedirect
|
||||
* @throws \TYPO3\CMS\Extbase\Mvc\Exception\StopActionException
|
||||
*/
|
||||
public function indexAction($doStateRedirect = TRUE): ?\Psr\Http\Message\ResponseInterface {
|
||||
if ($doStateRedirect) {
|
||||
$this->redirectToLastCalledControllerActionPair();
|
||||
}
|
||||
|
||||
$this->resetLastCalledControllerActionPair();
|
||||
|
||||
if (version_compare(\TYPO3\CMS\Core\Utility\VersionNumberUtility::getCurrentTypo3Version(), '11.0.0', '<')) {
|
||||
$this->redirect('general', 'General');
|
||||
return NULL;
|
||||
} else {
|
||||
return $this->redirect('general', 'General');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens general view.
|
||||
* It is called in 2 cases:
|
||||
* - on selection of general option in main menu,
|
||||
* - after redirection from action which must not change the view.
|
||||
*
|
||||
* @throws \TYPO3\CMS\Core\Cache\Exception\NoSuchCacheException
|
||||
*/
|
||||
public function generalAction(): ?\Psr\Http\Message\ResponseInterface {
|
||||
try {
|
||||
$this->view->assign('controllerName', 'General');
|
||||
|
||||
$this->prepareExtensionAndLangFileOptions();
|
||||
if (!$this->session->getDataByKey('languageFileSelection')) {
|
||||
throw new LFException('failure.select.noLangfile', 1);
|
||||
}
|
||||
$this->prepareGeneralViewMainSectionContent();
|
||||
} catch (LFException $e) {
|
||||
$this->addLFEFlashMessage($e);
|
||||
}
|
||||
$this->commonViewRenderingActionSettings();
|
||||
if (version_compare(\TYPO3\CMS\Core\Utility\VersionNumberUtility::getCurrentTypo3Version(), '11.0.0', '<')) {
|
||||
$this->view->assign('V11', FALSE);
|
||||
return NULL;
|
||||
} else {
|
||||
$this->view->assign('V11', TRUE);
|
||||
return $this->createBackendResponse();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This action saves in session currently selected options from selection menus in general view.
|
||||
* It is called on change of selection of any select menu in general view.
|
||||
*
|
||||
* @param string $extensionSelection
|
||||
* @param string $languageFileSelection
|
||||
* @param string $extKey
|
||||
* @throws \TYPO3\CMS\Extbase\Mvc\Exception\StopActionException
|
||||
*
|
||||
*/
|
||||
public function changeSelectionAction($extensionSelection = NULL, $languageFileSelection = NULL, $extKey = ''): ?\Psr\Http\Message\ResponseInterface {
|
||||
$this->saveSelectionsInSession(
|
||||
$extensionSelection,
|
||||
$languageFileSelection,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
$extKey
|
||||
);
|
||||
|
||||
if (version_compare(\TYPO3\CMS\Core\Utility\VersionNumberUtility::getCurrentTypo3Version(), '11.0.0', '<')) {
|
||||
$this->redirect('general');
|
||||
return NULL;
|
||||
} else {
|
||||
return $this->redirect('general');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the changes made in main section of general view.
|
||||
*
|
||||
* @param string $authorName
|
||||
* @param string $authorEmail
|
||||
* @param string $metaDescription
|
||||
* @param string $transformFile
|
||||
* @param integer $splitFile
|
||||
* @throws \TYPO3\CMS\Core\Cache\Exception\NoSuchCacheException
|
||||
* @throws \TYPO3\CMS\Extbase\Mvc\Exception\StopActionException
|
||||
*/
|
||||
public function generalSaveAction(
|
||||
$authorName = NULL,
|
||||
$authorEmail = NULL,
|
||||
$metaDescription = NULL,
|
||||
$transformFile = NULL,
|
||||
$splitFile = NULL
|
||||
): ?\Psr\Http\Message\ResponseInterface {
|
||||
try {
|
||||
$metaArray = [
|
||||
'authorName' => $authorName,
|
||||
'authorEmail' => $authorEmail,
|
||||
'description' => $metaDescription
|
||||
];
|
||||
$this->configurationService->execWrite([], $metaArray);
|
||||
|
||||
// split or merge
|
||||
if ($transformFile === 'xlf') {
|
||||
$splitFile = self::NORMAL_SPLIT;
|
||||
}
|
||||
if (($splitFile == self::NORMAL_SPLIT || $splitFile == self::MERGE)) {
|
||||
$langModes = [];
|
||||
// set vars
|
||||
if ($splitFile != self::NORMAL_SPLIT && $splitFile != self::MERGE) {
|
||||
$splitFile = 0;
|
||||
}
|
||||
$langKeys = Functions::buildLangArray();
|
||||
|
||||
// generate langModes
|
||||
foreach ($langKeys as $langKey) {
|
||||
if (!isset($langModes[$langKey])) {
|
||||
$langModes[$langKey] = $splitFile;
|
||||
}
|
||||
}
|
||||
|
||||
// exec split or merge
|
||||
$this->configurationService->execSplitFile($langModes);
|
||||
// reinitialize file object
|
||||
$this->configurationService->initFileObject(
|
||||
$this->session->getDataByKey('languageFileSelection'),
|
||||
$this->session->getDataByKey('extensionSelection')
|
||||
);
|
||||
}
|
||||
|
||||
if (!empty($transformFile)
|
||||
&& $this->configurationService->getFileObj()->getVar('fileType') != $transformFile
|
||||
) {
|
||||
$newFile = SgLib::setFileExtension(
|
||||
$transformFile,
|
||||
$this->configurationService->getFileObj()->getVar('relFile')
|
||||
);
|
||||
$this->configurationService->execTransform($transformFile, $newFile);
|
||||
$this->clearSelectOptionsCache('extensionAndLangFileOptions');
|
||||
}
|
||||
|
||||
$this->addFlashMessage(
|
||||
LocalizationUtility::translate('lang.file.write.success', 'lfeditor'),
|
||||
'',
|
||||
$severity = AbstractMessage::OK,
|
||||
$storeInSession = TRUE
|
||||
);
|
||||
} catch (LFException $e) {
|
||||
$this->addLFEFlashMessage($e);
|
||||
}
|
||||
|
||||
if (version_compare(\TYPO3\CMS\Core\Utility\VersionNumberUtility::getCurrentTypo3Version(), '11.0.0', '<')) {
|
||||
$this->redirect('general');
|
||||
return NULL;
|
||||
} else {
|
||||
return $this->redirect('general');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears extensionAndLangFileOptions cache, and in that way refreshes list of language file options in select box.
|
||||
*
|
||||
* @throws \TYPO3\CMS\Core\Cache\Exception\NoSuchCacheException
|
||||
* @throws \TYPO3\CMS\Extbase\Mvc\Exception\StopActionException
|
||||
*/
|
||||
public function refreshLanguageFileListAction(): ?\Psr\Http\Message\ResponseInterface {
|
||||
$this->clearSelectOptionsCache('extensionAndLangFileOptions');
|
||||
if (version_compare(\TYPO3\CMS\Core\Utility\VersionNumberUtility::getCurrentTypo3Version(), '11.0.0', '<')) {
|
||||
$this->redirect('general');
|
||||
return NULL;
|
||||
} else {
|
||||
return $this->redirect('general');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares main section content of general view.
|
||||
*
|
||||
* @return void
|
||||
* @throws LFException
|
||||
*/
|
||||
protected function prepareGeneralViewMainSectionContent() {
|
||||
$this->configurationService->initFileObject(
|
||||
$this->session->getDataByKey('languageFileSelection'),
|
||||
$this->session->getDataByKey('extensionSelection')
|
||||
);
|
||||
$extConfig = $this->configurationService->getExtConfig();
|
||||
$referenceLanguageSelection = $extConfig['defaultLanguage'];
|
||||
$langArray = $this->configurationService->getLangArray($this->backendUser);
|
||||
$infoArray = Functions::genGeneralInfoArray(
|
||||
$referenceLanguageSelection,
|
||||
$langArray,
|
||||
$this->configurationService->getFileObj()
|
||||
);
|
||||
$description = $infoArray['default']['meta']['description'] ?? '';
|
||||
$langFileExtension = $this->configurationService->getFileObj()->getVar('fileType');
|
||||
$preselectMerge = $this->isOriginSameForAllLanguages($infoArray);
|
||||
|
||||
$this->view->assign('infos', $infoArray);
|
||||
$this->view->assign('refLangNumTranslated', $infoArray[$referenceLanguageSelection]['numTranslated']);
|
||||
$this->view->assign('numTextAreaRows', $extConfig['numTextAreaRows']);
|
||||
$this->view->assign('metaDescription', $description);
|
||||
$this->view->assign('langFileExtension', $langFileExtension);
|
||||
$this->view->assign('preselectMerge', $preselectMerge);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares parameters for redirection to viewTreeAction.
|
||||
*
|
||||
* @param string $language
|
||||
* @return \Psr\Http\Message\ResponseInterface|null
|
||||
* @throws \TYPO3\CMS\Extbase\Mvc\Exception\StopActionException
|
||||
*/
|
||||
public function goToEditFileAction($language): ?\Psr\Http\Message\ResponseInterface {
|
||||
$this->session->setDataByKey('languageSelection', $language);
|
||||
|
||||
if (version_compare(\TYPO3\CMS\Core\Utility\VersionNumberUtility::getCurrentTypo3Version(), '11.0.0', '<')) {
|
||||
$this->redirect('editFile', 'EditFile');
|
||||
return NULL;
|
||||
} else {
|
||||
return $this->redirect('editFile', 'EditFile');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Switches between override mode and normal mode.
|
||||
*
|
||||
* @param string $editingMode 'extension', 'l10n', 'override'.
|
||||
* @return void
|
||||
* @throws \TYPO3\CMS\Extbase\Mvc\Exception\StopActionException
|
||||
*/
|
||||
public function switchEditingModeAction($editingMode = 'extension') {
|
||||
$this->session->setDataByKey('editingMode', $editingMode);
|
||||
$this->indexAction();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks do all language translations originate from same file.
|
||||
*
|
||||
* @param array $infoArray
|
||||
* @return bool
|
||||
*/
|
||||
private function isOriginSameForAllLanguages(array $infoArray) {
|
||||
foreach ($infoArray as $langInfo) {
|
||||
if ($infoArray['default']['origin'] !== $langInfo['origin']) {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,500 @@
|
||||
<?php
|
||||
|
||||
namespace SGalinski\Lfeditor\Controller;
|
||||
|
||||
/***************************************************************
|
||||
* 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\Functions;
|
||||
use SGalinski\Lfeditor\Utility\SgLib;
|
||||
use SGalinski\Lfeditor\Utility\Typo3Lib;
|
||||
use TYPO3\CMS\Core\Core\Environment;
|
||||
use TYPO3\CMS\Core\Messaging\AbstractMessage;
|
||||
use TYPO3\CMS\Extbase\Utility\LocalizationUtility;
|
||||
|
||||
/**
|
||||
* ManageBackups controller. It contains extbase actions for ManageBackups page.
|
||||
*/
|
||||
class ManageBackupsController extends AbstractBackendController {
|
||||
/**
|
||||
* A constant which is used in backup feature to indicate that
|
||||
* language constant is added after backup file was made.
|
||||
*/
|
||||
public const LANG_CONST_ADDED = 2;
|
||||
|
||||
/**
|
||||
* A constant which is used in backup feature to indicate that
|
||||
* language constant is deleted after backup file was made.
|
||||
*/
|
||||
public const LANG_CONST_DELETED = 1;
|
||||
|
||||
/**
|
||||
* A constant which is used in backup feature to indicate that
|
||||
* language constant isn't deleted nor added after backup file was made. It was just changed.
|
||||
*/
|
||||
public const LANG_CONST_NORMAL = 0;
|
||||
|
||||
/**
|
||||
* Opens manageBackups view.
|
||||
* It is called in 2 cases:
|
||||
* - on selection of manageBackups option in main menu,
|
||||
* - after redirection from action which must not change the view.
|
||||
*
|
||||
* @param string $fileName
|
||||
* @param string $langFile language file which was altered.
|
||||
* @param bool $showDiff
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function manageBackupsAction($fileName = '', $langFile = '', $showDiff = FALSE): ?\Psr\Http\Message\ResponseInterface {
|
||||
try {
|
||||
$this->view->assign('controllerName', 'ManageBackups');
|
||||
|
||||
$extensionOptions = $this->configurationService->menuExtList();
|
||||
$this->assignViewWidthMenuVariables('extension', $extensionOptions);
|
||||
|
||||
$this->initializeBackupObject($langFile);
|
||||
$this->prepareManageBackupsViewMainSectionContent();
|
||||
if ($showDiff) {
|
||||
$this->generateDiffContent($fileName);
|
||||
}
|
||||
} catch (LFException $e) {
|
||||
$this->addLFEFlashMessage($e);
|
||||
}
|
||||
$this->commonViewRenderingActionSettings();
|
||||
|
||||
if (version_compare(\TYPO3\CMS\Core\Utility\VersionNumberUtility::getCurrentTypo3Version(), '11.0.0', '<')) {
|
||||
$this->view->assign('V11', FALSE);
|
||||
return NULL;
|
||||
} else {
|
||||
$this->view->assign('V11', TRUE);
|
||||
return $this->createBackendResponse();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This action saves in session currently selected options from selection menus in manageBackups view.
|
||||
* It is called on change of selection of any select menu in searchConstant view.
|
||||
*
|
||||
* @param string $extensionSelection
|
||||
* @param string $extKey
|
||||
*/
|
||||
public function changeSelectionAction($extensionSelection = NULL, $extKey = ''): ?\Psr\Http\Message\ResponseInterface {
|
||||
$this->saveSelectionsInSession(
|
||||
$extensionSelection,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
$extKey
|
||||
);
|
||||
|
||||
|
||||
if (version_compare(\TYPO3\CMS\Core\Utility\VersionNumberUtility::getCurrentTypo3Version(), '11.0.0', '<')) {
|
||||
$this->redirect('manageBackups');
|
||||
return NULL;
|
||||
} else {
|
||||
return $this->redirect('manageBackups');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears extensionAndLangFileOptions cache, and in that way refreshes list of language file options in select box.
|
||||
*
|
||||
*/
|
||||
public function refreshLanguageFileListAction(): ?\Psr\Http\Message\ResponseInterface {
|
||||
$this->clearSelectOptionsCache('extensionAndLangFileOptions');
|
||||
|
||||
if (version_compare(\TYPO3\CMS\Core\Utility\VersionNumberUtility::getCurrentTypo3Version(), '11.0.0', '<')) {
|
||||
$this->redirect('manageBackups');
|
||||
return NULL;
|
||||
} else {
|
||||
return $this->redirect('manageBackups');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares main section content of manageBackupsConstant view.
|
||||
*
|
||||
* @throws LFException
|
||||
*/
|
||||
protected function prepareManageBackupsViewMainSectionContent() {
|
||||
$backups = $this->makeBackupsList();
|
||||
if (empty($backups)) {
|
||||
$this->addFlashMessage(
|
||||
LocalizationUtility::translate('failure.backup.noFiles', 'lfeditor'),
|
||||
'',
|
||||
$severity = AbstractMessage::NOTICE,
|
||||
$storeInSession = TRUE
|
||||
);
|
||||
return;
|
||||
}
|
||||
$recoverLabelThead = strtoupper(
|
||||
substr(LocalizationUtility::translate('function.backupMgr.recover', 'lfeditor'), 0, 1)
|
||||
);
|
||||
$differenceLabelThead = strtoupper(
|
||||
substr(LocalizationUtility::translate('function.backupMgr.diff.diff', 'lfeditor'), 0, 1)
|
||||
);
|
||||
|
||||
$this->view->assign('backups', $backups);
|
||||
$this->view->assign('recoverLabelThead', $recoverLabelThead);
|
||||
$this->view->assign('differenceLabelThead', $differenceLabelThead);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes list of backups for use in fluid page.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function makeBackupsList() {
|
||||
$backups = [];
|
||||
$metaArray = $this->backupService->getBackupObj()->getMetaInfos(2);
|
||||
if (is_array($metaArray)) {
|
||||
$keys = array_keys($metaArray);
|
||||
foreach ($keys as $langFile) {
|
||||
foreach ($metaArray[$langFile] as $fileName => $informations) {
|
||||
$backup = [];
|
||||
|
||||
// get path to filename
|
||||
$backupPath = $informations['pathBackup'];
|
||||
$pathSite = Environment::getPublicPath() . '/';
|
||||
|
||||
$file = Typo3Lib::fixFilePath($pathSite . '/' . $backupPath . '/' . $fileName);
|
||||
$origFile = Typo3Lib::fixFilePath(
|
||||
$this->session->getDataByKey('extensionSelection') . '/' . $langFile
|
||||
);
|
||||
|
||||
// check state
|
||||
if (!is_file($file)) {
|
||||
$backup['state'] = 'function.backupMgr.missing';
|
||||
} elseif (!is_file($origFile)) {
|
||||
$backup['state'] = 'lang.file.missing';
|
||||
} else {
|
||||
$backup['state'] = 'function.backupMgr.ok';
|
||||
}
|
||||
|
||||
$backup['date'] = date('Y-m-d H:i:s', $informations['createdAt']);
|
||||
$backup['langFile'] = $langFile;
|
||||
$backup['fileName'] = $fileName;
|
||||
$backups[] = $backup;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $backups;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes all backups.
|
||||
*
|
||||
*/
|
||||
public function deleteAllBackupAction(): ?\Psr\Http\Message\ResponseInterface {
|
||||
try {
|
||||
$this->initializeBackupObject();
|
||||
$delFiles = [];
|
||||
$metaArray = $this->backupService->getBackupObj()->getMetaInfos(2);
|
||||
foreach ($metaArray as $langFile => $metaPiece) {
|
||||
$files = array_keys($metaPiece);
|
||||
foreach ($files as $filename) {
|
||||
$delFiles[$filename] = $langFile;
|
||||
}
|
||||
}
|
||||
$this->backupService->execBackupDelete($delFiles);
|
||||
$this->addFlashMessage(
|
||||
LocalizationUtility::translate('function.backupMgr.success.deleteAll', 'lfeditor'),
|
||||
'',
|
||||
$severity = AbstractMessage::OK,
|
||||
$storeInSession = TRUE
|
||||
);
|
||||
} catch (LFException $e) {
|
||||
$this->addLFEFlashMessage($e);
|
||||
}
|
||||
|
||||
if (version_compare(\TYPO3\CMS\Core\Utility\VersionNumberUtility::getCurrentTypo3Version(), '11.0.0', '<')) {
|
||||
$this->redirect('manageBackups');
|
||||
return NULL;
|
||||
} else {
|
||||
return $this->redirect('manageBackups');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes backup.
|
||||
*
|
||||
* @param string $fileName
|
||||
* @param string $langFile
|
||||
* @throws \TYPO3\CMS\Extbase\Mvc\Exception\StopActionException
|
||||
*/
|
||||
public function deleteBackupAction($fileName, $langFile): ?\Psr\Http\Message\ResponseInterface {
|
||||
try {
|
||||
$this->initializeBackupObject($langFile);
|
||||
$delFiles = [];
|
||||
$delFiles[$fileName] = '';
|
||||
$this->backupService->execBackupDelete($delFiles);
|
||||
$this->addFlashMessage(
|
||||
LocalizationUtility::translate('function.backupMgr.success.delete', 'lfeditor'),
|
||||
'',
|
||||
$severity = AbstractMessage::OK,
|
||||
$storeInSession = TRUE
|
||||
);
|
||||
} catch (LFException $e) {
|
||||
$this->addLFEFlashMessage($e);
|
||||
}
|
||||
$this->redirect('manageBackups');
|
||||
|
||||
if (version_compare(\TYPO3\CMS\Core\Utility\VersionNumberUtility::getCurrentTypo3Version(), '11.0.0', '<')) {
|
||||
$this->redirect('manageBackups');
|
||||
return NULL;
|
||||
} else {
|
||||
return $this->redirect('manageBackups');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses backup to recover changes.
|
||||
*
|
||||
* @param string $fileName
|
||||
* @param string $langFile
|
||||
* @throws \TYPO3\CMS\Extbase\Mvc\Exception\StopActionException
|
||||
*/
|
||||
public function recoverBackupAction($fileName, $langFile): ?\Psr\Http\Message\ResponseInterface {
|
||||
try {
|
||||
$this->initializeBackupObject($langFile);
|
||||
// set backup file
|
||||
$metaArray = $this->backupService->getBackupObj()->getMetaInfos(3);
|
||||
$pathSite = Environment::getPublicPath() . '/';
|
||||
|
||||
$information = [
|
||||
'absPath' => $pathSite . $metaArray[$fileName]['pathBackup'],
|
||||
'relFile' => $fileName,
|
||||
];
|
||||
$this->backupService->getBackupObj()->setVar($information);
|
||||
$this->backupService->getBackupObj()->readFile();
|
||||
// read original file
|
||||
$this->configurationService->initFileObject(
|
||||
$this->backupService->getBackupObj()->getVar('langFile'),
|
||||
Typo3Lib::fixFilePath($pathSite . '/' . $this->backupService->getBackupObj()->getVar('extPath'))
|
||||
);
|
||||
// restore
|
||||
$this->backupService->execBackupRestore();
|
||||
$this->addFlashMessage(
|
||||
LocalizationUtility::translate('function.backupMgr.success.restore', 'lfeditor'),
|
||||
'',
|
||||
$severity = AbstractMessage::OK,
|
||||
$storeInSession = TRUE
|
||||
);
|
||||
} catch (LFException $e) {
|
||||
$this->addLFEFlashMessage($e);
|
||||
}
|
||||
if (version_compare(\TYPO3\CMS\Core\Utility\VersionNumberUtility::getCurrentTypo3Version(), '11.0.0', '<')) {
|
||||
$this->redirect('manageBackups');
|
||||
return NULL;
|
||||
} else {
|
||||
return $this->redirect('manageBackups');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows differences between backup and original.
|
||||
*
|
||||
* @param string $fileName
|
||||
* @param string $langFile
|
||||
* @return \Psr\Http\Message\ResponseInterface|null
|
||||
* @throws \TYPO3\CMS\Extbase\Mvc\Exception\StopActionException
|
||||
*/
|
||||
public function showDifferenceBackupAction($fileName, $langFile): ?\Psr\Http\Message\ResponseInterface {
|
||||
if (version_compare(\TYPO3\CMS\Core\Utility\VersionNumberUtility::getCurrentTypo3Version(), '11.0.0', '<')) {
|
||||
$this->redirect(
|
||||
'manageBackups',
|
||||
NULL,
|
||||
NULL,
|
||||
['fileName' => $fileName, 'langFile' => $langFile, 'showDiff' => TRUE]
|
||||
);
|
||||
return NULL;
|
||||
} else {
|
||||
return $this->redirect(
|
||||
'manageBackups',
|
||||
NULL,
|
||||
NULL,
|
||||
['fileName' => $fileName, 'langFile' => $langFile, 'showDiff' => TRUE]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes backup object.
|
||||
*
|
||||
* @param string $langFile
|
||||
* @throws LFException
|
||||
* @throws \Exception
|
||||
* @return void
|
||||
*/
|
||||
protected function initializeBackupObject($langFile = '') {
|
||||
$pathSite = Environment::getPublicPath() . '/';
|
||||
$information = [
|
||||
'extPath' => SgLib::trimPath($pathSite, $this->session->getDataByKey('extensionSelection')),
|
||||
'langFile' => $langFile,
|
||||
];
|
||||
$this->backupService->initBackupObject('base', $information);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates content which illustrates differences between backup and current state.
|
||||
*
|
||||
* @param string $fileName
|
||||
* @return void
|
||||
*/
|
||||
protected function generateDiffContent($fileName) {
|
||||
$localLangDiff = NULL;
|
||||
$metaDiff = NULL;
|
||||
$pathSite = Environment::getPublicPath() . '/';
|
||||
// set backup file
|
||||
$metaArray = $this->backupService->getBackupObj()->getMetaInfos(3);
|
||||
$informations = [
|
||||
'absPath' => Typo3Lib::fixFilePath(
|
||||
$pathSite . '/' .
|
||||
$metaArray[$fileName]['pathBackup']
|
||||
),
|
||||
'relFile' => $fileName,
|
||||
];
|
||||
$this->backupService->getBackupObj()->setVar($informations);
|
||||
|
||||
// exec diff
|
||||
// read original file
|
||||
$this->configurationService->initFileObject(
|
||||
$this->backupService->getBackupObj()->getVar('langFile'),
|
||||
Typo3Lib::fixFilePath($pathSite . '/' . $this->backupService->getBackupObj()->getVar('extPath'))
|
||||
);
|
||||
|
||||
// read backup file
|
||||
$this->backupService->getBackupObj()->readFile();
|
||||
|
||||
// get language data
|
||||
$originalLocalLang = $this->configurationService->getFileObj()->getLocalLangData();
|
||||
$backupLocalLang = $this->backupService->getBackupObj()->getLocalLangData();
|
||||
|
||||
// get meta data
|
||||
$origMeta = $this->configurationService->getFileObj()->getMetaData();
|
||||
$backupMeta = $this->backupService->getBackupObj()->getMetaData();
|
||||
|
||||
SgLib::fixMetaAttributes($origMeta);
|
||||
unset($originalLocalLang['trans-unit']);
|
||||
$localLangDiff = Functions::getBackupDiff(0, $originalLocalLang, $backupLocalLang);
|
||||
$metaDiff = Functions::getMetaDiff(0, $origMeta, $backupMeta);
|
||||
|
||||
// generate diff
|
||||
if (is_countable($localLangDiff) ? count($localLangDiff) : 0) {
|
||||
$this->outputManageBackupsDiff(
|
||||
$localLangDiff,
|
||||
$metaDiff,
|
||||
$originalLocalLang,
|
||||
$backupLocalLang,
|
||||
$this->configurationService->getFileObj()->getOriginLangData(),
|
||||
$this->backupService->getBackupObj()->getOriginLangData(),
|
||||
$origMeta,
|
||||
$backupMeta
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates output of difference between backup and original.
|
||||
*
|
||||
* @param array $diff language content (difference between backup and origin)
|
||||
* @param array $metaDiff meta content (difference between backup and origin)
|
||||
* @param array $origLang original language content
|
||||
* @param array $backupLang backup language content
|
||||
* @param array $origOriginLang original origins of each language
|
||||
* @param array $backupOriginLang backup origins of each language
|
||||
* @param array $origMeta original meta content
|
||||
* @param array $backupMeta backup meta content
|
||||
* @return void
|
||||
*/
|
||||
protected function outputManageBackupsDiff(
|
||||
$diff,
|
||||
$metaDiff,
|
||||
$origLang,
|
||||
$backupLang,
|
||||
$origOriginLang,
|
||||
$backupOriginLang,
|
||||
$origMeta,
|
||||
$backupMeta
|
||||
) {
|
||||
$differences = [];
|
||||
|
||||
// meta entry
|
||||
if (count($metaDiff)) {
|
||||
$difference = [];
|
||||
$difference['legend'] = LocalizationUtility::translate('function.backupMgr.diff.meta', 'lfeditor');
|
||||
$difference['constants'] = [];
|
||||
foreach ($metaDiff as $label => $value) {
|
||||
$constant = [];
|
||||
$constant['value'] = $value;
|
||||
$constant['label'] = $label;
|
||||
if (!isset($backupMeta[$label])) {
|
||||
$constant['state'] = self::LANG_CONST_ADDED;
|
||||
} elseif (!isset($origMeta[$label])) {
|
||||
$constant['state'] = self::LANG_CONST_DELETED;
|
||||
} else {
|
||||
$constant['state'] = self::LANG_CONST_NORMAL;
|
||||
}
|
||||
$difference['constants'][] = $constant;
|
||||
}
|
||||
$differences[] = $difference;
|
||||
}
|
||||
|
||||
// loop each language entry
|
||||
foreach ($diff as $langKey => $data) {
|
||||
$difference = [];
|
||||
if (!(is_countable($data) ? count($data) : 0) && ($origOriginLang[$langKey] == $backupOriginLang[$langKey])) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
$languageFile = Typo3Lib::transTypo3File($backupOriginLang[$langKey], FALSE);
|
||||
} catch (\Exception $e) {
|
||||
$languageFile = $backupOriginLang[$langKey];
|
||||
}
|
||||
$difference['legend'] = $langKey . ' (' . $languageFile . ')';
|
||||
$difference['constants'] = [];
|
||||
foreach ($data as $label => $value) {
|
||||
$constant = [];
|
||||
$constant['value'] = $value;
|
||||
$constant['label'] = $label;
|
||||
|
||||
if (!isset($backupLang[$langKey][$label])) {
|
||||
$constant['state'] = self::LANG_CONST_ADDED;
|
||||
} elseif (!isset($origLang[$langKey][$label])) {
|
||||
$constant['state'] = self::LANG_CONST_DELETED;
|
||||
} else {
|
||||
$constant['state'] = self::LANG_CONST_NORMAL;
|
||||
}
|
||||
$difference['constants'][] = $constant;
|
||||
}
|
||||
$differences[] = $difference;
|
||||
}
|
||||
$this->view->assign('differences', $differences);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,198 @@
|
||||
<?php
|
||||
|
||||
namespace SGalinski\Lfeditor\Controller;
|
||||
|
||||
/***************************************************************
|
||||
* 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\Functions;
|
||||
use TYPO3\CMS\Core\Messaging\AbstractMessage;
|
||||
use TYPO3\CMS\Extbase\Utility\LocalizationUtility;
|
||||
|
||||
/**
|
||||
* RenameConstant controller. It contains extbase actions for RenameConstant page.
|
||||
*/
|
||||
class RenameConstantController extends AbstractBackendController {
|
||||
/**
|
||||
* Opens renameConstant view.
|
||||
* It is called in 2 cases:
|
||||
* - on selection of renameConstant option in main menu,
|
||||
* - after redirection from action which must not change the view.
|
||||
*
|
||||
* @throws \TYPO3\CMS\Core\Cache\Exception\NoSuchCacheException
|
||||
*/
|
||||
public function renameConstantAction(): ?\Psr\Http\Message\ResponseInterface {
|
||||
try {
|
||||
$this->view->assign('controllerName', 'RenameConstant');
|
||||
|
||||
$this->prepareExtensionAndLangFileOptions();
|
||||
$this->configurationService->initFileObject(
|
||||
$this->session->getDataByKey('languageFileSelection'),
|
||||
$this->session->getDataByKey('extensionSelection')
|
||||
);
|
||||
$langData = $this->configurationService->getFileObj()->getLocalLangData();
|
||||
$constantOptions = $this->configurationService->menuConstList(
|
||||
$langData,
|
||||
LocalizationUtility::translate('select.nothing', 'lfeditor')
|
||||
);
|
||||
$this->assignViewWidthMenuVariables('constant', $constantOptions);
|
||||
$this->prepareRenameConstantViewMainSectionContent();
|
||||
} catch (LFException $e) {
|
||||
$this->addLFEFlashMessage($e);
|
||||
}
|
||||
$this->commonViewRenderingActionSettings();
|
||||
if (version_compare(\TYPO3\CMS\Core\Utility\VersionNumberUtility::getCurrentTypo3Version(), '11.0.0', '<')) {
|
||||
$this->view->assign('V11', FALSE);
|
||||
return NULL;
|
||||
} else {
|
||||
$this->view->assign('V11', TRUE);
|
||||
return $this->createBackendResponse();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This action saves in session currently selected options from selection menus in renameConstant view.
|
||||
* It is called on change of selection of any select menu in renameConstant view.
|
||||
*
|
||||
* @param string $extensionSelection
|
||||
* @param string $languageFileSelection
|
||||
* @param string $constantSelection
|
||||
* @param string $extKey
|
||||
* @throws \TYPO3\CMS\Extbase\Mvc\Exception\StopActionException
|
||||
*/
|
||||
public function changeSelectionAction(
|
||||
$extensionSelection = NULL,
|
||||
$languageFileSelection = NULL,
|
||||
$constantSelection = NULL,
|
||||
$extKey = ''
|
||||
): ?\Psr\Http\Message\ResponseInterface {
|
||||
$this->saveSelectionsInSession(
|
||||
$extensionSelection,
|
||||
$languageFileSelection,
|
||||
NULL,
|
||||
$constantSelection,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
$extKey
|
||||
);
|
||||
|
||||
if (version_compare(\TYPO3\CMS\Core\Utility\VersionNumberUtility::getCurrentTypo3Version(), '11.0.0', '<')) {
|
||||
$this->redirect('renameConstant');
|
||||
return NULL;
|
||||
} else {
|
||||
return $this->redirect('renameConstant');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the changes made in main section of renameConstant view.
|
||||
*
|
||||
* @param string $newConstantName
|
||||
*/
|
||||
public function renameConstantSaveAction($newConstantName): ?\Psr\Http\Message\ResponseInterface {
|
||||
try {
|
||||
$oldConstantName = $this->session->getDataByKey('constantSelection');
|
||||
$extConfig = $this->configurationService->getExtConfig();
|
||||
|
||||
if ($oldConstantName === $newConstantName) {
|
||||
throw new LFException('failure.langfile.noChange');
|
||||
}
|
||||
|
||||
$this->configurationService->initFileObject(
|
||||
$this->session->getDataByKey('languageFileSelection'),
|
||||
$this->session->getDataByKey('extensionSelection')
|
||||
);
|
||||
|
||||
$langData = $this->configurationService->getFileObj()->getLocalLangData();
|
||||
$constExists = !empty($langData['default'][$newConstantName])
|
||||
|| !empty($langData[$extConfig['defaultLanguage']][$newConstantName]);
|
||||
if ($constExists) {
|
||||
throw new LFException('failure.langfile.constExists');
|
||||
}
|
||||
|
||||
$langArray = Functions::buildLangArray();
|
||||
$newLang = [];
|
||||
foreach ($langArray as $lang) {
|
||||
if (isset($langData[$lang][$oldConstantName])) {
|
||||
$newLang[$lang][$newConstantName] = $langData[$lang][$oldConstantName];
|
||||
}
|
||||
$newLang[$lang][$oldConstantName] = '';
|
||||
}
|
||||
|
||||
$this->configurationService->execWrite($newLang, [], TRUE);
|
||||
|
||||
$this->addFlashMessage(
|
||||
LocalizationUtility::translate('lang.file.write.success', 'lfeditor'),
|
||||
'',
|
||||
$severity = AbstractMessage::OK,
|
||||
$storeInSession = TRUE
|
||||
);
|
||||
} catch (LFException $e) {
|
||||
$this->addLFEFlashMessage($e);
|
||||
}
|
||||
|
||||
if (version_compare(\TYPO3\CMS\Core\Utility\VersionNumberUtility::getCurrentTypo3Version(), '11.0.0', '<')) {
|
||||
$this->redirect('renameConstant');
|
||||
return NULL;
|
||||
} else {
|
||||
return $this->redirect('renameConstant');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears extensionAndLangFileOptions cache, and in that way refreshes list of language file options in select box.
|
||||
*
|
||||
* @return \Psr\Http\Message\ResponseInterface|null
|
||||
* @throws \TYPO3\CMS\Core\Cache\Exception\NoSuchCacheException
|
||||
* @throws \TYPO3\CMS\Extbase\Mvc\Exception\StopActionException
|
||||
*/
|
||||
public function refreshLanguageFileListAction(): ?\Psr\Http\Message\ResponseInterface {
|
||||
$this->clearSelectOptionsCache('extensionAndLangFileOptions');
|
||||
|
||||
if (version_compare(\TYPO3\CMS\Core\Utility\VersionNumberUtility::getCurrentTypo3Version(), '11.0.0', '<')) {
|
||||
$this->redirect('renameConstant');
|
||||
return NULL;
|
||||
} else {
|
||||
return $this->redirect('renameConstant');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares main section content of deleteConstant view.
|
||||
*
|
||||
* @throws LFException
|
||||
* @return void
|
||||
*/
|
||||
protected function prepareRenameConstantViewMainSectionContent() {
|
||||
$constantSelection = $this->session->getDataByKey('constantSelection');
|
||||
if (empty($constantSelection) || $constantSelection === '###default###') {
|
||||
throw new LFException('failure.select.noConst', 1);
|
||||
}
|
||||
|
||||
$this->view->assign('constantSelection', $constantSelection);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,182 @@
|
||||
<?php
|
||||
|
||||
namespace SGalinski\Lfeditor\Controller;
|
||||
|
||||
/***************************************************************
|
||||
* 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 TYPO3\CMS\Extbase\Mvc\Exception\UnsupportedRequestTypeException;
|
||||
|
||||
/**
|
||||
* SearchConstant controller. It contains extbase actions for SearchConstant page.
|
||||
*/
|
||||
class SearchConstantController extends AbstractBackendController {
|
||||
/**
|
||||
* Opens searchConstant view.
|
||||
* It is called in 2 cases:
|
||||
* - on selection of searchConstant option in main menu,
|
||||
* - after redirection from action which must not change the view.
|
||||
*
|
||||
* @param bool $searchDone
|
||||
* @throws \TYPO3\CMS\Core\Cache\Exception\NoSuchCacheException
|
||||
*/
|
||||
public function searchConstantAction($searchDone = FALSE): ?\Psr\Http\Message\ResponseInterface {
|
||||
try {
|
||||
$this->view->assign('controllerName', 'SearchConstant');
|
||||
|
||||
$this->prepareExtensionAndLangFileOptions();
|
||||
$this->prepareSearchConstantViewMainSectionContent($searchDone);
|
||||
} catch (LFException $e) {
|
||||
$this->addLFEFlashMessage($e);
|
||||
}
|
||||
$this->commonViewRenderingActionSettings();
|
||||
if (version_compare(\TYPO3\CMS\Core\Utility\VersionNumberUtility::getCurrentTypo3Version(), '11.0.0', '<')) {
|
||||
$this->view->assign('V11', FALSE);
|
||||
return NULL;
|
||||
} else {
|
||||
$this->view->assign('V11', TRUE);
|
||||
return $this->createBackendResponse();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This action saves in session currently selected options from selection menus in searchConstant view.
|
||||
* It is called on change of selection of any select menu in searchConstant view.
|
||||
*
|
||||
* @param string $extensionSelection
|
||||
* @param string $languageFileSelection
|
||||
* @param string $extKey
|
||||
* @throws \TYPO3\CMS\Extbase\Mvc\Exception\StopActionException
|
||||
*/
|
||||
public function changeSelectionAction($extensionSelection = NULL, $languageFileSelection = NULL, $extKey = ''): ?\Psr\Http\Message\ResponseInterface {
|
||||
$this->saveSelectionsInSession(
|
||||
$extensionSelection,
|
||||
$languageFileSelection,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
$extKey
|
||||
);
|
||||
|
||||
if (version_compare(\TYPO3\CMS\Core\Utility\VersionNumberUtility::getCurrentTypo3Version(), '11.0.0', '<')) {
|
||||
$this->redirect('searchConstant');
|
||||
return NULL;
|
||||
} else {
|
||||
return $this->redirect('searchConstant');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the changes made in main section of searchConstant view.
|
||||
*
|
||||
* @param boolean $caseSensitive
|
||||
* @param string $searchStr
|
||||
*/
|
||||
public function searchConstantSearchAction($caseSensitive, $searchStr): ?\Psr\Http\Message\ResponseInterface {
|
||||
$searchResultArray = [];
|
||||
try {
|
||||
$this->configurationService->initFileObject(
|
||||
$this->session->getDataByKey('languageFileSelection'),
|
||||
$this->session->getDataByKey('extensionSelection')
|
||||
);
|
||||
$langData = $this->configurationService->getFileObj()->getLocalLangData();
|
||||
$viewLanguages = $this->configurationService->getLangArray($this->backendUser);
|
||||
|
||||
$searchOptions = $caseSensitive ? '' : 'i';
|
||||
if (!preg_match('/^\/.*\/.*$/', $searchStr) && !empty($searchStr)) {
|
||||
foreach ($viewLanguages as $langKey) {
|
||||
if (!array_key_exists($langKey, $langData) || !is_array($langData[$langKey])) {
|
||||
continue;
|
||||
}
|
||||
foreach ($langData[$langKey] as $labelKey => $labelValue) {
|
||||
$labelKeyOrValueContainSearchStr = preg_match(
|
||||
'/' . $searchStr . '/' . $searchOptions,
|
||||
$labelKey
|
||||
) || preg_match('/' . $searchStr . '/' . $searchOptions, $labelValue);
|
||||
if ($labelKeyOrValueContainSearchStr) {
|
||||
$searchResultArray[$langKey][$labelKey] = $labelValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!count($searchResultArray)) {
|
||||
throw new LFException('failure.search.noConstants', 1);
|
||||
}
|
||||
} else {
|
||||
throw new LFException('function.const.search.enterSearchStr', 1);
|
||||
}
|
||||
} catch (LFException $e) {
|
||||
$this->addLFEFlashMessage($e);
|
||||
}
|
||||
$this->session->setDataByKey('searchResultArray', $searchResultArray);
|
||||
$this->session->setDataByKey('searchString', $searchStr);
|
||||
$this->session->setDataByKey('searchCaseSensitive', $caseSensitive);
|
||||
|
||||
if (version_compare(\TYPO3\CMS\Core\Utility\VersionNumberUtility::getCurrentTypo3Version(), '11.0.0', '<')) {
|
||||
$this->redirect('searchConstant', NULL, NULL, ['searchDone' => TRUE]);
|
||||
return NULL;
|
||||
} else {
|
||||
return $this->redirect('searchConstant', NULL, NULL, ['searchDone' => TRUE]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears extensionAndLangFileOptions cache, and in that way refreshes list of language file options in select box.
|
||||
*
|
||||
*/
|
||||
public function refreshLanguageFileListAction(): ?\Psr\Http\Message\ResponseInterface {
|
||||
$this->clearSelectOptionsCache('extensionAndLangFileOptions');
|
||||
|
||||
if (version_compare(\TYPO3\CMS\Core\Utility\VersionNumberUtility::getCurrentTypo3Version(), '11.0.0', '<')) {
|
||||
$this->redirect('searchConstant', NULL, NULL, ['searchDone' => TRUE]);
|
||||
return NULL;
|
||||
} else {
|
||||
return $this->redirect('searchConstant', NULL, NULL, ['searchDone' => TRUE]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares main section content of searchConstant view.
|
||||
*
|
||||
* @param bool $searchDone
|
||||
* @return void
|
||||
*/
|
||||
protected function prepareSearchConstantViewMainSectionContent($searchDone) {
|
||||
$searchResultArray = [];
|
||||
if ($searchDone) {
|
||||
$searchResultArray = $this->session->getDataByKey('searchResultArray');
|
||||
} else {
|
||||
$this->session->setDataByKey('searchResultArray', []);
|
||||
}
|
||||
$searchString = $this->session->getDataByKey('searchString');
|
||||
$searchCaseSensitive = $this->session->getDataByKey('searchCaseSensitive');
|
||||
|
||||
$this->view->assign('searchResultArray', $searchResultArray);
|
||||
$this->view->assign('searchString', $searchString);
|
||||
$this->view->assign('searchCaseSensitive', $searchCaseSensitive);
|
||||
}
|
||||
}
|
||||
283
typo3conf/ext/lfeditor/Classes/Controller/ViewTreeController.php
Normal file
283
typo3conf/ext/lfeditor/Classes/Controller/ViewTreeController.php
Normal file
@@ -0,0 +1,283 @@
|
||||
<?php
|
||||
|
||||
namespace SGalinski\Lfeditor\Controller;
|
||||
|
||||
/***************************************************************
|
||||
* 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\Functions;
|
||||
use TYPO3\CMS\Extbase\Mvc\Exception\UnsupportedRequestTypeException;
|
||||
use TYPO3\CMS\Extbase\Utility\LocalizationUtility;
|
||||
|
||||
/**
|
||||
* ViewTree controller. It contains extbase actions for ViewTree page.
|
||||
*/
|
||||
class ViewTreeController extends AbstractBackendController {
|
||||
/*********************************************
|
||||
* Actions called from viewTree view *
|
||||
*********************************************/
|
||||
|
||||
/**
|
||||
* Opens viewTree view.
|
||||
* It is called in 2 cases:
|
||||
* - on selection of viewTree option in main menu,
|
||||
* - after redirection from action which must not change the view.
|
||||
*
|
||||
*/
|
||||
public function viewTreeAction(): ?\Psr\Http\Message\ResponseInterface {
|
||||
try {
|
||||
$this->view->assign('controllerName', 'ViewTree');
|
||||
|
||||
$this->prepareExtensionAndLangFileOptions();
|
||||
$this->configurationService->initFileObject(
|
||||
$this->session->getDataByKey('languageFileSelection'),
|
||||
$this->session->getDataByKey('extensionSelection')
|
||||
);
|
||||
$languageOptions = $this->configurationService->menuLangList(
|
||||
$this->configurationService->getFileObj()->getLocalLangData(),
|
||||
'',
|
||||
$this->backendUser
|
||||
);
|
||||
$this->assignViewWidthMenuVariables('language', $languageOptions);
|
||||
$referenceLanguageOptions = $this->configurationService->menuLangList(
|
||||
$this->configurationService->getFileObj()->getLocalLangData(),
|
||||
LocalizationUtility::translate('select.nothing', 'lfeditor'),
|
||||
$this->backendUser
|
||||
);
|
||||
$this->assignViewWidthMenuVariables('referenceLanguage', $referenceLanguageOptions);
|
||||
$this->prepareViewTreeViewMainSectionContent();
|
||||
} catch (LFException $e) {
|
||||
$this->addLFEFlashMessage($e);
|
||||
}
|
||||
$this->commonViewRenderingActionSettings();
|
||||
if (version_compare(\TYPO3\CMS\Core\Utility\VersionNumberUtility::getCurrentTypo3Version(), '11.0.0', '<')) {
|
||||
$this->view->assign('V11', FALSE);
|
||||
return NULL;
|
||||
} else {
|
||||
$this->view->assign('V11', TRUE);
|
||||
return $this->createBackendResponse();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This action saves in session currently selected options from selection menus in viewTree view.
|
||||
* It is called on change of selection of any select menu in viewTree view.
|
||||
*
|
||||
* @param string $extensionSelection
|
||||
* @param string $languageFileSelection
|
||||
* @param string $languageSelection
|
||||
* @param string $referenceLanguageSelection
|
||||
* @param string $extKey
|
||||
* @throws \TYPO3\CMS\Extbase\Mvc\Exception\StopActionException
|
||||
*/
|
||||
public function changeSelectionAction(
|
||||
$extensionSelection = NULL,
|
||||
$languageFileSelection = NULL,
|
||||
$languageSelection = NULL,
|
||||
$referenceLanguageSelection = NULL,
|
||||
$extKey = ''
|
||||
): ?\Psr\Http\Message\ResponseInterface {
|
||||
$this->saveSelectionsInSession(
|
||||
$extensionSelection,
|
||||
$languageFileSelection,
|
||||
$referenceLanguageSelection,
|
||||
NULL,
|
||||
NULL,
|
||||
$languageSelection,
|
||||
NULL,
|
||||
NULL,
|
||||
$extKey
|
||||
);
|
||||
|
||||
|
||||
if (version_compare(\TYPO3\CMS\Core\Utility\VersionNumberUtility::getCurrentTypo3Version(), '11.0.0', '<')) {
|
||||
$this->redirect('viewTree');
|
||||
return NULL;
|
||||
} else {
|
||||
return $this->redirect('viewTree');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Selects explodeToken.
|
||||
*
|
||||
* @param string $explodeToken
|
||||
* @throws \TYPO3\CMS\Extbase\Mvc\Exception\StopActionException
|
||||
*/
|
||||
public function selectExplodeTokenAction($explodeToken): ?\Psr\Http\Message\ResponseInterface {
|
||||
$this->session->setDataByKey('explodeToken', $explodeToken);
|
||||
|
||||
if (version_compare(\TYPO3\CMS\Core\Utility\VersionNumberUtility::getCurrentTypo3Version(), '11.0.0', '<')) {
|
||||
$this->redirect('viewTree');
|
||||
return NULL;
|
||||
} else {
|
||||
return $this->redirect('viewTree');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears extensionAndLangFileOptions cache, and in that way refreshes list of language file options in select box.
|
||||
*
|
||||
*/
|
||||
public function refreshLanguageFileListAction(): ?\Psr\Http\Message\ResponseInterface {
|
||||
$this->clearSelectOptionsCache('extensionAndLangFileOptions');
|
||||
if (version_compare(\TYPO3\CMS\Core\Utility\VersionNumberUtility::getCurrentTypo3Version(), '11.0.0', '<')) {
|
||||
$this->redirect('viewTree');
|
||||
return NULL;
|
||||
} else {
|
||||
return $this->redirect('viewTree');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares main section content of viewTree view.
|
||||
*
|
||||
*/
|
||||
protected function prepareViewTreeViewMainSectionContent(): void {
|
||||
$explodeToken = $this->session->getDataByKey('explodeToken');
|
||||
if ($explodeToken === "") {
|
||||
$explodeToken = '.';
|
||||
}
|
||||
|
||||
$langData = $this->configurationService->getFileObj()->getLocalLangData();
|
||||
$refLangSelection = $this->session->getDataByKey('referenceLanguageSelection');
|
||||
$languageSelection = $this->session->getDataByKey('languageSelection');
|
||||
$tree = Functions::genTreeInfoArray($langData[$languageSelection] ?? [], $langData[$refLangSelection] ?? [], $explodeToken);
|
||||
$extConfig = $this->configurationService->getExtConfig();
|
||||
$treeHide = $extConfig['treeHide'];
|
||||
|
||||
$fluidTree = [];
|
||||
$levelIndex = 0;
|
||||
$this->addLevelElementsToFluidTree($tree, $levelIndex, NULL, $fluidTree, $treeHide);
|
||||
|
||||
$this->view->assign('fluidTree', $fluidTree);
|
||||
$this->view->assign('treeHide', $treeHide);
|
||||
$this->view->assign('explodeToken', $explodeToken);
|
||||
}
|
||||
|
||||
/**
|
||||
* @var integer Width of margin which is added if a branch is missing.
|
||||
*/
|
||||
protected $marginLeftSpaceUnit = 18;
|
||||
|
||||
/**
|
||||
* Makes tree structure which contains constants. The structure is optimised for recursive use on fluid pages.
|
||||
*
|
||||
* @param array $sourceTree
|
||||
* @param int $level
|
||||
* @param string $parentKey
|
||||
* @param array $fluidTree This structure is used for setting tree-data for use in fluid.
|
||||
* @param boolean $treeHide Default state of tree (TRUE - hidden, FALSE - opened)
|
||||
* @throws LFException
|
||||
* @return void
|
||||
*/
|
||||
protected function addLevelElementsToFluidTree(
|
||||
array $sourceTree,
|
||||
int $level,
|
||||
$parentKey,
|
||||
array &$fluidTree,
|
||||
$treeHide
|
||||
) {
|
||||
if (empty($sourceTree)) {
|
||||
throw new LFException('failure.select.emptyLanguage', 1);
|
||||
}
|
||||
$constKeys = array_keys($sourceTree[$level]);
|
||||
$index = 0;
|
||||
foreach ($sourceTree[$level] as $constKey => $treeNode) {
|
||||
if ($level === 0 || $treeNode['parent'] === $parentKey) {
|
||||
$fluidTreeElem = [];
|
||||
$fluidTreeElem['label'] = $treeNode['name'];
|
||||
$fluidTreeElem['parent'] = $fluidTree; //$treeNode['parent'];//; //
|
||||
$fluidTreeElem['type'] = $treeNode['type'] ?? '';
|
||||
$fluidTreeElem['isBottom'] = (!array_key_exists($index + 1, $constKeys) ||
|
||||
$sourceTree[$level][$constKeys[$index + 1]]['parent'] !== $treeNode['parent']) ? 1 : 0;
|
||||
|
||||
$icons = $this->prepareTreeIcons($level, $treeHide, $fluidTreeElem, isset($treeNode['childs']));
|
||||
$fluidTreeElem['icons'] = $icons;
|
||||
|
||||
if (array_key_exists($level + 1, $sourceTree)) {
|
||||
$this->addLevelElementsToFluidTree(
|
||||
$sourceTree,
|
||||
$level + 1,
|
||||
$constKey,
|
||||
$fluidTreeElem,
|
||||
$treeHide
|
||||
);
|
||||
}
|
||||
if ($level > 0) {
|
||||
$fluidTree['children'][$constKey] = $fluidTreeElem;
|
||||
} else {
|
||||
$fluidTree[$constKey] = $fluidTreeElem;
|
||||
}
|
||||
}
|
||||
$index++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sorts and adds icons in tree structure.
|
||||
*
|
||||
* @param int $level Tree level of constant.
|
||||
* @param boolean $treeHide Indicator which shows should all tree elements be closed (hidden) by default.
|
||||
* @param array $fluidTreeElem Element of tree which is built for use on fluid page.
|
||||
* @param boolean $hasChildren Indicator does this tree element have children
|
||||
* @return array
|
||||
*/
|
||||
protected function prepareTreeIcons(int $level, $treeHide, array $fluidTreeElem, $hasChildren): array {
|
||||
$icons = [];
|
||||
$leftMargins = [];
|
||||
$marginLeftSpaceCounter = 0;
|
||||
for ($iconLevel = $level, $currentFluidTreeElem = $fluidTreeElem;
|
||||
$currentFluidTreeElem;
|
||||
$iconLevel--, $currentFluidTreeElem = $currentFluidTreeElem['parent']) {
|
||||
$iconName = '.png';
|
||||
if ($iconLevel === $level) {
|
||||
if ($currentFluidTreeElem['isBottom']) {
|
||||
$iconName = 'Bottom' . $iconName;
|
||||
}
|
||||
if ($hasChildren) {
|
||||
$iconName = 'tree' . ($treeHide && $level != 0 ? 'Plus' : 'Minus') . $iconName;
|
||||
} else {
|
||||
$iconName = 'join' . $iconName;
|
||||
}
|
||||
} else {
|
||||
if (!$currentFluidTreeElem['isBottom']) {
|
||||
$iconName = 'line' . $iconName;
|
||||
$leftMargins[] = $marginLeftSpaceCounter;
|
||||
$marginLeftSpaceCounter = 0;
|
||||
} else {
|
||||
$marginLeftSpaceCounter += $this->marginLeftSpaceUnit;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
$icons[] = ['name' => $iconName];
|
||||
}
|
||||
$leftMargins[] = $marginLeftSpaceCounter;
|
||||
for ($iterator = 0, $iconsSize = count($icons); $iterator < $iconsSize; $iterator++) {
|
||||
$icons[$iterator]['marginLeft'] = $leftMargins[$iterator];
|
||||
}
|
||||
return $icons;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* 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!
|
||||
*/
|
||||
|
||||
namespace SGalinski\Lfeditor\Exceptions;
|
||||
|
||||
use TYPO3\CMS\Extbase\Utility\LocalizationUtility;
|
||||
|
||||
/**
|
||||
* DirectoryAccessRightsException can be thrown for exceptions relating to file access and write permissions
|
||||
* in directories
|
||||
*
|
||||
* @package SGalinski\Lfeditor\Exceptions
|
||||
* @author Kevin Ditscheid <kevin.ditscheid@sgalinski.de>
|
||||
*/
|
||||
class DirectoryAccessRightsException extends \Exception {
|
||||
/**
|
||||
* DirectoryAccessRightsException constructor.
|
||||
*
|
||||
* @param string $message
|
||||
* @param int $code
|
||||
* @param \Exception|NULL $previous
|
||||
*/
|
||||
public function __construct($message = '', $code = 0, $previous = NULL) {
|
||||
if (\strpos($message, 'LLL:') === 0) {
|
||||
$locallizedMessage = LocalizationUtility::translate($message, 'lfeditor');
|
||||
$message = $locallizedMessage ?? $message;
|
||||
}
|
||||
|
||||
if ($message === '') {
|
||||
$message = 'LFExeption: no error message given !!!';
|
||||
}
|
||||
|
||||
parent::__construct($message, $code, $previous);
|
||||
}
|
||||
}
|
||||
54
typo3conf/ext/lfeditor/Classes/Exceptions/LFException.php
Normal file
54
typo3conf/ext/lfeditor/Classes/Exceptions/LFException.php
Normal file
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
namespace SGalinski\Lfeditor\Exceptions;
|
||||
|
||||
/***************************************************************
|
||||
* 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 Exception;
|
||||
use TYPO3\CMS\Extbase\Utility\LocalizationUtility;
|
||||
|
||||
/**
|
||||
* adds a new error exception
|
||||
*/
|
||||
class LFException extends Exception {
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param string $msg error message (this message would be translated by TYPO3)
|
||||
* @param integer $severityCode (0 = error (default), 1 = notice)
|
||||
* @param string $staticMsg static message (appended at the localized string)
|
||||
*/
|
||||
public function __construct($msg, $severityCode = 0, $staticMsg = '') {
|
||||
if (!empty($msg)) {
|
||||
$msg = LocalizationUtility::translate($msg, 'lfeditor');
|
||||
}
|
||||
|
||||
if (empty($msg)) {
|
||||
$msg = 'LFExeption: no error message given !!!';
|
||||
}
|
||||
|
||||
parent::__construct($msg . ' ' . $staticMsg, $severityCode);
|
||||
}
|
||||
}
|
||||
49
typo3conf/ext/lfeditor/Classes/Service/AbstractService.php
Normal file
49
typo3conf/ext/lfeditor/Classes/Service/AbstractService.php
Normal file
@@ -0,0 +1,49 @@
|
||||
<?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\Session\PhpSession;
|
||||
use TYPO3\CMS\Core\SingletonInterface;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
|
||||
/**
|
||||
* Class AbstractService
|
||||
*/
|
||||
abstract class AbstractService implements SingletonInterface {
|
||||
/**
|
||||
* @var PhpSession
|
||||
*/
|
||||
protected $session;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct() {
|
||||
$this->session = GeneralUtility::makeInstance(PhpSession::class);
|
||||
$this->session->setSessionKey('tx_lfeditor_sessionVariables');
|
||||
}
|
||||
}
|
||||
316
typo3conf/ext/lfeditor/Classes/Service/BackupService.php
Normal file
316
typo3conf/ext/lfeditor/Classes/Service/BackupService.php
Normal file
@@ -0,0 +1,316 @@
|
||||
<?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 Exception;
|
||||
use SGalinski\Lfeditor\Exceptions\LFException;
|
||||
use SGalinski\Lfeditor\Utility\Functions;
|
||||
use SGalinski\Lfeditor\Utility\SgLib;
|
||||
use SGalinski\Lfeditor\Utility\Typo3Lib;
|
||||
use TYPO3\CMS\Core\Core\Environment;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
|
||||
/**
|
||||
* Class BackupService
|
||||
*/
|
||||
class BackupService extends AbstractService {
|
||||
/**
|
||||
* @var \SGalinski\Lfeditor\Service\FileBackupService $backupObj
|
||||
*/
|
||||
private $backupObj;
|
||||
|
||||
/**
|
||||
* init backup object
|
||||
*
|
||||
* @throws LFException raised if directories cant be created or backup class instantiated
|
||||
* @throws Exception|LFException
|
||||
* @param string $mode workspace
|
||||
* @param boolean|array $infos set to true if you want use information from the file object
|
||||
* @return void
|
||||
*/
|
||||
public function initBackupObject($mode = 'base', $infos = NULL) {
|
||||
$informations = [];
|
||||
$mode = ($mode ?: 'base');
|
||||
/** @var ConfigurationService $confService */
|
||||
$confService = GeneralUtility::makeInstance(ConfigurationService::class);
|
||||
|
||||
// create backup and meta directory
|
||||
$extConfig = $confService->getExtConfig();
|
||||
$pathSite = Environment::getPublicPath() . '/';
|
||||
try {
|
||||
SgLib::createDir($extConfig['pathBackup'], $pathSite);
|
||||
SgLib::createDir(dirname($extConfig['metaFile']), $pathSite);
|
||||
} catch (Exception $e) {
|
||||
throw new LFException('failure.failure', 0, '(' . $e->getMessage() . ')');
|
||||
}
|
||||
|
||||
// get information
|
||||
$extPath = '';
|
||||
$langFile = '';
|
||||
if (!is_array($infos)) {
|
||||
// build language file and extension path
|
||||
if ($mode == 'xlf') {
|
||||
try {
|
||||
$typo3RelFile = $confService->getFileObj()->getVar('typo3RelFile');
|
||||
$typo3AbsFile = Typo3Lib::transTypo3File($typo3RelFile, TRUE);
|
||||
} catch (Exception $e) {
|
||||
throw new LFException('failure.failure', 0, '(' . $e->getMessage() . ')');
|
||||
}
|
||||
|
||||
$langFile = SgLib::trimPath('EXT:', $typo3RelFile);
|
||||
$langFile = substr($langFile, strpos($langFile, '/') + 1);
|
||||
|
||||
$extPath = SgLib::trimPath(
|
||||
$langFile,
|
||||
SgLib::trimPath(
|
||||
$pathSite,
|
||||
$typo3AbsFile
|
||||
),
|
||||
'/'
|
||||
);
|
||||
} else {
|
||||
$extPath = SgLib::trimPath($pathSite, $confService->getFileObj()->getVar('absPath'), '/');
|
||||
$langFile = $confService->getFileObj()->getVar('relFile');
|
||||
}
|
||||
|
||||
// set data information
|
||||
$informations['localLang'] = $confService->getFileObj()->getLocalLangData();
|
||||
$informations['originLang'] = $confService->getFileObj()->getOriginLangData();
|
||||
$informations['meta'] = $confService->getFileObj()->getMetaData();
|
||||
}
|
||||
|
||||
// set information
|
||||
$informations['workspace'] = $mode;
|
||||
$informations['extPath'] = is_array($infos) ? $infos['extPath'] : $extPath;
|
||||
$informations['langFile'] = is_array($infos) ? $infos['langFile'] : $langFile;
|
||||
|
||||
// create and initialize the backup object
|
||||
try {
|
||||
$this->backupObj = GeneralUtility::makeInstance(FileBackupService::class);
|
||||
$this->backupObj->init('', $extConfig['pathBackup'], $extConfig['metaFile']);
|
||||
$this->backupObj->setVar($informations);
|
||||
} catch (LFException $e) {
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* executes the deletion of backup files
|
||||
*
|
||||
* @throws LFException raised if a backup file couldnt be deleted
|
||||
* @param array $delFiles files as key and the language file as value
|
||||
* @return void
|
||||
*/
|
||||
public function execBackupDelete($delFiles) {
|
||||
// delete files
|
||||
try {
|
||||
foreach ($delFiles as $filename => $langFile) {
|
||||
$this->backupObj->deleteSpecFile($filename, '', $langFile);
|
||||
}
|
||||
} catch (LFException $e) {
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* restores a backup file
|
||||
*
|
||||
* @throws LFException raised if some unneeded files couldnt be deleted
|
||||
* @throws Exception|LFException
|
||||
* @return void
|
||||
*/
|
||||
public function execBackupRestore() {
|
||||
/** @var ConfigurationService $confService */
|
||||
$confService = GeneralUtility::makeInstance(ConfigurationService::class);
|
||||
|
||||
// get vars
|
||||
$localLang = [];
|
||||
$meta = [];
|
||||
$origLang = $confService->getFileObj()->getLocalLangData();
|
||||
$origMeta = $confService->getFileObj()->getMetaData();
|
||||
$backupMeta = $this->backupObj->getMetaData();
|
||||
$backupLocalLang = $this->backupObj->getLocalLangData();
|
||||
$backupOriginLang = $this->backupObj->getOriginLangData();
|
||||
|
||||
// get differences between original and backup file
|
||||
$origDiff = Functions::getBackupDiff(1, $origLang, $backupLocalLang);
|
||||
$backupDiff = Functions::getBackupDiff(2, $origLang, $backupLocalLang);
|
||||
|
||||
if (is_countable($origDiff) ? count($origDiff) : 0) {
|
||||
foreach ($origDiff as $langKey => $data) {
|
||||
foreach ($data as $label => $value) {
|
||||
if (isset($backupLocalLang[$langKey][$label])) {
|
||||
$localLang[$langKey][$label] = $value;
|
||||
} else {
|
||||
$localLang[$langKey][$label] = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (is_countable($backupDiff) ? count($backupDiff) : 0) {
|
||||
foreach ($backupDiff as $langKey => $data) {
|
||||
foreach ($data as $label => $value) {
|
||||
$localLang[$langKey][$label] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// get differences between original and backup meta
|
||||
SgLib::fixMetaAttributes($origMeta);
|
||||
$origDiff = Functions::getMetaDiff(1, $origMeta, $backupMeta);
|
||||
$backupDiff = Functions::getMetaDiff(2, $origMeta, $backupMeta);
|
||||
|
||||
if (is_countable($origDiff) ? count($origDiff) : 0) {
|
||||
foreach ($origDiff as $label => $value) {
|
||||
if (isset($backupMeta[$label])) {
|
||||
$meta[$label] = $value;
|
||||
} else {
|
||||
$meta[$label] = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (is_countable($backupDiff) ? count($backupDiff) : 0) {
|
||||
foreach ($backupDiff as $label => $value) {
|
||||
$meta[$label] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
// restore origins of languages
|
||||
$deleteFiles = [];
|
||||
foreach ($backupOriginLang as $langKey => $file) {
|
||||
$curFile = $confService->getFileObj()->getOriginLangData($langKey);
|
||||
if ($curFile != $file && $curFile != $confService->getFileObj()->getVar('absFile')) {
|
||||
$deleteFiles[] = $curFile;
|
||||
}
|
||||
$confService->getFileObj()->setOriginLangData($file, $langKey);
|
||||
}
|
||||
|
||||
// write modified language array
|
||||
try {
|
||||
$confService->setExecBackup(0);
|
||||
$confService->execWrite($localLang, $meta, TRUE);
|
||||
} catch (LFException $e) {
|
||||
throw $e;
|
||||
}
|
||||
|
||||
// delete all old files
|
||||
try {
|
||||
if (count($deleteFiles)) {
|
||||
SgLib::deleteFiles($deleteFiles);
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
throw new LFException(
|
||||
'failure.langfile.notDeleted',
|
||||
0,
|
||||
'(' . $e->getMessage() . ')'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* exec the backup of files and deletes automatic old files
|
||||
*
|
||||
* @throws LFException raised if backup file cant written or unneeded files cant deleted
|
||||
* @return boolean
|
||||
*/
|
||||
public function execBackup() {
|
||||
$createdAt = [];
|
||||
/** @var ConfigurationService $confService */
|
||||
$confService = GeneralUtility::makeInstance(ConfigurationService::class);
|
||||
|
||||
// create backup object
|
||||
try {
|
||||
$this->initBackupObject('base', TRUE);
|
||||
} catch (LFException $e) {
|
||||
throw $e;
|
||||
}
|
||||
|
||||
// write backup file
|
||||
try {
|
||||
$this->backupObj->writeFile();
|
||||
} catch (LFException $e) {
|
||||
throw $e;
|
||||
}
|
||||
|
||||
// exec automatic deletion of backup files, if anzBackup greater zero
|
||||
$extConfig = $confService->getExtConfig();
|
||||
if ($extConfig['anzBackup'] <= 0) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// get difference information
|
||||
$metaArray = $this->backupObj->getMetaInfos(3);
|
||||
$rows = count($metaArray);
|
||||
$dif = $rows - $extConfig['anzBackup'];
|
||||
|
||||
if ($dif <= 0) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// sort metaArray
|
||||
foreach ($metaArray as $key => $row) {
|
||||
$createdAt[$key] = $row['createdAt'];
|
||||
}
|
||||
array_multisort($createdAt, SORT_DESC, $metaArray);
|
||||
|
||||
// get filenames
|
||||
$files = array_keys($metaArray);
|
||||
$numberFiles = count($files);
|
||||
|
||||
// delete files
|
||||
try {
|
||||
for (; $dif > 0; --$dif, --$numberFiles) {
|
||||
$this->backupObj->deleteSpecFile($files[$numberFiles - 1]);
|
||||
}
|
||||
} catch (LFException $e) {
|
||||
try { // delete current written file
|
||||
$this->backupObj->deleteFile();
|
||||
} catch (LFException $e) {
|
||||
throw $e;
|
||||
}
|
||||
throw $e;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return FileBackupService
|
||||
*/
|
||||
public function getBackupObj() {
|
||||
return $this->backupObj;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param FileBackupService $backupObj
|
||||
*/
|
||||
public function setBackupObj($backupObj) {
|
||||
$this->backupObj = $backupObj;
|
||||
}
|
||||
}
|
||||
843
typo3conf/ext/lfeditor/Classes/Service/ConfigurationService.php
Normal file
843
typo3conf/ext/lfeditor/Classes/Service/ConfigurationService.php
Normal file
@@ -0,0 +1,843 @@
|
||||
<?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 Exception;
|
||||
use SGalinski\Lfeditor\Exceptions\DirectoryAccessRightsException;
|
||||
use SGalinski\Lfeditor\Exceptions\LFException;
|
||||
use SGalinski\Lfeditor\Utility\ExtensionUtility;
|
||||
use SGalinski\Lfeditor\Utility\Functions;
|
||||
use SGalinski\Lfeditor\Utility\SgLib;
|
||||
use SGalinski\Lfeditor\Utility\Typo3Lib;
|
||||
use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
|
||||
use TYPO3\CMS\Core\Cache\CacheManager;
|
||||
use TYPO3\CMS\Core\Core\Environment;
|
||||
use TYPO3\CMS\Core\Localization\Locales;
|
||||
use TYPO3\CMS\Core\Package\PackageInterface;
|
||||
use TYPO3\CMS\Core\Package\PackageManager;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Core\Utility\VersionNumberUtility;
|
||||
use TYPO3\CMS\Extbase\Utility\LocalizationUtility;
|
||||
|
||||
/**
|
||||
* Class ConfigurationService
|
||||
*/
|
||||
class ConfigurationService extends AbstractService {
|
||||
/**
|
||||
* @var array extension configuration
|
||||
* @see prepareConfig()
|
||||
*/
|
||||
protected $extConfig = [];
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $invalidLanguages = '';
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $langArray = [];
|
||||
|
||||
/**
|
||||
* Available editing modes based on extension configuration
|
||||
*
|
||||
* @var array
|
||||
* @see prepareConfig()
|
||||
*/
|
||||
protected $availabledEditingModes = [];
|
||||
|
||||
/**
|
||||
* @var \SGalinski\Lfeditor\Service\FileBaseService
|
||||
*/
|
||||
protected $fileObj;
|
||||
|
||||
/**
|
||||
* @var \SGalinski\Lfeditor\Service\FileBaseService
|
||||
*/
|
||||
protected $convObj;
|
||||
|
||||
/**
|
||||
* @var PackageManager $packageManager
|
||||
*/
|
||||
private $packageManager;
|
||||
|
||||
public function __construct(PackageManager $packageManager) {
|
||||
parent::__construct();
|
||||
$this->packageManager = $packageManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* preparation and check of the configuration
|
||||
*
|
||||
* Note that the default value will be set, if a option check fails.
|
||||
*
|
||||
* @return array
|
||||
* @throws DirectoryAccessRightsException
|
||||
*/
|
||||
public function prepareConfig() {
|
||||
if (!empty($this->extConfig)) {
|
||||
return $this->extConfig;
|
||||
}
|
||||
$this->extConfig = ExtensionUtility::getExtensionConfiguration();
|
||||
|
||||
// regular expressions
|
||||
if (!array_key_exists('searchRegex', $this->extConfig)) {
|
||||
$this->extConfig['searchRegex'] = '/^([a-z0-9_]*locallang[a-z0-9_-]*\.(php|xml)|[^\.]*\.xlf)$/i';
|
||||
} elseif (!\preg_match('/^\/.*\/.*$/', $this->extConfig['searchRegex'])) {
|
||||
$this->extConfig['searchRegex'] = '/^([a-z0-9_]*locallang[a-z0-9_-]*\.(php|xml)|[^\.]*\.xlf)$/i';
|
||||
}
|
||||
|
||||
if (!array_key_exists('searchRegex', $this->extConfig)) {
|
||||
$this->extConfig['extIgnore'] = '/^csh_.*$/';
|
||||
} elseif (!\preg_match('/^\/.*\/.*$/', $this->extConfig['extIgnore'])) {
|
||||
$this->extConfig['extIgnore'] = '/^csh_.*$/';
|
||||
}
|
||||
|
||||
if (!array_key_exists('extWhitelist', $this->extConfig)) {
|
||||
$this->extConfig['extWhitelist'] = '';
|
||||
} elseif (!\preg_match('/^\/.*\/.*$/', $this->extConfig['extWhitelist'])) {
|
||||
$this->extConfig['extWhitelist'] = '';
|
||||
}
|
||||
|
||||
$this->extConfig['execBackup'] = TRUE;
|
||||
$this->extConfig['viewSysExt'] = TRUE;
|
||||
$this->extConfig['viewGlobalExt'] = TRUE;
|
||||
$this->extConfig['viewLocalExt'] = TRUE;
|
||||
$this->extConfig['treeHide'] = TRUE;
|
||||
|
||||
$this->extConfig['viewStateExt'] = 1;
|
||||
$this->extConfig['numTextAreaRows'] = 5;
|
||||
$this->extConfig['numSiteConsts'] = 6;
|
||||
$this->extConfig['anzBackup'] = 5;
|
||||
// Options for number of constants presented on EditFile page
|
||||
$this->extConfig['numSiteConstsOptions']
|
||||
= ['100' => 100, '200' => 200, '500' => 500, '1000' => 1000, '1500' => 1500, '2000' => 2000];
|
||||
|
||||
$pathSite = Environment::getPublicPath() . '/';
|
||||
// paths and files (don't need to exist)
|
||||
$this->extConfig['pathBackup'] = Typo3Lib::fixFilePath(
|
||||
$pathSite . '/typo3temp/LFEditor/Backup/'
|
||||
) . '/';
|
||||
$this->extConfig['metaFile'] = Typo3Lib::fixFilePath(
|
||||
$pathSite . '/typo3temp/LFEditor/Backup/Meta.xml'
|
||||
);
|
||||
$this->extConfig['pathOverrideFiles'] = Typo3Lib::fixFilePath(
|
||||
$pathSite . '/typo3conf/LFEditor/OverrideFiles/'
|
||||
);
|
||||
|
||||
// files
|
||||
$this->extConfig['pathCSS'] = 'Resources/Public/StyleSheets/Lfeditor.css';
|
||||
|
||||
// languages (default is forbidden)
|
||||
if (!empty($this->extConfig['viewLanguages'])) {
|
||||
$langs = GeneralUtility::trimExplode(',', $this->extConfig['viewLanguages'], TRUE);
|
||||
unset($this->extConfig['viewLanguages']);
|
||||
|
||||
$availableLanguageKeys = [];
|
||||
$locales = GeneralUtility::makeInstance(Locales::class);
|
||||
$languages = $locales->getLocales();
|
||||
|
||||
foreach ($languages as $language) {
|
||||
$availableLanguageKeys[$language] = TRUE;
|
||||
}
|
||||
|
||||
foreach ($langs as $lang) {
|
||||
if (!isset($availableLanguageKeys[$lang])) {
|
||||
if ($this->invalidLanguages === '') {
|
||||
$this->invalidLanguages = $lang;
|
||||
} else {
|
||||
$this->invalidLanguages .= ', ' . $lang;
|
||||
}
|
||||
}
|
||||
|
||||
if ($lang !== 'default') {
|
||||
$this->extConfig['viewLanguages'][] = $lang;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($this->extConfig['defaultLanguage'])) {
|
||||
$this->extConfig['defaultLanguage'] = 'default';
|
||||
} else {
|
||||
/** @var Locales $locales */
|
||||
$locales = GeneralUtility::makeInstance(Locales::class);
|
||||
$availableLanguageKeys = $locales->getLanguages();
|
||||
if (!isset($availableLanguageKeys[$this->extConfig['defaultLanguage']])) {
|
||||
$this->extConfig['defaultLanguage'] = 'default';
|
||||
}
|
||||
}
|
||||
|
||||
// editing modes
|
||||
$this->availabledEditingModes = [
|
||||
'extension' => LocalizationUtility::translate('select.editingMode.extension', 'lfeditor'),
|
||||
// The l10n mode does not work for TYPO3 9 and the var folder and we do not want to fix this, yet
|
||||
//'l10n' => LocalizationUtility::translate('select.editingMode.l10n', 'lfeditor'),
|
||||
// Note: override should be always available because it is the fallback mode for editors
|
||||
'override' => LocalizationUtility::translate('select.editingMode.override', 'lfeditor'),
|
||||
];
|
||||
|
||||
if (isset($this->extConfig['editModeExtension']) && ((int) $this->extConfig['editModeExtension']) === 0) {
|
||||
unset($this->availabledEditingModes['extension']);
|
||||
}
|
||||
if (isset($this->extConfig['editModeL10n']) && ((int) $this->extConfig['editModeL10n']) === 0) {
|
||||
unset($this->availabledEditingModes['l10n']);
|
||||
}
|
||||
|
||||
if (isset($this->extConfig['pathAdditionalConfiguration']) && $this->extConfig['pathAdditionalConfiguration']) {
|
||||
$pathAdditionalConfiguration = Typo3Lib::fixFilePath($this->extConfig['pathAdditionalConfiguration']);
|
||||
$this->extConfig['pathAdditionalConfiguration'] = $pathSite . $pathAdditionalConfiguration;
|
||||
$additionalConfigurationDirectory = \dirname($this->extConfig['pathAdditionalConfiguration']);
|
||||
if (!\is_writable($additionalConfigurationDirectory)) {
|
||||
$message = 'Directory ' . $additionalConfigurationDirectory . ' is not writable.'
|
||||
. 'This directory should be writable in order to write the language override configuration '
|
||||
. 'file ' . $pathAdditionalConfiguration;
|
||||
throw new DirectoryAccessRightsException($message);
|
||||
}
|
||||
} else {
|
||||
/** @var \TYPO3\CMS\Core\Configuration\ConfigurationManager $configurationManager */
|
||||
$configurationManager = GeneralUtility::makeInstance(
|
||||
\TYPO3\CMS\Core\Configuration\ConfigurationManager::class
|
||||
);
|
||||
$this->extConfig['pathAdditionalConfiguration'] = $configurationManager->getAdditionalConfigurationFileLocation(
|
||||
);
|
||||
}
|
||||
|
||||
return $this->extConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds extensions for the extension menu selector.
|
||||
*
|
||||
* Note: $this->extConfig must be initialized before call of this method (method prepareConfig() must be executed before this method).
|
||||
*
|
||||
* @return array
|
||||
* @throws LFException raised if no extensions are found
|
||||
*/
|
||||
public function menuExtList() {
|
||||
// search extensions
|
||||
$tmpExtList = [];
|
||||
$pathSite = Environment::getPublicPath() . '/';
|
||||
try {
|
||||
// local extensions
|
||||
|
||||
$labelLocal = LocalizationUtility::translate('ext.local', 'lfeditor');
|
||||
$labelSystem = LocalizationUtility::translate('ext.system', 'lfeditor');
|
||||
$tmpExtList[$labelLocal] = [];
|
||||
$tmpExtList[$labelSystem] = [];
|
||||
foreach ($this->packageManager->getAvailablePackages() as $package) {
|
||||
if (version_compare(VersionNumberUtility::getCurrentTypo3Version(), '11.0.0', '<')) {
|
||||
// local extensions
|
||||
if ($this->extConfig['viewLocalExt'] && \count(
|
||||
$content = Functions::searchExtensions(
|
||||
$pathSite . Typo3Lib::PATH_LOCAL_EXT,
|
||||
$this->extConfig['viewStateExt'],
|
||||
$this->extConfig['extIgnore'],
|
||||
$this->extConfig['extWhitelist']
|
||||
)
|
||||
)
|
||||
) {
|
||||
$tmpExtList[LocalizationUtility::translate('ext.local', 'lfeditor')] = $content;
|
||||
}
|
||||
|
||||
// global extensions
|
||||
if ($this->extConfig['viewGlobalExt'] && \is_dir(Typo3Lib::PATH_GLOBAL_EXT) && \count(
|
||||
$content = Functions::searchExtensions(
|
||||
$pathSite . Typo3Lib::PATH_GLOBAL_EXT,
|
||||
$this->extConfig['viewStateExt'],
|
||||
$this->extConfig['extIgnore'],
|
||||
$this->extConfig['extWhitelist']
|
||||
)
|
||||
)
|
||||
) {
|
||||
$tmpExtList[LocalizationUtility::translate('ext.global', 'lfeditor')] = $content;
|
||||
}
|
||||
|
||||
// system extensions
|
||||
if ($this->extConfig['viewSysExt'] && \count(
|
||||
$content = Functions::searchExtensions(
|
||||
$pathSite . Typo3Lib::PATH_SYS_EXT,
|
||||
$this->extConfig['viewStateExt'],
|
||||
$this->extConfig['extIgnore'],
|
||||
$this->extConfig['extWhitelist']
|
||||
)
|
||||
)
|
||||
) {
|
||||
$tmpExtList[LocalizationUtility::translate('ext.system', 'lfeditor')] = $content;
|
||||
}
|
||||
} else {
|
||||
// check, if the directory/extension should be saved
|
||||
if ($this->extConfig['extWhitelist'] !== ''
|
||||
&& !preg_match($this->extConfig['extWhitelist'], $package->getPackageKey())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($this->extConfig['viewLocalExt'] && $this->isPackageLocal($package)) {
|
||||
$tmpExtList[$labelLocal][] = $package->getPackagePath();
|
||||
}
|
||||
|
||||
if ($this->extConfig['viewSysExt'] && $this->isPackageSystemPackage($package)) {
|
||||
$tmpExtList[$labelSystem][] = $package->getPackagePath();
|
||||
}
|
||||
}
|
||||
}
|
||||
sort($tmpExtList[$labelLocal]);
|
||||
sort($tmpExtList[$labelSystem]);
|
||||
} catch (Exception $e) {
|
||||
throw new LFException('failure.failure', 0, '(' . $e->getMessage() . ')');
|
||||
}
|
||||
|
||||
// check extension array
|
||||
if (!\count($tmpExtList)) {
|
||||
throw new LFException('failure.search.noExtension');
|
||||
}
|
||||
|
||||
// create list
|
||||
$extList = Functions::prepareExtList($tmpExtList);
|
||||
$extList = \array_merge([$pathSite . 'fileadmin' => 'fileadmin/', ''], $extList);
|
||||
|
||||
foreach ($extList as $extAddress => $extLabel) {
|
||||
unset($extList[$extAddress]);
|
||||
$fixedExtAddress = Typo3Lib::fixFilePath($extAddress);
|
||||
$extList[$fixedExtAddress] = $extLabel;
|
||||
}
|
||||
return $extList;
|
||||
}
|
||||
|
||||
/**
|
||||
* checks if package is system package
|
||||
*
|
||||
* @param PackageInterface $package
|
||||
* @return bool
|
||||
*/
|
||||
private function isPackageLocal(PackageInterface $package): bool {
|
||||
return $package->getPackageMetaData()->getPackageType() === 'typo3-cms-extension';
|
||||
}
|
||||
|
||||
/**
|
||||
* checks if package is system package
|
||||
*
|
||||
* @param PackageInterface $package
|
||||
* @return bool
|
||||
*/
|
||||
private function isPackageSystemPackage(PackageInterface $package): bool {
|
||||
return $package->getPackageMetaData()->isFrameworkType();
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds language files of extension which address is passed as $extensionAddress parameter.
|
||||
*
|
||||
* @param string $extensionAddress
|
||||
* @return array
|
||||
* @throws LFException
|
||||
*/
|
||||
public function menuLangFileList($extensionAddress) {
|
||||
// check
|
||||
if (empty($extensionAddress)) {
|
||||
throw new LFException('failure.search.noLangFile', 1);
|
||||
}
|
||||
|
||||
// search and prepare files
|
||||
try {
|
||||
/** @var array $files */
|
||||
$files = SgLib::searchFiles(
|
||||
$extensionAddress,
|
||||
$this->extConfig['searchRegex']
|
||||
);
|
||||
} catch (Exception $e) {
|
||||
throw new LFException(
|
||||
'failure.search.noLangFile',
|
||||
1,
|
||||
'(' . $e->getMessage() . ')'
|
||||
);
|
||||
}
|
||||
|
||||
$fileArray = [];
|
||||
if (\count($files)) {
|
||||
foreach ($files as $file) {
|
||||
$filename = \substr($file, \strlen($extensionAddress) + 1);
|
||||
$fileArray[$filename] = $filename;
|
||||
}
|
||||
} else {
|
||||
throw new LFException('failure.search.noLangFile', 1);
|
||||
}
|
||||
|
||||
return $fileArray;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used for the language menu selector
|
||||
*
|
||||
* @param array $langData language data
|
||||
* @param string $default optional default value (if you dont want a default let it empty)
|
||||
* @param BackendUserAuthentication $backendUser
|
||||
* @param bool $translatedLanguagesOnly looks only for translated languages
|
||||
* @return array
|
||||
* @throws LFException
|
||||
*/
|
||||
public function menuLangList(
|
||||
$langData,
|
||||
$default = '',
|
||||
BackendUserAuthentication $backendUser = NULL,
|
||||
$translatedLanguagesOnly = FALSE
|
||||
) {
|
||||
// build languages
|
||||
$languageArray = $this->getLangArray($backendUser);
|
||||
$languageList = [];
|
||||
foreach ($languageArray as $language) {
|
||||
$constCount = 0;
|
||||
if (array_key_exists($language, $langData) && \is_array($langData[$language])) {
|
||||
$constCount = \count($langData[$language]);
|
||||
}
|
||||
if ($translatedLanguagesOnly && $constCount <= 0) {
|
||||
continue;
|
||||
}
|
||||
$languageLabel = $language;
|
||||
if ($language === 'default') {
|
||||
$languageLabel = 'en';
|
||||
}
|
||||
$languageList[$language] = $languageLabel . ' (' . $constCount . ' ' .
|
||||
LocalizationUtility::translate('const.consts', 'lfeditor') . ')';
|
||||
}
|
||||
|
||||
// add default value
|
||||
if (!empty($default)) {
|
||||
$languageList = \array_merge(['###default###' => $default], $languageList);
|
||||
}
|
||||
return $languageList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns list (array) of constants.
|
||||
*
|
||||
* @param array $langData language data
|
||||
* @param string $default name of default entry
|
||||
* @return array
|
||||
*/
|
||||
public function menuConstList($langData, $default) {
|
||||
// generate constant list
|
||||
$constList = [];
|
||||
$languages = Functions::buildLangArray();
|
||||
foreach ($languages as $language) {
|
||||
if (!\array_key_exists($language, $langData) || !\is_array($langData[$language]) || !\count(
|
||||
$langData[$language]
|
||||
)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/** @var array $constants */
|
||||
$constants = \array_keys($langData[$language]);
|
||||
foreach ($constants as $constant) {
|
||||
$constList[\str_replace('#', '$*-*$', $constant)] = $constant;
|
||||
}
|
||||
}
|
||||
|
||||
// sorting and default entry
|
||||
\asort($constList);
|
||||
$constList = \array_merge(['###default###' => $default], $constList);
|
||||
return $constList;
|
||||
}
|
||||
|
||||
/**
|
||||
* creates and instantiates a file object
|
||||
*
|
||||
* Naming Convention:
|
||||
* File<workspace><filetype>Service
|
||||
*
|
||||
*
|
||||
* @param string $langFile
|
||||
* @param string $extPath
|
||||
* @param bool $flagReadFile
|
||||
* @return void
|
||||
* @throws LFException
|
||||
*/
|
||||
public function initFileObject($langFile, $extPath, $flagReadFile = TRUE) {
|
||||
$fileType = SgLib::getFileExtension($langFile);
|
||||
$className = __NAMESPACE__ . '\FileBase' . \strtoupper($fileType) . 'Service';
|
||||
if (!\class_exists($className)) {
|
||||
throw new LFException('failure.langfile.unknownType');
|
||||
}
|
||||
/** @var \SGalinski\Lfeditor\Service\FileService $originalFileObject */
|
||||
$originalFileObject = GeneralUtility::makeInstance($className);
|
||||
$originalFileObject->init($langFile, $extPath, '');
|
||||
|
||||
try {
|
||||
if ($this->session->getDataByKey('editingMode') === 'override') {
|
||||
/** @var FileOverrideService $overrideFileObj */
|
||||
$overrideFileObj = GeneralUtility::makeInstance(FileOverrideService::class);
|
||||
$overrideFileObj->init($originalFileObject, '', '');
|
||||
$this->fileObj = $overrideFileObj;
|
||||
} else {
|
||||
$this->fileObj = $originalFileObject;
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
throw new LFException('failure.failure', 0, '(' . $e->getMessage() . ')');
|
||||
}
|
||||
|
||||
if ($flagReadFile) {
|
||||
$this->fileObj->readFile();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes writing of language files
|
||||
*
|
||||
*
|
||||
* @param array $modArray changes (constants with empty values will be deleted)
|
||||
* @param array $modMetaArray meta changes (indexes with empty values will be deleted)
|
||||
* @param boolean $forceDel set to true if you want delete default constants
|
||||
* @param array|NULL $editedLanguages
|
||||
* @return void
|
||||
* @throws LFException if file could not be written or some param criteria is not correct
|
||||
* @throws \TYPO3\CMS\Core\Cache\Exception\NoSuchCacheException
|
||||
* @throws Exception
|
||||
*/
|
||||
public function execWrite($modArray, $modMetaArray = [], $forceDel = FALSE, $editedLanguages = NULL) {
|
||||
// checks
|
||||
if (!\is_array($modArray)) {
|
||||
throw new LFException('failure.file.notWritten');
|
||||
}
|
||||
|
||||
$fileObject = $this->getFileObj();
|
||||
if ($fileObject === NULL) {
|
||||
$this->initFileObject(
|
||||
$this->session->getDataByKey('languageFileSelection'),
|
||||
$this->session->getDataByKey('extensionSelection')
|
||||
);
|
||||
$fileObject = $this->getFileObj();
|
||||
}
|
||||
|
||||
// execute backup
|
||||
$extConfig = $this->getExtConfig();
|
||||
if ($extConfig['execBackup'] && $this->session->getDataByKey('editingMode') === 'extension') {
|
||||
/** @var BackupService $backupService */
|
||||
$backupService = GeneralUtility::makeInstance(BackupService::class);
|
||||
$backupService->execBackup();
|
||||
}
|
||||
|
||||
if (!$this->session->getDataByKey('defaultLanguagePermission')) {
|
||||
unset($modArray[$this->extConfig['defaultLanguage']]);
|
||||
}
|
||||
// set new language data
|
||||
foreach ($modArray as $langKey => $data) {
|
||||
if (\is_array($data)) {
|
||||
foreach ($data as $const => $value) {
|
||||
$fileObject->setLocalLangData($const, $value, $langKey, $forceDel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// set changed meta data
|
||||
foreach ($modMetaArray as $metaIndex => $metaValue) {
|
||||
$fileObject->setMetaData($metaIndex, $metaValue);
|
||||
}
|
||||
|
||||
// write new language data
|
||||
$fileObject->writeFile($editedLanguages);
|
||||
|
||||
// delete possible language files
|
||||
$absFile = $fileObject->getVar('absFile');
|
||||
$originLang = $fileObject->getOriginLangData();
|
||||
$emptyFiles = [];
|
||||
foreach ($originLang as $lang => $origin) {
|
||||
if ($origin === $absFile || !\is_file($origin)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$langData = $fileObject->getLocalLangData($lang);
|
||||
if (\is_array($langData) && !\count($langData)) {
|
||||
$emptyFiles[] = $origin;
|
||||
}
|
||||
}
|
||||
|
||||
// delete all empty language files
|
||||
try {
|
||||
if (\count($emptyFiles)) {
|
||||
SgLib::deleteFiles($emptyFiles);
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
throw new LFException('failure.langfile.notDeleted', 0, '(' . $e->getMessage() . ')');
|
||||
}
|
||||
|
||||
/** @var CacheManager $cacheManager */
|
||||
$cacheManager = GeneralUtility::makeInstance(CacheManager::class);
|
||||
$cacheManager->getCache('l10n')->flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* Splits or merges a language file
|
||||
*
|
||||
* @param array $langModes language shortcuts and their mode (1 = splitNormal, 2 = merge)
|
||||
* @return void
|
||||
* @throws LFException raised if file could not be split or merged (i.e. empty langModes)
|
||||
* @throws Exception|LFException
|
||||
*/
|
||||
public function execSplitFile(array $langModes) {
|
||||
// check
|
||||
if (!\is_array($langModes) || !\count($langModes)) {
|
||||
throw new LFException('failure.langfile.notSplittedOrMerged');
|
||||
}
|
||||
|
||||
// rewrite originLang array
|
||||
$delLangFiles = [];
|
||||
foreach ($langModes as $langKey => $mode) {
|
||||
if ($langKey === 'default') {
|
||||
continue;
|
||||
}
|
||||
|
||||
// get origin of this language
|
||||
$origin = $this->fileObj->getOriginLangData($langKey);
|
||||
|
||||
// split or merge
|
||||
if ($mode === 1) {
|
||||
// nothing to do if the file is already a normal splitted file
|
||||
if (Typo3Lib::checkFileLocation($origin) !== 'l10n') {
|
||||
if ($this->fileObj->checkLocalizedFile(\basename($origin), $langKey)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// delete file if was it a l10n file
|
||||
if ($this->fileObj->checkLocalizedFile(\basename($origin), $langKey)) {
|
||||
$delLangFiles[] = $origin;
|
||||
}
|
||||
|
||||
$origin = Typo3Lib::fixFilePath(
|
||||
\dirname($this->fileObj->getVar('absFile')) .
|
||||
'/' . $this->fileObj->nameLocalizedFile($langKey)
|
||||
);
|
||||
} elseif ($mode === 2) {
|
||||
if ($this->fileObj->checkLocalizedFile(\basename($origin), $langKey)) {
|
||||
$delLangFiles[] = $origin;
|
||||
}
|
||||
$origin = $this->fileObj->getVar('absFile');
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
$this->fileObj->setOriginLangData($origin, $langKey);
|
||||
}
|
||||
|
||||
// write new language file
|
||||
$this->execWrite([]);
|
||||
|
||||
// delete old localized files, if single mode was selected
|
||||
try {
|
||||
if (\count($delLangFiles)) {
|
||||
SgLib::deleteFiles($delLangFiles);
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
throw new LFException(
|
||||
'failure.langfile.notDeleted',
|
||||
0,
|
||||
'(' . $e->getMessage() . ')'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* converts language files between different formats
|
||||
*
|
||||
* @param string $type new file format
|
||||
* @param string $newFile new relative file
|
||||
* @return void
|
||||
* @throws Exception|LFException
|
||||
* @throws LFException raised if transforming or deletion of old files failed
|
||||
*/
|
||||
public function execTransform($type, $newFile) {
|
||||
// copy current object to convObj
|
||||
$this->convObj = clone $this->fileObj;
|
||||
unset($this->fileObj);
|
||||
|
||||
// init new language file object (dont try to read file)
|
||||
$this->initFileObject($newFile, $this->convObj->getVar('absPath'), FALSE);
|
||||
|
||||
// recreate originLang
|
||||
$origins = $this->convObj->getOriginLangData();
|
||||
foreach ($origins as $langKey => $file) {
|
||||
// localized or merged language origin
|
||||
$newFile = SgLib::setFileExtension($type, $file);
|
||||
if ($this->convObj->getVar('workspace') === 'base') {
|
||||
if ($this->convObj->checkLocalizedFile(\basename($file), $langKey)) {
|
||||
$newFile = \dirname($file) . '/' . $this->fileObj->nameLocalizedFile($langKey);
|
||||
}
|
||||
}
|
||||
$this->fileObj->setOriginLangData(Typo3Lib::fixFilePath($newFile), $langKey);
|
||||
}
|
||||
|
||||
// recreate meta data
|
||||
$meta = $this->convObj->getMetaData();
|
||||
foreach ($meta as $metaIndex => $metaValue) {
|
||||
$this->fileObj->setMetaData($metaIndex, $metaValue);
|
||||
}
|
||||
|
||||
// write new language file
|
||||
$this->extConfig['execBackup'] = 0;
|
||||
$this->execWrite($this->convObj->getLocalLangData());
|
||||
|
||||
// delete all old files
|
||||
try {
|
||||
$delFiles = $this->convObj->getOriginLangData();
|
||||
if (\is_array($delFiles) && \count($delFiles)) {
|
||||
SgLib::deleteFiles($delFiles);
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
throw new LFException(
|
||||
'failure.langfile.notDeleted',
|
||||
0,
|
||||
'(' . $e->getMessage() . ')'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************
|
||||
* Getters and setters *
|
||||
*************************/
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getExtConfig() {
|
||||
return $this->extConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets 'execBackup' parameter of extension configuration.
|
||||
*
|
||||
* @param int $execBackup
|
||||
*/
|
||||
public function setExecBackup($execBackup) {
|
||||
$this->extConfig['execBackup'] = $execBackup;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $extConfig
|
||||
*/
|
||||
public function setExtConfig($extConfig) {
|
||||
$this->extConfig = $extConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getInvalidLanguages() {
|
||||
return $this->invalidLanguages;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $invalidLanguages
|
||||
*/
|
||||
public function setInvalidLanguages($invalidLanguages) {
|
||||
$this->invalidLanguages = $invalidLanguages;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getAvailableEditingModes() {
|
||||
return $this->availabledEditingModes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return FileBaseService
|
||||
*/
|
||||
public function getFileObj() {
|
||||
return $this->fileObj;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param FileBasePHPService $fileObj
|
||||
*/
|
||||
public function setFileObj($fileObj) {
|
||||
$this->fileObj = $fileObj;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns array of system languages.
|
||||
*
|
||||
* @param BackendUserAuthentication $backendUser
|
||||
* @return array
|
||||
* @throws LFException
|
||||
*/
|
||||
public function getLangArray(BackendUserAuthentication $backendUser = NULL) {
|
||||
if ($this->invalidLanguages !== '') {
|
||||
throw new LFException('failure.config.invalidLanguage', 0, $this->invalidLanguages);
|
||||
}
|
||||
|
||||
if (empty($this->langArray)) {
|
||||
$languages = Functions::buildLangArray($this->extConfig['viewLanguages']);
|
||||
$languages = $this->narrowToUserLanguages($languages, $backendUser);
|
||||
|
||||
if (!\in_array('default', $languages, TRUE)) {
|
||||
$languages = \array_merge(['default'], $languages);
|
||||
}
|
||||
if (!\in_array($this->extConfig['defaultLanguage'], $languages, TRUE)) {
|
||||
$languages = \array_merge([$this->extConfig['defaultLanguage']], $languages);
|
||||
}
|
||||
$this->langArray = $languages;
|
||||
}
|
||||
return $this->langArray;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $langArray
|
||||
*/
|
||||
public function setLangArray($langArray) {
|
||||
$this->langArray = $langArray;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the path to the configured AdditionalConfiguration.php file
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getAdditionalConfigurationFilePath() {
|
||||
return $this->extConfig['pathAdditionalConfiguration'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Narrows $languages to user languages if user is not admin.
|
||||
*
|
||||
* @param array $languages
|
||||
* @param BackendUserAuthentication $backendUser
|
||||
* @return array
|
||||
*/
|
||||
protected function narrowToUserLanguages(array $languages, BackendUserAuthentication $backendUser) {
|
||||
if ($backendUser !== NULL && !$backendUser->isAdmin()) {
|
||||
$sysLanguageService = GeneralUtility::makeInstance(SysLanguageService::class);
|
||||
foreach ($languages as $index => $languageFlag) {
|
||||
$sysLanguageId = $sysLanguageService->getSysLanguageIdByFlag($languageFlag);
|
||||
if ($languageFlag === 'default'
|
||||
|| ($sysLanguageId !== NULL && $backendUser->checkLanguageAccess($sysLanguageId))
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
unset($languages[$index]);
|
||||
}
|
||||
}
|
||||
return $languages;
|
||||
}
|
||||
}
|
||||
478
typo3conf/ext/lfeditor/Classes/Service/FileBackupService.php
Normal file
478
typo3conf/ext/lfeditor/Classes/Service/FileBackupService.php
Normal file
@@ -0,0 +1,478 @@
|
||||
<?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 Exception;
|
||||
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;
|
||||
use TYPO3\CMS\Core\Utility\VersionNumberUtility;
|
||||
|
||||
/**
|
||||
* backup class
|
||||
*/
|
||||
class FileBackupService extends FileService {
|
||||
/**
|
||||
* @var string $metaFile
|
||||
*/
|
||||
private $metaFile;
|
||||
|
||||
/**
|
||||
* @var array $metaArray
|
||||
*/
|
||||
private $metaArray = [];
|
||||
|
||||
/**
|
||||
* @var string $extName
|
||||
*/
|
||||
private $extName = '';
|
||||
|
||||
/**
|
||||
* @var string $extPath
|
||||
*/
|
||||
private $extPath = '';
|
||||
|
||||
/**
|
||||
* @var string $langFile
|
||||
*/
|
||||
private $langFile = '';
|
||||
|
||||
/**
|
||||
* extended init
|
||||
*
|
||||
* @throws LFException raised if the meta file cant be correctly read
|
||||
* @param string $file name of the file (can be a path, if you need this (no check))
|
||||
* @param string $path path to the file
|
||||
* @param string $metaFile absolute path to the meta file (includes filename)
|
||||
* @return void
|
||||
*/
|
||||
public function init($file, $path, $metaFile) {
|
||||
// init
|
||||
$this->setVar(['metaFile' => $metaFile]);
|
||||
parent::init($file, $path, $metaFile);
|
||||
|
||||
// read meta file
|
||||
try {
|
||||
if (is_file($this->metaFile)) {
|
||||
$this->readMetaFile();
|
||||
}
|
||||
} catch (LFException $e) {
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
#####################
|
||||
###### Set/Get ######
|
||||
#####################
|
||||
|
||||
/**
|
||||
* sets information
|
||||
*
|
||||
* structure:
|
||||
* $infos["metaFile"] = absolute path to the meta file (includes filename)
|
||||
* $infos["extPath"] = extension path
|
||||
* $infos["langFile"] = language file
|
||||
*
|
||||
* @param array $informations information (see above)
|
||||
* @return void
|
||||
*/
|
||||
public function setVar($informations) {
|
||||
if (!empty($informations['metaFile'])) {
|
||||
$this->metaFile = Typo3Lib::fixFilePath($informations['metaFile']);
|
||||
}
|
||||
|
||||
if (!empty($informations['extPath'])) {
|
||||
$this->extPath = Typo3Lib::fixFilePath($informations['extPath']);
|
||||
$this->extName = basename($informations['extPath']);
|
||||
}
|
||||
|
||||
if (!empty($informations['langFile'])) {
|
||||
$this->langFile = Typo3Lib::fixFilePath($informations['langFile']);
|
||||
}
|
||||
|
||||
parent::setVar($informations);
|
||||
}
|
||||
|
||||
/**
|
||||
* returns requested information
|
||||
*
|
||||
* @param string $info
|
||||
* @return mixed
|
||||
*/
|
||||
public function getVar($info) {
|
||||
if ($info == 'metaFile') {
|
||||
return $this->metaFile;
|
||||
} elseif ($info == 'extName') {
|
||||
return $this->extName;
|
||||
} elseif ($info == 'extPath') {
|
||||
return $this->extPath;
|
||||
} elseif ($info == 'langFile') {
|
||||
return $this->langFile;
|
||||
} else {
|
||||
return parent::getVar($info);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* returns meta information about backup files
|
||||
*
|
||||
* Modes:
|
||||
* - 0 => full meta information (default)
|
||||
* - 1 => only meta information of given extension key
|
||||
* - 2 => only meta information of given extension key and workspace
|
||||
* - 3 => only meta information of given extension key, workspace and language file
|
||||
*
|
||||
* @param integer $mode
|
||||
* @param string $extName extension Name (default = $this->extName)
|
||||
* @param string $workspace (default = $this->workspace)
|
||||
* @param string $langFile language file (default = $this->langFile)
|
||||
* @return array
|
||||
*/
|
||||
public function getMetaInfos($mode = 0, $extName = '', $workspace = '', $langFile = '') {
|
||||
$extName = empty($extName) ? $this->extName : $extName;
|
||||
$langFile = empty($langFile) ? $this->langFile : $langFile;
|
||||
$workspace = empty($workspace) ? $this->workspace : $workspace;
|
||||
|
||||
// build return value
|
||||
if (!$mode) {
|
||||
return $this->metaArray;
|
||||
} elseif ($mode == 1) {
|
||||
return $this->metaArray[$extName] ?? [];
|
||||
} elseif ($mode == 2) {
|
||||
return $this->metaArray[$extName][$workspace] ?? [];
|
||||
} elseif ($mode == 3) {
|
||||
return $this->metaArray[$extName][$workspace][$langFile] ?? [];
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* rewrites current meta information array with the given equivalent
|
||||
*
|
||||
* Modes:
|
||||
* - 0 => full meta information (default)
|
||||
* - 1 => only meta information of given extension key
|
||||
* - 2 => only meta information of given extension key and workspace
|
||||
* - 3 => only meta information of given extension key, workspace and language file
|
||||
*
|
||||
* @param array $metaArray meta information
|
||||
* @param integer $mode
|
||||
* @param string $extName extension Name (default = $this->extName)
|
||||
* @param string $workspace (default = $this->workspace)
|
||||
* @param string $langFile language file (default = $this->langFile)
|
||||
* @return void
|
||||
*/
|
||||
private function setMetaInfos($metaArray, $mode = 0, $extName = '', $workspace = '', $langFile = '') {
|
||||
$extName = empty($extName) ? $this->extName : $extName;
|
||||
$langFile = empty($langFile) ? $this->langFile : $langFile;
|
||||
$workspace = empty($workspace) ? $this->workspace : $workspace;
|
||||
|
||||
// build new meta information array
|
||||
if (is_array($metaArray) && count($metaArray)) {
|
||||
if (!$mode) {
|
||||
$this->metaArray = $metaArray;
|
||||
} elseif ($mode == 1) {
|
||||
$this->metaArray[$extName] = $metaArray;
|
||||
} elseif ($mode == 2) {
|
||||
$this->metaArray[$extName][$workspace] = $metaArray;
|
||||
} elseif ($mode == 3) {
|
||||
$this->metaArray[$extName][$workspace][$langFile] = $metaArray;
|
||||
}
|
||||
} else {
|
||||
if (!$mode) {
|
||||
unset($this->metaArray);
|
||||
} elseif ($mode == 1) {
|
||||
unset($this->metaArray[$extName]);
|
||||
} elseif ($mode == 2) {
|
||||
unset($this->metaArray[$extName][$workspace]);
|
||||
} elseif ($mode == 3) {
|
||||
unset($this->metaArray[$extName][$workspace][$langFile]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
###############################
|
||||
###### Meta FileService Methods ######
|
||||
###############################
|
||||
|
||||
/**
|
||||
* reads the meta information file and parses the content into $this->metaArray
|
||||
*
|
||||
* @throws LFException raised if no meta content was generated
|
||||
* @return void
|
||||
*/
|
||||
private function readMetaFile() {
|
||||
// read file and parse xml to array
|
||||
$metaArray = GeneralUtility::xml2array(file_get_contents($this->metaFile));
|
||||
if (!is_array($metaArray)) {
|
||||
throw new LFException('failure.backup.metaFile.notRead');
|
||||
}
|
||||
|
||||
$this->metaArray = $metaArray;
|
||||
}
|
||||
|
||||
/**
|
||||
* generate meta XML
|
||||
*
|
||||
* @return string meta information (xml)
|
||||
*/
|
||||
private function genMetaXML() {
|
||||
$options = [];
|
||||
// define assocTagNames
|
||||
$options['parentTagMap'] = [
|
||||
'' => 'extKey',
|
||||
'extKey' => 'workspace',
|
||||
'workspace' => 'langFile',
|
||||
'langFile' => 'file',
|
||||
];
|
||||
return GeneralUtility::array2xml($this->getMetaInfos(), '', 0, 'LFBackupMeta', 0, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* writes the meta information file
|
||||
*
|
||||
* @throws LFException raised if the meta file cant be written
|
||||
* @return void
|
||||
*/
|
||||
private function writeMetaFile() {
|
||||
$metaXML = $this->genMetaXML();
|
||||
if (empty($metaXML)) {
|
||||
throw new LFException('failure.backup.metaFile.notWritten');
|
||||
}
|
||||
|
||||
if (!GeneralUtility::writeFile($this->metaFile, $this->getXMLHeader() . $metaXML)) {
|
||||
throw new LFException('failure.backup.metaFile.notWritten');
|
||||
}
|
||||
}
|
||||
|
||||
#################################
|
||||
###### Backup FileService Methods ######
|
||||
#################################
|
||||
|
||||
/**
|
||||
* generates the xml header
|
||||
*
|
||||
* @return string xml header
|
||||
*/
|
||||
private function getXMLHeader() {
|
||||
return '<?xml version="1.0" encoding="utf-8" standalone="yes" ?>' . "\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* removes the meta information entry and the backup file
|
||||
*
|
||||
* @param string $filename
|
||||
* @param string $extName (default = $this->extName)
|
||||
* @param string $langFile (default = $this->langFile)
|
||||
* @throws Exception|LFException
|
||||
* @throws LFException
|
||||
* @return void
|
||||
*/
|
||||
public function deleteSpecFile($filename, $extName = '', $langFile = '') {
|
||||
// get needed meta information
|
||||
$extName = empty($extName) ? $this->extName : $extName;
|
||||
$langFile = empty($langFile) ? $this->langFile : $langFile;
|
||||
$metaArray = $this->getMetaInfos(3, $extName, '', $langFile);
|
||||
|
||||
// check backup file
|
||||
if (!isset($metaArray[$filename])) {
|
||||
throw new LFException('failure.backup.notDeleted');
|
||||
}
|
||||
|
||||
// get file
|
||||
$backupPath = $metaArray[$filename]['pathBackup'];
|
||||
$pathSite = Environment::getPublicPath() . '/';
|
||||
$file = GeneralUtility::fixWindowsFilePath($pathSite . $backupPath . '/' . $filename);
|
||||
|
||||
// build new meta information file
|
||||
unset($metaArray[$filename]);
|
||||
if (!count($metaArray)) {
|
||||
$metaArray = NULL;
|
||||
}
|
||||
$this->setMetaInfos($metaArray, 3, $extName, '', $langFile);
|
||||
|
||||
$extMetaArray = $this->getMetaInfos(2, $extName);
|
||||
if (!count($extMetaArray)) {
|
||||
$extMetaArray = NULL;
|
||||
}
|
||||
$this->setMetaInfos($extMetaArray, 2, $extName);
|
||||
|
||||
// write meta information
|
||||
try {
|
||||
$this->writeMetaFile();
|
||||
} catch (LFException $e) {
|
||||
throw $e;
|
||||
}
|
||||
|
||||
// delete backup file
|
||||
try {
|
||||
SgLib::deleteFiles([$file]);
|
||||
} catch (Exception $e) {
|
||||
throw new LFException(
|
||||
'failure.backup.notDeleted',
|
||||
0,
|
||||
'(' . $e->getMessage() . ')',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* wrapper for deleteSpecFile()
|
||||
*
|
||||
* @throws LFException raised if the backup or meta file cant be written
|
||||
* @return void
|
||||
*/
|
||||
public function deleteFile() {
|
||||
try {
|
||||
$this->deleteSpecFile($this->relFile);
|
||||
} catch (LFException $e) {
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* reads a backup file
|
||||
*
|
||||
* @throws LFException raised if the backup file can't be read
|
||||
* @return void
|
||||
*/
|
||||
public function readFile() {
|
||||
if (!is_file($this->absFile)) {
|
||||
throw new LFException('failure.backup.notRead');
|
||||
}
|
||||
|
||||
// read file and transform from xml to array
|
||||
$phpArray = GeneralUtility::xml2array(file_get_contents($this->absFile));
|
||||
if (!is_array($phpArray)) {
|
||||
throw new LFException('failure.backup.notRead');
|
||||
}
|
||||
|
||||
$pathSite = Environment::getPublicPath() . '/';
|
||||
// read array
|
||||
$localLang = $originLang = [];
|
||||
foreach ($phpArray['data'] as $langKey => $informations) {
|
||||
// read origin
|
||||
try {
|
||||
$originLang[$langKey] = Typo3Lib::transTypo3File($informations['meta']['origin'], TRUE);
|
||||
} catch (Exception $e) {
|
||||
$originLang[$langKey] = $pathSite . $informations['meta']['origin'];
|
||||
}
|
||||
|
||||
// read data
|
||||
if (is_array($informations['langData'])) {
|
||||
foreach ($informations['langData'] as $const => $value) {
|
||||
$localLang[$langKey][$const] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check
|
||||
if (!count($localLang) || !count($originLang)) {
|
||||
throw new LFException('failure.backup.notRead');
|
||||
}
|
||||
|
||||
$this->localLang = $localLang;
|
||||
$this->originLang = $originLang;
|
||||
$this->meta = $phpArray['meta'];
|
||||
}
|
||||
|
||||
/**
|
||||
* prepares the final Content
|
||||
*
|
||||
* @return string prepared content (xml)
|
||||
*/
|
||||
private function prepareBackupContent() {
|
||||
$phpArray = [];
|
||||
$options = [];
|
||||
// set meta
|
||||
$phpArray['meta'] = $this->meta;
|
||||
$pathSite = Environment::getPublicPath() . '/';
|
||||
// set array
|
||||
foreach ($this->originLang as $lang => $origin) {
|
||||
// set origin
|
||||
try {
|
||||
$phpArray['data'][$lang]['meta']['origin'] = Typo3Lib::transTypo3File($origin, FALSE);
|
||||
} catch (Exception $e) {
|
||||
$phpArray['data'][$lang]['meta']['origin'] = substr($origin, strlen($pathSite));
|
||||
}
|
||||
|
||||
// set data
|
||||
if (\array_key_exists($lang, $this->localLang) && \is_array($this->localLang[$lang])) {
|
||||
foreach ($this->localLang[$lang] as $labelKey => $labelVal) {
|
||||
$phpArray['data'][$lang]['langData'][$labelKey] = $labelVal;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// define assocTagNames
|
||||
$options['parentTagMap'] = [
|
||||
'data' => 'languageKey',
|
||||
'langData' => 'label'
|
||||
];
|
||||
|
||||
// get xml
|
||||
return GeneralUtility::array2xml($phpArray, '', 0, 'LFBackup', 0, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* prepares the backup file and writes the new meta information
|
||||
*
|
||||
* @param array | NULL $editedLanguages
|
||||
* @return array raised if meta file cant be written
|
||||
* @throws Exception
|
||||
* @throws LFException
|
||||
* @return array
|
||||
*/
|
||||
protected function prepareFileContents($editedLanguages = NULL) {
|
||||
$backupFiles = [];
|
||||
// get content
|
||||
$xml = $this->prepareBackupContent();
|
||||
|
||||
// get and set name of backup
|
||||
$backupName = 'locallang_' . substr(md5(md5($xml)), 0, 10) . '.bak';
|
||||
$this->setVar(['relFile' => $backupName]);
|
||||
$pathSite = Environment::getPublicPath() . '/';
|
||||
// get new meta information
|
||||
$metaArray = $this->getMetaInfos(3);
|
||||
$metaArray[$this->relFile]['createdAt'] = time();
|
||||
$metaArray[$this->relFile]['pathBackup'] = str_replace($pathSite, '', $this->absPath);
|
||||
$this->setMetaInfos($metaArray, 3);
|
||||
|
||||
// write meta information file
|
||||
try {
|
||||
$this->writeMetaFile();
|
||||
} catch (LFException $e) {
|
||||
throw $e;
|
||||
}
|
||||
|
||||
$backupFiles[$this->absPath . $this->relFile] = $this->getXMLHeader() . $xml;
|
||||
return $backupFiles;
|
||||
}
|
||||
}
|
||||
256
typo3conf/ext/lfeditor/Classes/Service/FileBasePHPService.php
Normal file
256
typo3conf/ext/lfeditor/Classes/Service/FileBasePHPService.php
Normal file
@@ -0,0 +1,256 @@
|
||||
<?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;
|
||||
|
||||
/**
|
||||
* base workspace class (php)
|
||||
*/
|
||||
class FileBasePHPService extends FileBaseService {
|
||||
/**
|
||||
* extended init
|
||||
*
|
||||
* @param string $file name of the file (can be a path, if you need this (no check))
|
||||
* @param string $path path to the file
|
||||
*
|
||||
* @return void
|
||||
* @throws LFException
|
||||
*/
|
||||
public function init($file, $path, $metaFile) {
|
||||
$this->setVar(['fileType' => 'php']);
|
||||
parent::init($file, $path, $metaFile);
|
||||
}
|
||||
|
||||
/**
|
||||
* reads a language file
|
||||
*
|
||||
* @throws LFException raised if the file does not contain a locallang array
|
||||
* @param string $file language file
|
||||
* @param string $langKey language shortcut (not used)
|
||||
* @return array language content
|
||||
*/
|
||||
protected function readLLFile($file, $langKey) {
|
||||
$LOCAL_LANG = NULL;
|
||||
if (!is_file($file)) {
|
||||
throw new LFException('failure.select.noLangfile');
|
||||
}
|
||||
|
||||
include($file);
|
||||
|
||||
/** @var array $LOCAL_LANG */
|
||||
if (!is_array($LOCAL_LANG) || !count($LOCAL_LANG)) {
|
||||
throw new LFException('failure.search.noFileContent', 0, '(' . $file . ')');
|
||||
}
|
||||
|
||||
/** @var array $LFMETA */
|
||||
if ($langKey == 'default') {
|
||||
$this->meta = $LFMETA;
|
||||
}
|
||||
|
||||
return $LOCAL_LANG;
|
||||
}
|
||||
|
||||
/**
|
||||
* checks the given content, if its a localized language file reference
|
||||
*
|
||||
* @param mixed $content language content (only one language)
|
||||
* @param string $langKey language shortcut
|
||||
* @return string localized file (absolute) or a boolean false
|
||||
*/
|
||||
protected function getLocalizedFile($content, $langKey) {
|
||||
if ((string) $content != 'EXT') {
|
||||
return '';
|
||||
}
|
||||
|
||||
return Typo3Lib::fixFilePath(
|
||||
dirname($this->absFile) .
|
||||
'/' . $this->nameLocalizedFile($langKey)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* checks a filename, if its a localized file
|
||||
*
|
||||
* @param string $filename filename
|
||||
* @param string $langKey language shortcut
|
||||
* @return boolean true(localized) or false
|
||||
*/
|
||||
public function checkLocalizedFile($filename, $langKey) {
|
||||
if (!preg_match('/^.*\.(' . $langKey . ')\.php$/', $filename)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the name of a localized file
|
||||
*
|
||||
* @param string $langKey language shortcut
|
||||
* @return string localized file (only filename)
|
||||
*/
|
||||
public function nameLocalizedFile($langKey) {
|
||||
return SgLib::setFileExtension($langKey . '.php', basename($this->relFile));
|
||||
}
|
||||
|
||||
/**
|
||||
* prepares the meta data for writing into a file
|
||||
*
|
||||
* @return string meta data for writing purposes
|
||||
*/
|
||||
private function prepareMeta() {
|
||||
if (!is_array($this->meta) || !count($this->meta)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$metaData = '';
|
||||
foreach ($this->meta as $metaIndex => $value) {
|
||||
$value = preg_replace('/[^\\\]\'/', '\\\'', $value);
|
||||
$metaData .= "\t" . '\'' . $metaIndex . '\' => \'' . $value . '\',' . "\n";
|
||||
}
|
||||
|
||||
return $metaData;
|
||||
}
|
||||
|
||||
/**
|
||||
* generates the header data of a language file
|
||||
*
|
||||
* @return string header data
|
||||
*/
|
||||
private function getHeader() {
|
||||
$extKey = basename($this->absPath);
|
||||
|
||||
$header = '<?php' . "\n";
|
||||
$header .= "/**\n * local language labels of module \"$extKey\"\n";
|
||||
$header .= " *\n * This file is detected by the translation tool\n";
|
||||
$header .= " *\n * Modified/Created by extension 'lfeditor'\n */\n\n";
|
||||
|
||||
return $header;
|
||||
}
|
||||
|
||||
/**
|
||||
* generates the footer data of a language file
|
||||
*
|
||||
* @return string footer data
|
||||
*/
|
||||
private function getFooter() {
|
||||
return '?>' . "\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* prepares the content of a language file
|
||||
*
|
||||
* @param array $localLang content of the given language
|
||||
* @param string $lang language shortcut
|
||||
* @return string language part of the main file
|
||||
*/
|
||||
private function getLangContent($localLang, $lang) {
|
||||
$content = "\t'$lang' => array (\n";
|
||||
if (is_array($localLang) && count($localLang)) {
|
||||
ksort($localLang);
|
||||
foreach ($localLang as $const => $value) {
|
||||
$value = preg_replace("/([^\\\])'/", "$1\'", $value);
|
||||
$value = str_replace("\r", '', $value);
|
||||
$content .= "\t\t'$const' => '$value',\n";
|
||||
}
|
||||
}
|
||||
$content .= "\t),\n";
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* prepares the content of a localized language file
|
||||
*
|
||||
* @param array $localLang content of the given language
|
||||
* @param string $lang language shortcut
|
||||
* @return string language content
|
||||
*/
|
||||
private function getLangContentLoc($localLang, $lang) {
|
||||
$content = '$LOCAL_LANG[\'' . $lang . '\'] = array (' . "\n";
|
||||
if (is_array($localLang) && count($localLang)) {
|
||||
ksort($localLang);
|
||||
foreach ($localLang as $const => $value) {
|
||||
$value = preg_replace("/([^\\\])'/", "$1\'", $value);
|
||||
$value = str_replace("\r", '', $value);
|
||||
$content .= "\t'$const' => '$value',\n";
|
||||
}
|
||||
}
|
||||
$content .= ");\n";
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* prepares the final content
|
||||
*
|
||||
* @param array | NULL $editedLanguages
|
||||
* @return array language files as key and content as value
|
||||
*/
|
||||
protected function prepareFileContents($editedLanguages = NULL) {
|
||||
// prepare Content
|
||||
$mainFileContent = '';
|
||||
$languages = SgLib::getSystemLanguages();
|
||||
$languageFiles = [];
|
||||
foreach ($languages as $lang) {
|
||||
// get content of localized and main file
|
||||
if ($this->checkLocalizedFile(basename($this->originLang[$lang]), $lang)) {
|
||||
if (is_array($this->localLang[$lang]) && count($this->localLang[$lang])) {
|
||||
$languageFiles[$this->originLang[$lang]] = $this->getHeader();
|
||||
$languageFiles[$this->originLang[$lang]] .=
|
||||
$this->getLangContentLoc($this->localLang[$lang], $lang);
|
||||
$languageFiles[$this->originLang[$lang]] .= $this->getFooter();
|
||||
$mainFileContent .= "\t'$lang' => 'EXT',\n";
|
||||
} else {
|
||||
$mainFileContent .= "\t'$lang' => '',\n";
|
||||
}
|
||||
} else {
|
||||
$mainFileContent .= $this->getLangContent($this->localLang[$lang], $lang);
|
||||
}
|
||||
}
|
||||
|
||||
// only a localized file?
|
||||
if ($this->checkLocalizedFile(basename($this->absFile), implode('|', SgLib::getSystemLanguages()))) {
|
||||
return $languageFiles;
|
||||
}
|
||||
|
||||
// prepare Content for the main file
|
||||
$languageFiles[$this->absFile] = $this->getHeader();
|
||||
$languageFiles[$this->absFile] .= '$LFMETA = array (' . "\n";
|
||||
$languageFiles[$this->absFile] .= $this->prepareMeta();
|
||||
$languageFiles[$this->absFile] .= ');' . "\n\n";
|
||||
$languageFiles[$this->absFile] .= '$LOCAL_LANG = array (' . "\n";
|
||||
$languageFiles[$this->absFile] .= $mainFileContent;
|
||||
$languageFiles[$this->absFile] .= ');' . "\n";
|
||||
$languageFiles[$this->absFile] .= $this->getFooter();
|
||||
|
||||
return $languageFiles;
|
||||
}
|
||||
}
|
||||
186
typo3conf/ext/lfeditor/Classes/Service/FileBaseService.php
Normal file
186
typo3conf/ext/lfeditor/Classes/Service/FileBaseService.php
Normal file
@@ -0,0 +1,186 @@
|
||||
<?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\Localization\Locales;
|
||||
use TYPO3\CMS\Core\Utility\ArrayUtility;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Core\Utility\PathUtility;
|
||||
|
||||
/**
|
||||
* base workspace class
|
||||
*/
|
||||
abstract class FileBaseService extends FileService {
|
||||
/**
|
||||
* @param string $content
|
||||
* @param string $lang
|
||||
* @return mixed
|
||||
*/
|
||||
abstract protected function getLocalizedFile($content, $lang);
|
||||
|
||||
/**
|
||||
* @param string $filename
|
||||
* @param string $langKey
|
||||
* @return mixed
|
||||
*/
|
||||
abstract public function checkLocalizedFile($filename, $langKey);
|
||||
|
||||
/**
|
||||
* @param string $langKey
|
||||
* @return mixed
|
||||
*/
|
||||
abstract public function nameLocalizedFile($langKey);
|
||||
|
||||
/**
|
||||
* @param string $file
|
||||
* @param string $langKey
|
||||
* @return mixed
|
||||
*/
|
||||
abstract protected function readLLFile($file, $langKey);
|
||||
|
||||
/**
|
||||
* extended init
|
||||
*
|
||||
* @param string $file name of the file (can be a path, if you need this (no check))
|
||||
* @param string $path path to the file
|
||||
* @param string $metaFile
|
||||
*
|
||||
* @return void
|
||||
* @throws \InvalidArgumentException
|
||||
* @throws LFException
|
||||
*/
|
||||
public function init($file, $path, $metaFile) {
|
||||
$locales = GeneralUtility::makeInstance(Locales::class);
|
||||
$availableLanguages = implode('|', $locales->getLocales());
|
||||
|
||||
// localization files should not be edited
|
||||
if ($this->checkLocalizedFile(basename($file), $availableLanguages)) {
|
||||
throw new LFException('failure.langfile.notSupported');
|
||||
}
|
||||
|
||||
$this->setWorkspace('base');
|
||||
parent::init($file, $path, $metaFile);
|
||||
}
|
||||
|
||||
/**
|
||||
* reads the absolute language file with all localized sub files
|
||||
*
|
||||
* @throws \Exception
|
||||
* @throws LFException
|
||||
* @return void
|
||||
*/
|
||||
public function readFile() {
|
||||
// read absolute file
|
||||
$localLang = $this->readLLFile($this->absFile, 'default');
|
||||
// loop all languages
|
||||
$languages = SgLib::getSystemLanguages();
|
||||
$originLang = [];
|
||||
foreach ($languages as $lang) {
|
||||
$originLang[$lang] = $this->absFile;
|
||||
if (!\array_key_exists($lang, $localLang)) {
|
||||
continue;
|
||||
}
|
||||
if ($lang === 'default' || (\is_array($localLang[$lang]) && \count($localLang[$lang]))) {
|
||||
if (\is_array($localLang[$lang]) && \count($localLang[$lang])) {
|
||||
\ksort($localLang[$lang]);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// get localized file
|
||||
$lFile = $this->getLocalizedFile($localLang[$lang], $lang);
|
||||
if ($lFile && $this->checkLocalizedFile(basename($lFile), $lang)) {
|
||||
$originLang[$lang] = $lFile;
|
||||
$localLang[$lang] = [];
|
||||
|
||||
if (!is_file($lFile)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// read the content
|
||||
try {
|
||||
$llang = $this->readLLFile($lFile, $lang);
|
||||
} catch (\Exception $e) {
|
||||
throw $e;
|
||||
}
|
||||
|
||||
// merge arrays and save origin of current language
|
||||
ArrayUtility::mergeRecursiveWithOverrule($localLang, $llang);
|
||||
}
|
||||
}
|
||||
|
||||
// check
|
||||
if (!\is_array($localLang)) {
|
||||
throw new LFException('failure.search.noFileContent');
|
||||
}
|
||||
|
||||
// copy all to object variables, if everything was ok
|
||||
$this->localLang = $localLang;
|
||||
$this->originLang = $originLang;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a localized file is found in labels pack (e.g. a language pack was downloaded in the backend)
|
||||
* or if $sameLocation is set, then checks for a file located in "{language}.locallang.xlf" at the same directory
|
||||
*
|
||||
* @param string $fileRef Absolute file reference to locallang file
|
||||
* @param string $language Language key
|
||||
* @param bool $sameLocation If TRUE, then locallang localization file name will be returned with same directory as $fileRef
|
||||
* @return string|null Absolute path to the language file, or null if error occurred
|
||||
*/
|
||||
protected function getLocalizedFileName($fileRef, $language, $sameLocation = FALSE) {
|
||||
// If $fileRef is already prefixed with "[language key]" then we should return it as is
|
||||
$fileName = PathUtility::basename($fileRef);
|
||||
if (GeneralUtility::isFirstPartOfStr($fileName, $language . '.')) {
|
||||
return GeneralUtility::getFileAbsFileName($fileRef);
|
||||
}
|
||||
|
||||
if ($sameLocation) {
|
||||
return GeneralUtility::getFileAbsFileName(str_replace($fileName, $language . '.' . $fileName, $fileRef));
|
||||
}
|
||||
|
||||
// Analyze file reference
|
||||
$validatedPrefix = Typo3Lib::getLocalizedFilePrefix($fileRef);
|
||||
if ($validatedPrefix) {
|
||||
// Divide file reference into extension key, directory (if any) and base name:
|
||||
[$extensionKey, $file_extPath] = explode('/', substr($fileRef, strlen($validatedPrefix)), 2);
|
||||
$temp = GeneralUtility::revExplode('/', $file_extPath, 2);
|
||||
if (count($temp) === 1) {
|
||||
array_unshift($temp, '');
|
||||
}
|
||||
// Add empty first-entry if not there.
|
||||
[$file_extPath, $file_fileName] = $temp;
|
||||
|
||||
// The filename is prefixed with "[language key]." because it prevents the llxmltranslate tool from detecting it.
|
||||
return Typo3Lib::getLabelsPath() . $language . '/' . $extensionKey . '/' . ($file_extPath ? $file_extPath . '/' : '') . $language . '.' . $file_fileName;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
429
typo3conf/ext/lfeditor/Classes/Service/FileBaseXLFService.php
Normal file
429
typo3conf/ext/lfeditor/Classes/Service/FileBaseXLFService.php
Normal file
@@ -0,0 +1,429 @@
|
||||
<?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\ExtensionUtility;
|
||||
use SGalinski\Lfeditor\Utility\SgLib;
|
||||
use SGalinski\Lfeditor\Utility\Typo3Lib;
|
||||
use TYPO3\CMS\Core\Utility\ArrayUtility;
|
||||
|
||||
/**
|
||||
* base workspace class (xlf)
|
||||
*/
|
||||
class FileBaseXLFService extends FileBaseService {
|
||||
/**
|
||||
* extended init
|
||||
*
|
||||
* @param string $file name of the file (can be a path, if you need this (no check))
|
||||
* @param string $path path to the file
|
||||
* @param string $metaFile
|
||||
* @return void
|
||||
* @throws LFException
|
||||
*/
|
||||
public function init($file, $path, $metaFile) {
|
||||
$this->setFileType('xlf');
|
||||
parent::init($file, $path, $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() {
|
||||
$this->readXlfFile();
|
||||
|
||||
foreach ($this->localLang['default'] as $constant => $value) {
|
||||
if (empty($value)) {
|
||||
$this->localLang['default'][$constant] = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* reads a language file
|
||||
*
|
||||
* @param string $file language file
|
||||
* @param string $langKey language shortcut
|
||||
* @return array language content
|
||||
* @throws LFException thrown if no data can be found
|
||||
*/
|
||||
protected function readLLFile($file, $langKey) {
|
||||
if (!\is_file($file)) {
|
||||
throw new LFException('failure.select.noLangfile');
|
||||
}
|
||||
|
||||
// LIBXML_NOCDATA treat CDATA node as text node.
|
||||
// htmlentities in CDATA are not modified,
|
||||
// and those - normaly encoded if XML is valid - outside CDATA will be decoded.
|
||||
|
||||
$xmlContent = \simplexml_load_string(\file_get_contents($file), \SimpleXMLElement::class, LIBXML_NOCDATA);
|
||||
|
||||
// Cast XML to associative array with json_decode/encode.
|
||||
// This way, value is XML are casted to string.
|
||||
$xmlContent = \json_decode(\json_encode($xmlContent), TRUE);
|
||||
|
||||
// check data
|
||||
if (!\is_array($xmlContent['file']['body'])) {
|
||||
throw new LFException('failure.search.noFileContent', 0, '(' . $file . ')');
|
||||
}
|
||||
|
||||
if ($langKey === 'default') {
|
||||
$this->meta = $xmlContent['file']['header'] ?? [];
|
||||
}
|
||||
$this->meta['@attributes'] = $xmlContent['file']['@attributes'];
|
||||
|
||||
return $xmlContent['file']['body'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves the trans-unit parts of the xlf language files into flat
|
||||
* source arrays with the target language or the source if the target is en
|
||||
*
|
||||
* @param array $sourceData
|
||||
* @return array
|
||||
*/
|
||||
public function resolveTranslationUnitsArrayIntoFlatArray(array $sourceData) {
|
||||
$flatData = [];
|
||||
|
||||
if (isset($sourceData['trans-unit']['@attributes'])) {
|
||||
$sourceData['trans-unit'] = [$sourceData['trans-unit']];
|
||||
}
|
||||
if (!array_key_exists('trans-unit', $sourceData)) {
|
||||
return $flatData;
|
||||
}
|
||||
|
||||
foreach ((array) $sourceData['trans-unit'] as $data) {
|
||||
if (isset($data['@attributes']['id'])) {
|
||||
$constant = $data['@attributes']['id'];
|
||||
if (array_key_exists('target', $data)) {
|
||||
$flatData[$constant] = $data['target'];
|
||||
} else {
|
||||
$flatData[$constant] = $data['source'];
|
||||
}
|
||||
|
||||
if (empty($flatData[$constant])) {
|
||||
$flatData[$constant] = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $flatData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the absolute language file with all localized sub files
|
||||
*
|
||||
* @return void
|
||||
* @throws LFException
|
||||
*/
|
||||
public function readXlfFile() {
|
||||
$localLang = [];
|
||||
// read absolute file
|
||||
$localLang['default'] = $this->readLLFile($this->absFile, 'default');
|
||||
$localLang['default'] = $this->resolveTranslationUnitsArrayIntoFlatArray($localLang['default']);
|
||||
|
||||
// loop all languages
|
||||
$originLang = [];
|
||||
$languages = SgLib::getSystemLanguages();
|
||||
foreach ($languages as $lang) {
|
||||
$originLang[$lang] = $this->absFile;
|
||||
if ($lang === 'default') {
|
||||
continue;
|
||||
}
|
||||
|
||||
// get localized file
|
||||
$content = array_key_exists($lang, $localLang) ? $localLang[$lang] : '';
|
||||
$lFile = $this->getLocalizedFile($content, $lang);
|
||||
if ($this->checkLocalizedFile(\basename($lFile), $lang)) {
|
||||
$originLang[$lang] = $lFile;
|
||||
$localLang[$lang] = [];
|
||||
|
||||
if (!\is_file($lFile)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// read the content
|
||||
$localSubLanguage = $this->readLLFile($lFile, $lang);
|
||||
$localLang[$lang] = $this->resolveTranslationUnitsArrayIntoFlatArray($localSubLanguage);
|
||||
|
||||
// merge arrays and save origin of current language
|
||||
ArrayUtility::mergeRecursiveWithOverrule($localLang, $localSubLanguage);
|
||||
}
|
||||
}
|
||||
|
||||
// copy all to object variables, if everything was ok
|
||||
$this->localLang = $localLang;
|
||||
$this->originLang = $originLang;
|
||||
}
|
||||
|
||||
/**
|
||||
* checks the localLang array to find localized version of the language
|
||||
* (checks l10n directory too)
|
||||
*
|
||||
* @param string $content language content (only one language)
|
||||
* @param string $langKey language shortcut
|
||||
* @return string localized file (absolute)
|
||||
*/
|
||||
protected function getLocalizedFile($content, $langKey) {
|
||||
$file = '';
|
||||
if ($this->session->getDataByKey('editingMode') !== 'extension') {
|
||||
$file = $this->getLocalizedFileName($this->absFile, $langKey);
|
||||
}
|
||||
if (!\is_file($file)) {
|
||||
$file = \dirname($this->absFile) . '/' . $this->nameLocalizedFile($langKey);
|
||||
}
|
||||
return Typo3Lib::fixFilePath($file);
|
||||
}
|
||||
|
||||
/**
|
||||
* checks a filename if its a localized file reference
|
||||
*
|
||||
* @param string $filename
|
||||
* @param string $langKey language shortcut
|
||||
* @return boolean true(localized) or false
|
||||
*/
|
||||
public function checkLocalizedFile($filename, $langKey) {
|
||||
if (!\preg_match('/^(' . $langKey . ')\..*\.xlf$/', $filename)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the name of a localized file
|
||||
*
|
||||
* @param string $langKey language shortcut
|
||||
* @return string localized file (only filename)
|
||||
*/
|
||||
public function nameLocalizedFile($langKey) {
|
||||
return $langKey . '.' . \basename($this->relFile);
|
||||
}
|
||||
|
||||
/**
|
||||
* generates the xml header
|
||||
*
|
||||
* @return string xml header
|
||||
*/
|
||||
private function getXMLHeader() {
|
||||
return '<?xml version="1.0" encoding="utf-8" standalone="yes" ?>' . "\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* converts the array to a xml string
|
||||
*
|
||||
* @param array $phpArray
|
||||
* @param string $targetLanguage
|
||||
* @param array $enLanguage
|
||||
* @return string xml content
|
||||
*/
|
||||
private function array2xml($phpArray, $targetLanguage, $enLanguage) {
|
||||
$targetLanguage = \htmlspecialchars($targetLanguage);
|
||||
$targetLanguageAttribute = ($targetLanguage !== 'default' ? ' target-language="' . $targetLanguage . '"' : '');
|
||||
|
||||
$lfeditorExtConf = ExtensionUtility::getExtensionConfiguration();
|
||||
$date = ($lfeditorExtConf['changeXlfDate'] ? \gmdate('Y-m-d\TH:i:s\Z') : $this->meta['@attributes']['date']);
|
||||
|
||||
$xmlString = $this->getXMLHeader() . '<xliff version="1.0">
|
||||
<file source-language="en"' . $targetLanguageAttribute . ' datatype="plaintext" original="messages" date="' . $date . '">
|
||||
###HEADER###
|
||||
###BODY###
|
||||
</file>
|
||||
</xliff>';
|
||||
|
||||
$header = '<header/>';
|
||||
if (\is_array($phpArray['header']) && \count($phpArray['header'])) {
|
||||
$header = '<header>' . "\n";
|
||||
foreach ($phpArray['header'] as $tagName => $tagValue) {
|
||||
$tagName = \htmlspecialchars($tagName);
|
||||
$header .= "\t\t\t" . '<' . $tagName . '>' . \htmlspecialchars(implode(' ', $tagValue)) .
|
||||
'</' . $tagName . '>' . "\n";
|
||||
}
|
||||
$header .= "\t\t" . '</header>';
|
||||
}
|
||||
$xmlString = \str_replace('###HEADER###', $header, $xmlString);
|
||||
|
||||
$body = '<body/>';
|
||||
if (\is_array($phpArray['data']) && \count($phpArray['data'])) {
|
||||
$body = '<body>' . "\n";
|
||||
$startCDATA = "<![CDATA[";
|
||||
$endCDATA = "]]>";
|
||||
$approved = ($targetLanguage !== 'default' ? ' approved="yes"' : '');
|
||||
foreach ($phpArray['data'] as $constant => $value) {
|
||||
if (!array_key_exists($constant, $enLanguage)) {
|
||||
continue;
|
||||
}
|
||||
$enValue = $enLanguage[$constant];
|
||||
|
||||
// CDATA markers are stripped when reading the XML file from the disk,
|
||||
// and html entities are not decoded.
|
||||
// So, for simplicity and safety, when writing back the data to the file,
|
||||
// we will always enclose value in CDATA, so html entities are preserved
|
||||
// and XML remains valid.
|
||||
$value = $startCDATA . $value . $endCDATA;
|
||||
$enValue = $startCDATA . $enValue . $endCDATA;
|
||||
|
||||
$body .= "\t\t\t" . '<trans-unit id="' . \htmlspecialchars(
|
||||
$constant
|
||||
) . '"' . $approved . $this->addPreserveSpaceAttribute(
|
||||
$value,
|
||||
$enValue,
|
||||
$targetLanguage
|
||||
) . '>' . "\n";
|
||||
|
||||
if ($targetLanguage !== 'default') {
|
||||
$body .= "\t\t\t\t" . '<source>' . $enValue . '</source>' . "\n";
|
||||
$body .= "\t\t\t\t" . '<target>' . $value . '</target>' . "\n";
|
||||
} else {
|
||||
$body .= "\t\t\t\t" . '<source>' . $value . '</source>' . "\n";
|
||||
}
|
||||
$body .= "\t\t\t" . '</trans-unit>' . "\n";
|
||||
}
|
||||
$body .= "\t\t" . '</body>';
|
||||
}
|
||||
$xmlString = \str_replace('###BODY###', $body, $xmlString);
|
||||
|
||||
return $xmlString;
|
||||
}
|
||||
|
||||
/**
|
||||
* prepares the content of a language file
|
||||
*
|
||||
* @param array $localLang
|
||||
* @return array new xml array
|
||||
*/
|
||||
private function getLangContent($localLang) {
|
||||
$content = [];
|
||||
if (!\is_array($localLang) || !\count($localLang)) {
|
||||
return $content;
|
||||
}
|
||||
|
||||
\ksort($localLang);
|
||||
foreach ($localLang as $const => $value) {
|
||||
$content[$const] = \str_replace("\r", '', $value);
|
||||
}
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* prepares the meta array for nicer saving
|
||||
*
|
||||
* @return array meta content
|
||||
*/
|
||||
private function prepareMeta() {
|
||||
if (\is_array($this->meta) && \count($this->meta)) {
|
||||
foreach ($this->meta as $label => $value) {
|
||||
$this->meta[$label] = \str_replace("\r", '', $value);
|
||||
}
|
||||
}
|
||||
$this->addGeneratorString();
|
||||
|
||||
$metadata = $this->meta;
|
||||
unset($metadata['@attributes']);
|
||||
|
||||
return $metadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* prepares the final content
|
||||
*
|
||||
* @param array | NULL $editedLanguages
|
||||
* @return array language files as key and content as value
|
||||
*/
|
||||
protected function prepareFileContents($editedLanguages = NULL) {
|
||||
// prepare Content
|
||||
$metaData = $this->prepareMeta();
|
||||
$languages = SgLib::getSystemLanguages();
|
||||
$languageFiles = [];
|
||||
$enLanguage = $this->getLangContent($this->localLang['default']);
|
||||
foreach ($languages as $lang) {
|
||||
if ($lang === 'default') {
|
||||
continue;
|
||||
}
|
||||
// If default language content and $lang language content are not edited, skip this file.
|
||||
if ($editedLanguages !== NULL &&
|
||||
!\in_array('default', $editedLanguages, TRUE) && !\in_array($lang, $editedLanguages, TRUE)
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (\array_key_exists($lang, $this->localLang) && \is_array($this->localLang[$lang]) && \count(
|
||||
$this->localLang[$lang]
|
||||
)) {
|
||||
$file = $this->originLang[$lang];
|
||||
$data = [
|
||||
'header' => $metaData,
|
||||
'data' => $this->getLangContent($this->localLang[$lang]),
|
||||
];
|
||||
if (array_key_exists($file, $languageFiles)) {
|
||||
$languageFiles[$file] .= $this->array2xml($data, $lang, $enLanguage);
|
||||
} else {
|
||||
$languageFiles[$file] = $this->array2xml($data, $lang, $enLanguage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// only a localized file?
|
||||
if ($this->checkLocalizedFile(\basename($this->absFile), \implode('|', SgLib::getSystemLanguages()))) {
|
||||
return $languageFiles;
|
||||
}
|
||||
if ($editedLanguages !== NULL && !\in_array('default', $editedLanguages, TRUE)) {
|
||||
return $languageFiles;
|
||||
}
|
||||
|
||||
// prepare content for the main file
|
||||
$data = [
|
||||
'header' => $metaData,
|
||||
'data' => $enLanguage,
|
||||
];
|
||||
$languageFiles[$this->absFile] = $this->array2xml($data, 'default', $enLanguage);
|
||||
|
||||
return $languageFiles;
|
||||
}
|
||||
|
||||
/**
|
||||
* If constant's source (en) or target value contains multiple spaces or LF character,
|
||||
* returns string ' xml:space="preserve"'.
|
||||
*
|
||||
* @param string $value
|
||||
* @param string $enValue
|
||||
* @param string $targetLanguage
|
||||
* @return string
|
||||
*/
|
||||
protected function addPreserveSpaceAttribute($value, $enValue, $targetLanguage) {
|
||||
$valueContainsSpacesOrLF = \strpos($value, ' ') !== FALSE || \strpos($value, "\n") !== FALSE;
|
||||
$enValueContainsSpacesOrLF = FALSE;
|
||||
if ($targetLanguage !== 'default') {
|
||||
$enValueContainsSpacesOrLF = \strpos($enValue, ' ') !== FALSE || \strpos($enValue, "\n") !== FALSE;
|
||||
}
|
||||
return ($valueContainsSpacesOrLF || $enValueContainsSpacesOrLF ? ' xml:space="preserve"' : '');
|
||||
}
|
||||
}
|
||||
358
typo3conf/ext/lfeditor/Classes/Service/FileBaseXMLService.php
Normal file
358
typo3conf/ext/lfeditor/Classes/Service/FileBaseXMLService.php
Normal file
@@ -0,0 +1,358 @@
|
||||
<?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 DOMDocument;
|
||||
use Exception;
|
||||
use SGalinski\Lfeditor\Exceptions\LFException;
|
||||
use SGalinski\Lfeditor\Utility\CdataSupportingSimpleXMLElement;
|
||||
use SGalinski\Lfeditor\Utility\SgLib;
|
||||
use SGalinski\Lfeditor\Utility\Typo3Lib;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
|
||||
/**
|
||||
* base workspace class (xml)
|
||||
*/
|
||||
class FileBaseXMLService extends FileBaseService {
|
||||
/**
|
||||
* extended init
|
||||
*
|
||||
* @param string $file name of the file (can be a path, if you need this (no check))
|
||||
* @param string $path path to the file
|
||||
*
|
||||
* @param string $metaFile
|
||||
* @return void
|
||||
* @throws LFException
|
||||
*/
|
||||
public function init($file, $path, $metaFile) {
|
||||
$this->setVar(['fileType' => 'xml']);
|
||||
parent::init($file, $path, $metaFile);
|
||||
}
|
||||
|
||||
/**
|
||||
* reads a language file
|
||||
*
|
||||
* @throws LFException raised if the file does not contain a valid llxml or xml is not valid
|
||||
* @param string $file language file
|
||||
* @param string $langKey language shortcut
|
||||
* @return array language content
|
||||
*/
|
||||
protected function readLLFile($file, $langKey) {
|
||||
if (!\is_file($file)) {
|
||||
throw new LFException('failure.select.noLangfile');
|
||||
}
|
||||
|
||||
// read xml into array
|
||||
$xmlContent = GeneralUtility::xml2array(\file_get_contents($file));
|
||||
|
||||
// check data
|
||||
if (!\is_array($xmlContent['data'])) {
|
||||
throw new LFException('failure.search.noFileContent', 0, '(' . $file . ')');
|
||||
}
|
||||
|
||||
// set header data
|
||||
if ($langKey === 'default') {
|
||||
$this->meta = $xmlContent['meta'];
|
||||
}
|
||||
|
||||
return $xmlContent['data'];
|
||||
}
|
||||
|
||||
/**
|
||||
* checks the localLang array to find localized version of the language
|
||||
* (checks l10n directory too)
|
||||
*
|
||||
* @param string $content language content (only one language)
|
||||
* @param string $langKey language shortcut
|
||||
* @return string localized file (absolute)
|
||||
*/
|
||||
protected function getLocalizedFile($content, $langKey) {
|
||||
if ($this->session->getDataByKey('editingMode') === 'l10n') {
|
||||
$file = $this->getLocalizedFileName($this->absFile, $langKey);
|
||||
if (\is_file($file)) {
|
||||
return Typo3Lib::fixFilePath($file);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
$file = Typo3Lib::transTypo3File($content, TRUE);
|
||||
} catch (Exception $e) {
|
||||
if (!$file = $this->getLocalizedFileName($this->absFile, $langKey, TRUE)) {
|
||||
return $content;
|
||||
}
|
||||
if (!\is_file($file)) {
|
||||
return $content;
|
||||
}
|
||||
}
|
||||
|
||||
return Typo3Lib::fixFilePath($file);
|
||||
}
|
||||
|
||||
/**
|
||||
* checks a filename if its a localized file reference
|
||||
*
|
||||
* @param string $filename filename
|
||||
* @param string $langKey language shortcut
|
||||
* @return boolean true(localized) or false
|
||||
*/
|
||||
public function checkLocalizedFile($filename, $langKey) {
|
||||
if (!\preg_match('/^(' . $langKey . ')\..*\.xml$/', $filename)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the name of a localized file
|
||||
*
|
||||
* @param string $langKey language shortcut
|
||||
* @return string localized file (only filename)
|
||||
*/
|
||||
public function nameLocalizedFile($langKey) {
|
||||
return $langKey . '.' . \basename($this->relFile);
|
||||
}
|
||||
|
||||
/**
|
||||
* generates the xml header
|
||||
*
|
||||
* @return string xml header
|
||||
*/
|
||||
private function getXMLHeader() {
|
||||
return '<?xml version="1.0" encoding="utf-8" standalone="yes" ?>' . "\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts php array to xml string with support for CDATA tags.
|
||||
*
|
||||
* @param array $phpArray
|
||||
* @param CdataSupportingSimpleXMLElement $xmlElement
|
||||
* @param array $parentTagMap
|
||||
* @param string $parentTagName
|
||||
* @return void
|
||||
*/
|
||||
protected function arrayToXml(
|
||||
array $phpArray,
|
||||
CdataSupportingSimpleXMLElement $xmlElement,
|
||||
array $parentTagMap = [],
|
||||
$parentTagName = NULL
|
||||
) {
|
||||
foreach ($phpArray as $key => $value) {
|
||||
if (\strcasecmp($key, '@attributes') === 0) {
|
||||
continue;
|
||||
}
|
||||
$tagName = $key;
|
||||
$indexAttributeValue = NULL;
|
||||
if (\count($parentTagMap) !== 0 && !empty($parentTagMap[$parentTagName])) {
|
||||
$tagName = $parentTagMap[$parentTagName];
|
||||
$indexAttributeValue = $key;
|
||||
}
|
||||
// If element is array, check that it is not 'label' tag, just in case
|
||||
if (\is_array($value) && $tagName !== 'label') {
|
||||
if (\is_numeric($tagName)) {
|
||||
$tagName = 'item' . $tagName;
|
||||
}
|
||||
$subNode = $xmlElement->addChild($tagName);
|
||||
if ($indexAttributeValue !== NULL) {
|
||||
$subNode->addAttribute('index', $indexAttributeValue);
|
||||
}
|
||||
$subNode->addAttribute('type', 'array');
|
||||
$this->arrayToXml($value, $subNode, $parentTagMap, $tagName);
|
||||
} else {
|
||||
// CDATA markers are stripped when reading the XML file from the disk,
|
||||
// and html entities are not decoded.
|
||||
// So, for simplicity and safety, when writing back the data to the file,
|
||||
// we will always enclose value in CDATA, so html entities are preserved
|
||||
// and XML remains valid.
|
||||
$simpleSubNode = $xmlElement->addChildCData($tagName, $value);
|
||||
if ($indexAttributeValue !== NULL) {
|
||||
$simpleSubNode->addAttribute('index', $indexAttributeValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts php array to formatted xml string with support for CDATA tags.
|
||||
*
|
||||
* @param array $phpArray php structure with data
|
||||
* @param string $firstTag name of first tag
|
||||
* @return string xml content
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function array2xml(array $phpArray, $firstTag) {
|
||||
if (\count($phpArray) === 0) {
|
||||
return '';
|
||||
}
|
||||
|
||||
/** @var CdataSupportingSimpleXMLElement $xmlElement */
|
||||
$xmlElement = new CdataSupportingSimpleXMLElement(
|
||||
$this->getXMLHeader() . '<' . $firstTag . '></' . $firstTag . '>'
|
||||
);
|
||||
$xmlElement->addAttribute('type', 'array');
|
||||
|
||||
$parentTagMap = [
|
||||
'data' => 'languageKey',
|
||||
'languageKey' => 'label',
|
||||
];
|
||||
|
||||
$this->arrayToXml($phpArray, $xmlElement, $parentTagMap);
|
||||
$formattedXml = $this->formatXml($xmlElement);
|
||||
|
||||
return $formattedXml;
|
||||
}
|
||||
|
||||
/**
|
||||
* prepares the content of a language file
|
||||
*
|
||||
* @param array $localLang content of the given language
|
||||
* @param string $lang shortcut
|
||||
* @return array new xml array
|
||||
*/
|
||||
private function getLangContent($localLang, $lang) {
|
||||
$content = [];
|
||||
$content['data'][$lang] = '';
|
||||
if (!\is_array($localLang) || !\count($localLang)) {
|
||||
return $content;
|
||||
}
|
||||
|
||||
\ksort($localLang);
|
||||
foreach ($localLang as $const => $value) {
|
||||
if ($content['data'][$lang] === '') {
|
||||
$content['data'][$lang] = [];
|
||||
}
|
||||
|
||||
$content['data'][$lang][$const] = \str_replace("\r", '', $value);
|
||||
}
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* prepares the meta array for nicer saving
|
||||
*
|
||||
* @return array meta content
|
||||
*/
|
||||
private function prepareMeta() {
|
||||
if (\is_array($this->meta) && \count($this->meta)) {
|
||||
foreach ($this->meta as $label => $value) {
|
||||
$this->meta[$label] = \str_replace("\r", '', $value);
|
||||
}
|
||||
}
|
||||
$this->addGeneratorString();
|
||||
|
||||
return $this->meta;
|
||||
}
|
||||
|
||||
/**
|
||||
* prepares the final content
|
||||
*
|
||||
* @param array | NULL $editedLanguages
|
||||
* @return array language files as key and content as value
|
||||
*/
|
||||
protected function prepareFileContents($editedLanguages = NULL) {
|
||||
$mergedFile = TRUE;
|
||||
|
||||
// prepare Content
|
||||
$mainFileContent = ['meta' => $this->prepareMeta()];
|
||||
$languages = SgLib::getSystemLanguages();
|
||||
$languageFiles = [];
|
||||
foreach ($languages as $lang) {
|
||||
// get content of localized and main file
|
||||
if (array_key_exists($lang, $this->originLang) && $this->checkLocalizedFile(\basename($this->originLang[$lang]), $lang)) {
|
||||
$mergedFile = FALSE;
|
||||
if (\is_array($this->localLang[$lang]) && \count($this->localLang[$lang])
|
||||
// check if this language content was edited
|
||||
&& (NULL === $editedLanguages || \in_array($lang, $editedLanguages, TRUE))
|
||||
) {
|
||||
$languageFiles[$this->originLang[$lang]] .=
|
||||
$this->array2xml(
|
||||
$this->getLangContent($this->localLang[$lang], $lang),
|
||||
'T3locallangExt'
|
||||
);
|
||||
|
||||
try {
|
||||
$mainFileContent['data'][$lang] =
|
||||
Typo3Lib::transTypo3File($this->originLang[$lang], FALSE);
|
||||
} catch (Exception $e) {
|
||||
if (!Typo3Lib::checkFileLocation($this->originLang[$lang]) == 'l10n') {
|
||||
$mainFileContent['data'][$lang] = $this->originLang[$lang];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$mainFileContent['data'][$lang] = '';
|
||||
}
|
||||
} elseif (array_key_exists($lang, $this->localLang)) {
|
||||
$mainFileContent = \array_merge_recursive(
|
||||
$mainFileContent,
|
||||
$this->getLangContent($this->localLang[$lang], $lang)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// only a localized file?
|
||||
if ($this->checkLocalizedFile(\basename($this->absFile), \implode('|', SgLib::getSystemLanguages()))) {
|
||||
return $languageFiles;
|
||||
}
|
||||
if (!$mergedFile && $editedLanguages !== NULL && !\in_array('default', $editedLanguages, TRUE)) {
|
||||
return $languageFiles;
|
||||
}
|
||||
|
||||
// prepare Content for the main file
|
||||
$languageFiles[$this->absFile] = $this->array2xml($mainFileContent, 'T3locallang');
|
||||
|
||||
return $languageFiles;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats xml and returns as a string.
|
||||
*
|
||||
* @param \SimpleXMLElement $xmlElement
|
||||
* @return string
|
||||
*/
|
||||
private function formatXml(\SimpleXMLElement $xmlElement) {
|
||||
$dom = new DOMDocument('1.0');
|
||||
$dom->preserveWhiteSpace = FALSE;
|
||||
$dom->formatOutput = TRUE;
|
||||
|
||||
$xmlRaw = $xmlElement->asXML();
|
||||
|
||||
//Search CDATA tags to decode the content inside
|
||||
//Because $xmlElement->asXML() encode html entities
|
||||
$xmlRaw = preg_replace_callback(
|
||||
"#(<\!\[CDATA\[.*\]\]>)#sU",
|
||||
function ($matches) {
|
||||
return htmlspecialchars_decode($matches[1]);
|
||||
},
|
||||
$xmlRaw
|
||||
);
|
||||
$dom->loadXML($xmlRaw);
|
||||
|
||||
$formattedXml = $dom->saveXML();
|
||||
return $formattedXml;
|
||||
}
|
||||
}
|
||||
360
typo3conf/ext/lfeditor/Classes/Service/FileOverrideService.php
Normal file
360
typo3conf/ext/lfeditor/Classes/Service/FileOverrideService.php
Normal file
@@ -0,0 +1,360 @@
|
||||
<?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';
|
||||
}
|
||||
}
|
||||
}
|
||||
487
typo3conf/ext/lfeditor/Classes/Service/FileService.php
Normal file
487
typo3conf/ext/lfeditor/Classes/Service/FileService.php
Normal file
@@ -0,0 +1,487 @@
|
||||
<?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\Utility\GeneralUtility;
|
||||
|
||||
/**
|
||||
* include some general functions only usable for the 'lfeditor' module
|
||||
*/
|
||||
abstract class FileService extends AbstractService {
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $localLang = [];
|
||||
|
||||
/**
|
||||
* Absolute address (origin) of language file
|
||||
* which contains translation for language given as a key of the array.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $originLang = [];
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $absPath;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $relFile;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $absFile;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $fileType;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $workspace;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $meta = [];
|
||||
|
||||
/**
|
||||
* @param array|NULL $editedLanguages
|
||||
* @return mixed
|
||||
*/
|
||||
abstract protected function prepareFileContents($editedLanguages);
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
abstract public function readFile();
|
||||
|
||||
/**
|
||||
* sets some variables
|
||||
*
|
||||
* @param string $file filename or relative path from second param to the language file
|
||||
* @param string $path absolute path to the extension or language file
|
||||
* @param string $metaFile absolute path to the meta file (includes filename) DO NOT REMOVE! It's required in some
|
||||
* implementations.
|
||||
* @return void
|
||||
*/
|
||||
public function init($file, $path, $metaFile) {
|
||||
$this->setAbsPath($path);
|
||||
$this->setRelFile($file);
|
||||
$this->setAbsFile($this->absPath . '/' . $this->relFile);
|
||||
}
|
||||
|
||||
/**
|
||||
* sets information
|
||||
*
|
||||
* structure:
|
||||
* $infos["absPath"] = absolute path to an extension or file
|
||||
* $infos["relFile"] = relative path with filename from "absPath"
|
||||
* $infos["workspace"] = workspace (base or xll)
|
||||
* $infos["fileType"] = file type (php or xml)
|
||||
* $infos["localLang"] = language data
|
||||
* $infos["originLang"] = origin language array
|
||||
* $infos["meta"] = meta data
|
||||
*
|
||||
* @param array $informations
|
||||
* @return void
|
||||
*/
|
||||
public function setVar($informations) {
|
||||
// path and file information
|
||||
if (!empty($informations['absPath'])) {
|
||||
$this->absPath = Typo3Lib::fixFilePath($informations['absPath'] . '/');
|
||||
}
|
||||
if (!empty($informations['relFile'])) {
|
||||
$this->relFile = Typo3Lib::fixFilePath($informations['relFile']);
|
||||
}
|
||||
$this->absFile = $this->absPath . $this->relFile;
|
||||
|
||||
// file type and workspace
|
||||
if (!empty($informations['workspace'])) {
|
||||
$this->workspace = $informations['workspace'];
|
||||
}
|
||||
if (!empty($informations['fileType'])) {
|
||||
$this->fileType = $informations['fileType'];
|
||||
}
|
||||
|
||||
// data arrays
|
||||
if (!count($this->localLang) && array_key_exists('localLang', $informations) && is_array($informations['localLang'])) {
|
||||
$this->localLang = $informations['localLang'];
|
||||
}
|
||||
if (!count($this->originLang) && array_key_exists('originLang', $informations) && is_array($informations['originLang'])) {
|
||||
$this->originLang = $informations['originLang'];
|
||||
}
|
||||
if (!count($this->meta) && array_key_exists('meta', $informations) && is_array($informations['meta'])) {
|
||||
$this->meta = $informations['meta'];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* returns requested information
|
||||
*
|
||||
* @param string $info
|
||||
* @return string
|
||||
*/
|
||||
public function getVar($info) {
|
||||
$value = '';
|
||||
if ($info == 'relFile') {
|
||||
$value = $this->relFile;
|
||||
} elseif ($info == 'absPath') {
|
||||
$value = $this->absPath;
|
||||
} elseif ($info == 'absFile') {
|
||||
$value = $this->absFile;
|
||||
} elseif ($info == 'fileType') {
|
||||
$value = $this->fileType;
|
||||
} elseif ($info == 'workspace') {
|
||||
$value = $this->workspace;
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns language data
|
||||
*
|
||||
* @param string $langKey valid language key
|
||||
* @return array language data
|
||||
*/
|
||||
public function getLocalLangData($langKey = '') {
|
||||
if (empty($langKey)) {
|
||||
return $this->localLang;
|
||||
}
|
||||
if (array_key_exists($langKey, $this->localLang) && is_array($this->localLang[$langKey])) {
|
||||
return $this->localLang[$langKey];
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* deletes or sets constants in local language data
|
||||
*
|
||||
* @param string $constant constant name (if empty an index number will be used)
|
||||
* @param string $value new value (if empty the constant will be deleted)
|
||||
* @param string $langKey language shortcut
|
||||
* @param boolean $forceDel set to true, if you want delete default values too
|
||||
* @return void
|
||||
*/
|
||||
public function setLocalLangData($constant, $value, $langKey, $forceDel = FALSE) {
|
||||
if (!empty($value) || (($langKey === 'default' && !$forceDel))) {
|
||||
if (!array_key_exists($langKey, $this->localLang) || $this->localLang[$langKey] === '') {
|
||||
$this->localLang[$langKey] = [];
|
||||
}
|
||||
$this->localLang[$langKey][$constant] = $value;
|
||||
} elseif (isset($this->localLang[$langKey][$constant])) {
|
||||
if ($this->session->getDataByKey('editingMode') === 'override' &&
|
||||
isset($this->localLang[$langKey][$constant])
|
||||
) {
|
||||
$this->localLang[$langKey][$constant] = "";
|
||||
} else {
|
||||
unset($this->localLang[$langKey][$constant]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* returns origin
|
||||
*
|
||||
* @param string $langKey valid language key
|
||||
* @return mixed an origin or full array
|
||||
*/
|
||||
public function getOriginLangData($langKey = '') {
|
||||
if (empty($langKey)) {
|
||||
return $this->originLang;
|
||||
} else {
|
||||
return $this->originLang[$langKey] ?? [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* sets new origin of a given language
|
||||
*
|
||||
* @param string $origin new origin
|
||||
* @param string $langKey language shortcut
|
||||
* @return void
|
||||
*/
|
||||
public function setOriginLangData($origin, $langKey) {
|
||||
if (!empty($origin)) {
|
||||
$this->originLang[$langKey] = $origin;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* returns meta data
|
||||
*
|
||||
* @param string $metaIndex special meta index
|
||||
* @return mixed meta data
|
||||
*/
|
||||
public function getMetaData($metaIndex = '') {
|
||||
if (!empty($metaIndex)) {
|
||||
return $this->meta[$metaIndex] ?? '';
|
||||
} else {
|
||||
return $this->meta;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* deletes or sets constants in meta data
|
||||
*
|
||||
* @param string $metaIndex
|
||||
* @param string $value new value (if empty the meta index will be deleted)
|
||||
* @return void
|
||||
*/
|
||||
public function setMetaData($metaIndex, $value) {
|
||||
if (!empty($value)) {
|
||||
$this->meta[$metaIndex] = $value;
|
||||
} elseif (isset($this->meta[$metaIndex])) {
|
||||
unset($this->meta[$metaIndex]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* writes language files
|
||||
*
|
||||
* @param array | NULL $editedLanguages
|
||||
* @throws LFException raised if a file cant be written
|
||||
* @return void
|
||||
*/
|
||||
public function writeFile($editedLanguages = NULL) {
|
||||
// get prepared language files
|
||||
$languageFiles = $this->prepareFileContents($editedLanguages);
|
||||
$this->writeFilesWithContent($languageFiles);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the given files with the given content.
|
||||
*
|
||||
* Array structure:
|
||||
* array (
|
||||
* '/var/www/file.xlf' => 'My content',
|
||||
* ...
|
||||
* )
|
||||
*
|
||||
* @param array $files
|
||||
* @throws LFException
|
||||
* @return void
|
||||
*/
|
||||
public function writeFilesWithContent(array $files = []) {
|
||||
// check write permissions of all files
|
||||
foreach ($files as $file => $content) {
|
||||
[$extensionNameFromFile, $extPrefixedPath] = Typo3Lib::getExtNameFromOverrideFile($file);
|
||||
if (strpos($extensionNameFromFile, '-') !== FALSE) {
|
||||
$file = str_replace(
|
||||
$extensionNameFromFile,
|
||||
str_replace('-', '_', $extensionNameFromFile),
|
||||
$file
|
||||
);
|
||||
}
|
||||
if (!SgLib::checkWritePerms($file)) {
|
||||
throw new LFException('failure.file.badPermissions');
|
||||
}
|
||||
}
|
||||
|
||||
// write files
|
||||
foreach ($files as $file => $content) {
|
||||
[$extensionNameFromFile, $extPrefixedPath] = Typo3Lib::getExtNameFromOverrideFile($file);
|
||||
if (strpos($extensionNameFromFile, '-') !== FALSE) {
|
||||
$file = str_replace(
|
||||
$extensionNameFromFile,
|
||||
str_replace('-', '_', $extensionNameFromFile),
|
||||
$file
|
||||
);
|
||||
}
|
||||
if (!GeneralUtility::writeFile($file, $content)) {
|
||||
throw new LFException('failure.file.notWritten');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes generator meta tag.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function addGeneratorString() {
|
||||
$this->meta['generator'] = 'LFEditor';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns $absFile.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getAbsFile() {
|
||||
return $this->absFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets $absFile.
|
||||
*
|
||||
* @param string $absFile
|
||||
* @return void
|
||||
*/
|
||||
public function setAbsFile($absFile) {
|
||||
$this->absFile = $absFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns $absPath - absolute path to an extension or file.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getAbsPath() {
|
||||
return $this->absPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets $absPath - absolute path to an extension or file.
|
||||
*
|
||||
* @param string $absPath
|
||||
* @return void
|
||||
*/
|
||||
public function setAbsPath($absPath) {
|
||||
$this->absPath = $absPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns $fileType
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getFileType() {
|
||||
return $this->fileType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets $fileType.
|
||||
*
|
||||
* @param string $fileType
|
||||
* @return void
|
||||
*/
|
||||
public function setFileType($fileType) {
|
||||
$this->fileType = $fileType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns $locallang
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getLocalLang() {
|
||||
return $this->localLang;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets $locallang.
|
||||
*
|
||||
* @param array $localLang
|
||||
*/
|
||||
public function setLocalLang(array $localLang) {
|
||||
$this->localLang = $localLang;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns meta data.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getMeta() {
|
||||
return $this->meta;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets meta data.
|
||||
*
|
||||
* @param array $meta
|
||||
*/
|
||||
public function setMeta(array $meta) {
|
||||
$this->meta = $meta;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns $originLang.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getOriginLang() {
|
||||
return $this->originLang;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets $originLang.
|
||||
*
|
||||
* @param array $originLang
|
||||
*/
|
||||
public function setOriginLang(array $originLang) {
|
||||
$this->originLang = $originLang;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns relFile - relative path with filename from "absPath".
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getRelFile() {
|
||||
return $this->relFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets relFile - relative path with filename from "absPath".
|
||||
*
|
||||
* @param string $relFile
|
||||
*/
|
||||
public function setRelFile($relFile) {
|
||||
$this->relFile = $relFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns workspace.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getWorkspace() {
|
||||
return $this->workspace;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets workspace.
|
||||
*
|
||||
* @param string $workspace
|
||||
*/
|
||||
public function setWorkspace($workspace) {
|
||||
$this->workspace = $workspace;
|
||||
}
|
||||
}
|
||||
125
typo3conf/ext/lfeditor/Classes/Service/LicensingService.php
Normal file
125
typo3conf/ext/lfeditor/Classes/Service/LicensingService.php
Normal file
@@ -0,0 +1,125 @@
|
||||
<?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 Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use SGalinski\Lfeditor\Utility\ExtensionUtility;
|
||||
use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
|
||||
use TYPO3\CMS\Core\Http\NullResponse;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
|
||||
/**
|
||||
* Class SGalinski\SgRoutes\Service\LicensingService
|
||||
*/
|
||||
class LicensingService {
|
||||
/**
|
||||
* Licensing Service Url
|
||||
*/
|
||||
public const URL = 'https://www.sgalinski.de/?eID=sgLicensing';
|
||||
|
||||
/**
|
||||
* Licensing Service Url
|
||||
*/
|
||||
public const EXTENSION_KEY = 'lfeditor';
|
||||
|
||||
/**
|
||||
* @var null|bool $isLicenseKeyValid
|
||||
*/
|
||||
private static $isLicenseKeyValid = NULL;
|
||||
|
||||
/**
|
||||
* @return boolean
|
||||
*/
|
||||
public static function checkKey() {
|
||||
if (static::$isLicenseKeyValid === NULL) {
|
||||
static::$isLicenseKeyValid = FALSE;
|
||||
$configuration = ExtensionUtility::getExtensionConfiguration();
|
||||
if (isset($configuration['key']) && $key = \trim($configuration['key'])) {
|
||||
static::$isLicenseKeyValid = (bool) \preg_match('/^([A-Z\d]{6}-?){4}$/', $key);
|
||||
}
|
||||
}
|
||||
|
||||
return static::$isLicenseKeyValid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Licensing Service ping
|
||||
*
|
||||
* @param boolean $returnUrl
|
||||
* @return string
|
||||
*/
|
||||
public static function ping($returnUrl = FALSE) {
|
||||
try {
|
||||
$configuration = ExtensionUtility::getExtensionConfiguration();
|
||||
$key = '';
|
||||
if (isset($configuration['key'])) {
|
||||
$key = \trim($configuration['key']);
|
||||
}
|
||||
$params = [
|
||||
'extension' => self::EXTENSION_KEY,
|
||||
'host' => GeneralUtility::getIndpEnv('HTTP_HOST'),
|
||||
'key' => $key
|
||||
];
|
||||
$params = \http_build_query($params);
|
||||
$pingUrl = self::URL;
|
||||
$pingUrl .= $params !== '' ? (\strpos($pingUrl, '?') === FALSE ? '?' : '&') . $params : '';
|
||||
if ($returnUrl) {
|
||||
return $pingUrl;
|
||||
}
|
||||
|
||||
GeneralUtility::getUrl($pingUrl);
|
||||
} catch (\Exception $exception) {
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a random password string based on the configured password policies.
|
||||
*
|
||||
* @param ServerRequestInterface $request
|
||||
* @param ResponseInterface $response
|
||||
* @return ResponseInterface
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function ajaxPing(ServerRequestInterface $request, ResponseInterface $response = NULL) {
|
||||
/** @var BackendUserAuthentication $backendUser */
|
||||
$backendUser = $GLOBALS['BE_USER'];
|
||||
$moduleKey = 'tools_beuser/index.php/user-LfeditorLfeditor_pinged';
|
||||
if ($backendUser && !$backendUser->getModuleData($moduleKey, 'ses')) {
|
||||
$backendUser->pushModuleData($moduleKey, TRUE);
|
||||
self::ping();
|
||||
}
|
||||
|
||||
if ($response === NULL) {
|
||||
$response = new NullResponse();
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
144
typo3conf/ext/lfeditor/Classes/Service/SysLanguageService.php
Normal file
144
typo3conf/ext/lfeditor/Classes/Service/SysLanguageService.php
Normal file
@@ -0,0 +1,144 @@
|
||||
<?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 TYPO3\CMS\Core\Database\Connection;
|
||||
use TYPO3\CMS\Core\Database\ConnectionPool;
|
||||
use TYPO3\CMS\Core\Localization\Locales;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Core\Utility\VersionNumberUtility;
|
||||
|
||||
/**
|
||||
* Class SysLanguageService works with data from sys_language table.
|
||||
*/
|
||||
class SysLanguageService extends AbstractService {
|
||||
/** @var array */
|
||||
protected $sysLanguageList;
|
||||
|
||||
/** @var array */
|
||||
protected $isoReverseMapping;
|
||||
|
||||
/**
|
||||
* Selects data (uid, title, flag) from sys_language table by list of uid-s ($uids).
|
||||
* If no $uids specified, selects all records.
|
||||
*
|
||||
* @param string $uids Comma separated list of uid-s.
|
||||
* @return array|bool
|
||||
*/
|
||||
public function selectFromSysLanguageByUids($uids = NULL) {
|
||||
$connectionPool = GeneralUtility::makeInstance(ConnectionPool::class);
|
||||
$queryBuilder = $connectionPool->getQueryBuilderForTable('sys_language');
|
||||
$queryBuilder = $queryBuilder->select('uid', 'title', 'flag')
|
||||
->from('sys_language')
|
||||
->groupBy('flag', 'uid');
|
||||
if ($uids !== NULL) {
|
||||
$queryBuilder = $queryBuilder->where(
|
||||
$queryBuilder->expr()->in(
|
||||
'uid',
|
||||
$queryBuilder->createNamedParameter($uids, Connection::PARAM_INT_ARRAY)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$rows = $queryBuilder->execute()->fetchAll();
|
||||
$sysLanguageList = [];
|
||||
foreach ($rows as $row) {
|
||||
$sysLanguageList[$row['flag']]['uid'] = $row['uid'];
|
||||
$sysLanguageList[$row['flag']]['title'] = $row['title'];
|
||||
}
|
||||
|
||||
return $sysLanguageList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialises array of system languages from database.
|
||||
*/
|
||||
public function initSysLanguageList() {
|
||||
if (!isset($this->sysLanguageList)) {
|
||||
$this->sysLanguageList = $this->selectFromSysLanguageByUids();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the iso reverse mapped flag language or the given value if nothing could be mapped.
|
||||
*
|
||||
* @param string $flag language acronym (iso language code, e.g.: 'de', 'da', 'fi'...)
|
||||
* @return string
|
||||
*/
|
||||
public function doIsoReverseMapping($flag) {
|
||||
$isoReverseMapping = $this->getIsoReverseMapping();
|
||||
$mappedFlag = isset($isoReverseMapping[$flag]) ? (string) $isoReverseMapping[$flag] : '';
|
||||
if ($mappedFlag !== '') {
|
||||
$flag = $mappedFlag;
|
||||
}
|
||||
|
||||
return $flag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns system language id for given language acronym ($flag).
|
||||
* If that language is not registered in system, function returns NULL.
|
||||
*
|
||||
* @param string $flag language acronym (iso language code, e.g.: 'de', 'da', 'fi'...)
|
||||
* @return int|NULL
|
||||
*/
|
||||
public function getSysLanguageIdByFlag($flag) {
|
||||
$this->initSysLanguageList();
|
||||
$flag = $this->doIsoReverseMapping($flag);
|
||||
|
||||
// chinese seems to have a big mapping issue. In general it seems that the iso handling is currently more
|
||||
// or less simply fucked up in TYPO3. Also it's possible that I don't get the bigger picture here. Who knows...
|
||||
// Also note: Chinese isn't working without a default file in the override mode.
|
||||
if ($flag === 'zh') {
|
||||
$flag = 'cn';
|
||||
}
|
||||
|
||||
if (!empty($this->sysLanguageList[$flag]['uid'])) {
|
||||
return (int) $this->sysLanguageList[$flag]['uid'];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the mapping between ISO language codes and TYPO3 (old) codes.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getIsoReverseMapping() {
|
||||
if (!empty($this->isoReverseMapping)) {
|
||||
return $this->isoReverseMapping;
|
||||
}
|
||||
|
||||
/** @var Locales $locales */
|
||||
$locales = GeneralUtility::makeInstance(Locales::class);
|
||||
|
||||
$isoMapping = $locales->getIsoMapping();
|
||||
$this->isoReverseMapping = \array_flip($isoMapping);
|
||||
return $this->isoReverseMapping;
|
||||
}
|
||||
}
|
||||
124
typo3conf/ext/lfeditor/Classes/Session/PhpSession.php
Normal file
124
typo3conf/ext/lfeditor/Classes/Session/PhpSession.php
Normal file
@@ -0,0 +1,124 @@
|
||||
<?php
|
||||
|
||||
namespace SGalinski\Lfeditor\Session;
|
||||
|
||||
/***************************************************************
|
||||
* 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 TYPO3\CMS\Core\SingletonInterface;
|
||||
|
||||
/**
|
||||
* PHP Session handler
|
||||
*/
|
||||
class PhpSession implements SingletonInterface {
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $sessionKey;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct() {
|
||||
session_start();
|
||||
$this->sessionKey = uniqid('', TRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sessionKey
|
||||
* @return void
|
||||
*/
|
||||
public function setSessionKey($sessionKey) {
|
||||
$this->sessionKey = $sessionKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current session key
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getSessionKey() {
|
||||
return $this->sessionKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Exchanges the complete session data
|
||||
*
|
||||
* @param mixed $data
|
||||
* @return void
|
||||
*/
|
||||
public function exchangeData($data) {
|
||||
$this->destroy();
|
||||
$_SESSION[$this->sessionKey] = $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the complete session data
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getData() {
|
||||
return $_SESSION[$this->sessionKey];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets data inside the session below the given key
|
||||
*
|
||||
* @param string $key
|
||||
* @param mixed $data
|
||||
* @return void
|
||||
*/
|
||||
public function setDataByKey($key, $data) {
|
||||
$_SESSION[$this->sessionKey][$key] = $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns data of the session defined by the given key
|
||||
*
|
||||
* @param string $key
|
||||
* @return mixed
|
||||
*/
|
||||
public function getDataByKey($key) {
|
||||
return $_SESSION[$this->sessionKey][$key] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes data defined by the given key.
|
||||
*
|
||||
* @param string $key
|
||||
* @return void
|
||||
*/
|
||||
public function unsetDataByKey($key) {
|
||||
unset($_SESSION[$this->sessionKey][$key]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all session data
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function destroy() {
|
||||
unset($_SESSION[$this->sessionKey]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
namespace SGalinski\Lfeditor\Utility;
|
||||
|
||||
/***************************************************************
|
||||
* 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!
|
||||
***************************************************************/
|
||||
|
||||
/**
|
||||
* Class which adds CDATA support to SimpleXMLElement.
|
||||
*/
|
||||
class CdataSupportingSimpleXMLElement extends \SimpleXMLElement {
|
||||
/**
|
||||
* Add CDATA text in a node
|
||||
*
|
||||
* @param string $cdataText The CDATA value to add
|
||||
* @return void
|
||||
*/
|
||||
protected function addCData($cdataText) {
|
||||
$node = dom_import_simplexml($this);
|
||||
$no = $node->ownerDocument;
|
||||
$node->appendChild($no->createCDATASection($cdataText));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a child with CDATA value
|
||||
*
|
||||
* @param string $name The name of the child element to add.
|
||||
* @param string $cdataText The CDATA value of the child element.
|
||||
* @return CdataSupportingSimpleXMLElement
|
||||
*/
|
||||
public function addChildCData($name, $cdataText) {
|
||||
/** @var CdataSupportingSimpleXMLElement $child */
|
||||
$child = $this->addChild($name);
|
||||
if ($cdataText !== '') {
|
||||
$child->addCData($cdataText);
|
||||
}
|
||||
return $child;
|
||||
}
|
||||
}
|
||||
46
typo3conf/ext/lfeditor/Classes/Utility/ExtensionUtility.php
Normal file
46
typo3conf/ext/lfeditor/Classes/Utility/ExtensionUtility.php
Normal file
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* 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!
|
||||
*/
|
||||
|
||||
namespace SGalinski\Lfeditor\Utility;
|
||||
|
||||
use TYPO3\CMS\Core\Utility\VersionNumberUtility;
|
||||
|
||||
/**
|
||||
* Class ExtensionUtility
|
||||
*
|
||||
* @package SGalinski\Lfeditor\Utility
|
||||
* @author Kevin Ditscheid <kevin.ditscheid@sgalinski.de>
|
||||
*/
|
||||
class ExtensionUtility {
|
||||
/**
|
||||
* Get the extension configuration
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function getExtensionConfiguration(): array {
|
||||
return $GLOBALS['TYPO3_CONF_VARS']['EXTENSIONS']['lfeditor'] ?? [];
|
||||
}
|
||||
}
|
||||
400
typo3conf/ext/lfeditor/Classes/Utility/Functions.php
Normal file
400
typo3conf/ext/lfeditor/Classes/Utility/Functions.php
Normal file
@@ -0,0 +1,400 @@
|
||||
<?php
|
||||
|
||||
namespace SGalinski\Lfeditor\Utility;
|
||||
|
||||
/***************************************************************
|
||||
* 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 Exception;
|
||||
use SGalinski\Lfeditor\Service\FileBasePHPService;
|
||||
use TYPO3\CMS\Core\Core\Environment;
|
||||
use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
|
||||
use TYPO3\CMS\Core\Utility\VersionNumberUtility;
|
||||
use TYPO3\CMS\Extbase\Utility\LocalizationUtility;
|
||||
|
||||
/**
|
||||
* contains functions for the 'lfeditor' extension
|
||||
*/
|
||||
class Functions {
|
||||
/**
|
||||
* Prepares the extension array.
|
||||
*
|
||||
* This function creates the surface of the select box and adds
|
||||
* some additional information to each entry.
|
||||
*
|
||||
* Structure of file array:
|
||||
* $fileArray[textHeader] = further arrays with extension paths
|
||||
*
|
||||
* @param array $fileArray see above
|
||||
* @return array prepared array
|
||||
*/
|
||||
public static function prepareExtList($fileArray) {
|
||||
$myArray = [];
|
||||
foreach ($fileArray as $header => $extPaths) {
|
||||
if (!is_array($extPaths) || !count($extPaths)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
unset($prepArray);
|
||||
foreach ($extPaths as $extPath) {
|
||||
$prepArray[$extPath] = basename($extPath);
|
||||
}
|
||||
ksort($prepArray);
|
||||
$myArray = array_merge($myArray, ['###extensionGroup###' . $header => $header], $prepArray);
|
||||
}
|
||||
return $myArray;
|
||||
}
|
||||
|
||||
/**
|
||||
* searches extensions in a given path
|
||||
*
|
||||
* Modes for $state:
|
||||
* 0 - loaded and unloaded
|
||||
* 1 - only loaded
|
||||
* 2 - only unloaded
|
||||
*
|
||||
* @param string $path path
|
||||
* @param integer $state optional: extension state to ignore (see above)
|
||||
* @param string $extIgnoreRegExp optional: directories to ignore (regular expression; pcre with slashes)
|
||||
* @param string $extWhitelistRegExp optional: keep only those directories (regular expression; pcre with slashes)
|
||||
* @return array result of the search
|
||||
* @throws Exception raised, if the given path cant be opened for reading
|
||||
*/
|
||||
public static function searchExtensions($path, $state = 0, $extIgnoreRegExp = '', $extWhitelistRegExp = '') {
|
||||
if (!@$fhd = opendir($path)) {
|
||||
throw new Exception('cant open "' . $path . '"');
|
||||
}
|
||||
|
||||
$path = rtrim($path, '/');
|
||||
$extArray = [];
|
||||
while ($extDir = readdir($fhd)) {
|
||||
$extDirPath = $path . '/' . $extDir;
|
||||
|
||||
// ignore all unless the file is a directory and no point dir
|
||||
if (!is_dir($extDirPath) || preg_match('/^\.{1,2}$/', $extDir)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// check, if the directory/extension should be saved
|
||||
if (preg_match($extIgnoreRegExp, $extDir)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// check, if the directory/extension should be saved
|
||||
if ($extWhitelistRegExp !== '' && !preg_match($extWhitelistRegExp, $extDir)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// state filter
|
||||
if ($state) {
|
||||
$extState = (int) ExtensionManagementUtility::isLoaded($extDir);
|
||||
if (($extState && $state == 2) || (!$extState && $state == 1)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
$extArray[] = $extDirPath;
|
||||
}
|
||||
closedir($fhd);
|
||||
|
||||
return $extArray;
|
||||
}
|
||||
|
||||
/**
|
||||
* prepares a given language string for section output
|
||||
*
|
||||
* @param string $value language string
|
||||
* @return string prepared output in sections
|
||||
*/
|
||||
public static function prepareSectionName($value) {
|
||||
return html_entity_decode(LocalizationUtility::translate($value, 'lfeditor'));
|
||||
}
|
||||
|
||||
/**
|
||||
* checks and returns given languages or TYPO3 language list if the given content was empty
|
||||
*
|
||||
* @param array $languages optional: some language shortcuts
|
||||
* @return array language list
|
||||
*/
|
||||
public static function buildLangArray($languages = NULL) {
|
||||
if (!is_array($languages) || !count($languages)) {
|
||||
return SgLib::getSystemLanguages();
|
||||
} else {
|
||||
return $languages;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* generates output for a diff between the backup and original file
|
||||
*
|
||||
* Note that the generated diff will be an array with a normal structure like
|
||||
* any language content array.
|
||||
*
|
||||
* Modes of diffType:
|
||||
* - all changes at the original since the backup was done (0)
|
||||
* - only changes at the original (1)
|
||||
* - only changes at the backup (2)
|
||||
*
|
||||
* @param integer $diffType see above for available modes
|
||||
* @param array $origLang original language data
|
||||
* @param array $backupLocalLang backup language data
|
||||
* @return mixed generated diff
|
||||
*/
|
||||
public static function getBackupDiff($diffType, $origLang, $backupLocalLang) {
|
||||
// get all languages and generate the diff
|
||||
$langKeys = array_merge(array_keys($origLang), array_keys($backupLocalLang));
|
||||
$diff = [];
|
||||
foreach ($langKeys as $langKey) {
|
||||
// prevent warnings
|
||||
if (!is_array($origLang[$langKey])) {
|
||||
$origLang[$langKey] = [];
|
||||
}
|
||||
if (!is_array($backupLocalLang[$langKey])) {
|
||||
$backupLocalLang[$langKey] = [];
|
||||
}
|
||||
$origDiff[$langKey] = [];
|
||||
$backupDiff[$langKey] = [];
|
||||
|
||||
// generate diff
|
||||
if (!$diffType || $diffType == 1) {
|
||||
$origDiff[$langKey] = array_diff_assoc($origLang[$langKey], $backupLocalLang[$langKey]);
|
||||
}
|
||||
if (!$diffType || $diffType == 2) {
|
||||
$backupDiff[$langKey] = array_diff_assoc(
|
||||
$backupLocalLang[$langKey],
|
||||
$origLang[$langKey]
|
||||
);
|
||||
}
|
||||
$diff[$langKey] = array_merge($origDiff[$langKey], $backupDiff[$langKey]);
|
||||
}
|
||||
return $diff;
|
||||
}
|
||||
|
||||
/**
|
||||
* generates output for a meta diff between the backup and original file
|
||||
*
|
||||
* Note that the generated diff will be an array with a normal structure like
|
||||
* any meta content array.
|
||||
*
|
||||
* Modes of diffType:
|
||||
* - all changes at the original since the backup was done (0)
|
||||
* - only changes at the original (1)
|
||||
* - only changes at the backup (2)
|
||||
*
|
||||
* @param integer $diffType see above for available modes
|
||||
* @param array $origMeta original meta data
|
||||
* @param array $backupMeta backup meta data
|
||||
* @return mixed generated diff
|
||||
*/
|
||||
public static function getMetaDiff($diffType, $origMeta, $backupMeta) {
|
||||
$origDiff = [];
|
||||
$backupDiff = [];
|
||||
|
||||
if (!$diffType || $diffType == 1) {
|
||||
$origDiff = array_diff_assoc($origMeta, $backupMeta);
|
||||
}
|
||||
if (!$diffType || $diffType == 2) {
|
||||
$backupDiff = array_diff_assoc($backupMeta, $origMeta);
|
||||
}
|
||||
|
||||
if ($diffType == 1) {
|
||||
return $origDiff;
|
||||
} elseif ($diffType == 2) {
|
||||
return $backupDiff;
|
||||
} else {
|
||||
return array_merge($origDiff, $backupDiff);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* generates a general information array
|
||||
*
|
||||
* @param string $refLang reference language
|
||||
* @param array $languages language key array
|
||||
* @param FileBasePHPService $fileObj file object
|
||||
* @return array general information array
|
||||
* @see outputGeneral()
|
||||
*/
|
||||
public static function genGeneralInfoArray($refLang, $languages, $fileObj) {
|
||||
$numTranslated = [];
|
||||
// reference language data information
|
||||
$localRefLangData = $fileObj->getLocalLangData($refLang);
|
||||
|
||||
// generate needed data
|
||||
$infos = [];
|
||||
foreach ($languages as $langKey) {
|
||||
// get origin data and meta information
|
||||
$origin = $fileObj->getOriginLangData($langKey);
|
||||
$infos['default']['meta'] = $fileObj->getMetaData();
|
||||
|
||||
// language data
|
||||
$localLangData = $fileObj->getLocalLangData($langKey);
|
||||
|
||||
// detailed constants information
|
||||
$infos[$langKey]['numUntranslated'] =
|
||||
count(array_diff_key($localRefLangData, $localLangData));
|
||||
$infos[$langKey]['numUnknown'] =
|
||||
count(array_diff_key($localLangData, $localRefLangData));
|
||||
$infos[$langKey]['numTranslated'] =
|
||||
count(array_intersect_key($localLangData, $localRefLangData));
|
||||
|
||||
// set origin
|
||||
try {
|
||||
$infos[$langKey]['origin'] = '[-]';
|
||||
if (!empty($origin)) {
|
||||
$infos[$langKey]['origin'] = Typo3Lib::transTypo3File($origin, FALSE);
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
$pathSite = Environment::getPublicPath() . '/';
|
||||
$infos[$langKey]['origin'] = SgLib::trimPath($pathSite, $origin);
|
||||
}
|
||||
}
|
||||
|
||||
// Sort by numTranslated DESC
|
||||
foreach ($infos as $key => $row) {
|
||||
$numTranslated[$key] = $row['numTranslated'];
|
||||
}
|
||||
array_multisort($numTranslated, SORT_DESC, $infos);
|
||||
|
||||
return $infos;
|
||||
}
|
||||
|
||||
/**
|
||||
* generates a tree information array
|
||||
*
|
||||
* structure:
|
||||
* tree[dimension][branch]['name'] = name of constant
|
||||
* tree[dimension][branch]['type'] = type of constant (0=>normal;1=>untranslated;2=>unknown)
|
||||
* tree[dimension][branch]['parent'] = parentOfBranch (absConstName)
|
||||
* tree[dimension][branch]['childs'] = amount of children
|
||||
*
|
||||
* @param array $langData language data (only one language)
|
||||
* @param array $refLang reference data (only reference language)
|
||||
* @param string $expToken explode token
|
||||
* @return array tree information array
|
||||
*/
|
||||
public static function genTreeInfoArray($langData, $refLang, $expToken) {
|
||||
// reference language
|
||||
$refConsts = [];
|
||||
if (is_array($refLang) && count($refLang)) {
|
||||
$refConsts = array_keys($refLang);
|
||||
}
|
||||
$langConsts = array_merge(array_keys($langData), $refConsts);
|
||||
|
||||
// generate tree information array
|
||||
$curAbsName = '';
|
||||
$tree = [];
|
||||
foreach ($langConsts as $constant) {
|
||||
// add root
|
||||
$tree[0]['Root']['name'] = 'Root';
|
||||
|
||||
// get type
|
||||
$type = 0; // normal
|
||||
if (!in_array($constant, $refConsts)) {
|
||||
$type = 2;
|
||||
} // unknown
|
||||
elseif (empty($langData[$constant])) {
|
||||
$type = 1;
|
||||
} // untranslated
|
||||
|
||||
$branches = explode($expToken, $constant);
|
||||
$numBranches = is_countable($branches) ? count($branches) : 0;
|
||||
for ($i = 0, $curDim = 1; $i < $numBranches; ++$i, ++$curDim) {
|
||||
// get current absolute constant name
|
||||
if (!$i) {
|
||||
$curAbsName = $branches[$i];
|
||||
} else {
|
||||
$curAbsName .= $expToken . $branches[$i];
|
||||
}
|
||||
|
||||
if (isset($tree[$curDim][$curAbsName]['name'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// add branch
|
||||
$tree[$curDim][$curAbsName]['name'] = $branches[$i];
|
||||
$tree[$curDim][$curAbsName]['type'] = $type;
|
||||
|
||||
// set parent
|
||||
if ($i > 0) {
|
||||
$parentAbsName = substr($curAbsName, 0, strrpos($curAbsName, (string) $expToken));
|
||||
} else {
|
||||
$parentAbsName = 'Root';
|
||||
}
|
||||
$tree[$curDim][$curAbsName]['parent'] = $parentAbsName;
|
||||
if (array_key_exists('childs', $tree[$curDim - 1][$parentAbsName])) {
|
||||
++$tree[$curDim - 1][$parentAbsName]['childs'];
|
||||
} else {
|
||||
$tree[$curDim - 1][$parentAbsName]['childs'] = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $tree;
|
||||
}
|
||||
|
||||
/**
|
||||
* get best explode token of a given language data
|
||||
*
|
||||
* @param string $curToken current token
|
||||
* @param array $langData some test language data
|
||||
* @return string new token
|
||||
*/
|
||||
public static function getExplodeToken($curToken, $langData) {
|
||||
$ascii = [];
|
||||
// get current token
|
||||
if (!empty($curToken)) {
|
||||
return $curToken;
|
||||
}
|
||||
|
||||
// return default token, if no test data found
|
||||
if (!is_array($langData) || !count($langData)) {
|
||||
return '.';
|
||||
}
|
||||
|
||||
// get ascii codes (possible explode values)
|
||||
$ascii['.'] = ord('.');
|
||||
$ascii['_'] = ord('_');
|
||||
|
||||
// get best possible character of the default language
|
||||
$defKeys = array_keys($langData);
|
||||
$numKeys = count($defKeys);
|
||||
$maxTestCount = ($numKeys >= 10) ? 10 : $numKeys;
|
||||
$counts = [];
|
||||
for ($i = 0; $i < $maxTestCount; ++$i) {
|
||||
$curCounts = count_chars($defKeys[$i], 1);
|
||||
foreach ($ascii as $sign) {
|
||||
$counts[$sign] += $curCounts[$sign];
|
||||
}
|
||||
}
|
||||
|
||||
// get curToken
|
||||
foreach ($counts as $sign => $curCounts) {
|
||||
if ($curCounts > $counts[$curToken]) {
|
||||
$curToken = $sign;
|
||||
}
|
||||
}
|
||||
|
||||
return chr($curToken);
|
||||
}
|
||||
}
|
||||
349
typo3conf/ext/lfeditor/Classes/Utility/SgLib.php
Normal file
349
typo3conf/ext/lfeditor/Classes/Utility/SgLib.php
Normal file
@@ -0,0 +1,349 @@
|
||||
<?php
|
||||
|
||||
namespace SGalinski\Lfeditor\Utility;
|
||||
|
||||
/***************************************************************
|
||||
* 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 Exception;
|
||||
use TYPO3\CMS\Core\Localization\Locales;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
|
||||
/**
|
||||
* personal library with lots of useful methods
|
||||
*/
|
||||
class SgLib {
|
||||
#################################
|
||||
######## string functions #######
|
||||
#################################
|
||||
|
||||
/**
|
||||
* trims some string from an given path
|
||||
*
|
||||
* @param string $replace string part to delete
|
||||
* @param string $path some path
|
||||
* @param string $prefix some prefix for the new path
|
||||
* @return string new path
|
||||
*/
|
||||
public static function trimPath($replace, $path, $prefix = '') {
|
||||
return trim(str_replace($replace, '', $path), '/') . $prefix;
|
||||
}
|
||||
|
||||
#####################################
|
||||
######## filesystem functions #######
|
||||
#####################################
|
||||
|
||||
/**
|
||||
* reads the extension of a given filename
|
||||
*
|
||||
* @param string $file filename
|
||||
* @return string extension of a given filename
|
||||
*/
|
||||
public static function getFileExtension($file) {
|
||||
return substr($file, strrpos($file, '.') + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* replaces the file extension in a given filename
|
||||
*
|
||||
* @param string $type new file extension
|
||||
* @param string $file filename
|
||||
* @return string new filename
|
||||
*/
|
||||
public static function setFileExtension($type, $file) {
|
||||
return substr($file, 0, strrpos($file, '.') + 1) . $type;
|
||||
}
|
||||
|
||||
/**
|
||||
* checks write permission of a given file (checks directory permission if file does not exists)
|
||||
*
|
||||
* @param string $file file path
|
||||
* @return boolean true or false
|
||||
*/
|
||||
public static function checkWritePerms($file) {
|
||||
if (!is_file($file)) {
|
||||
$file = dirname($file);
|
||||
}
|
||||
|
||||
if (!is_writable($file)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* deletes given files
|
||||
*
|
||||
* @param array $files files
|
||||
* @return void
|
||||
* @throws Exception raised, if some files cant be deleted (thrown after deletion of all)
|
||||
*/
|
||||
public static function deleteFiles($files) {
|
||||
// delete all old files
|
||||
$error = [];
|
||||
foreach ($files as $file) {
|
||||
if (is_file($file)) {
|
||||
if (!unlink($file)) {
|
||||
$error[] = $file;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (count($error)) {
|
||||
throw new Exception('following files cant be deleted: "' . implode(', ', $error) . '"');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a full path (all nonexistent directories will be created)
|
||||
*
|
||||
* @param string $path full path
|
||||
* @param string $protectArea protected path (i.e. /var/www -- needed for basedir restrictions)
|
||||
* @return void
|
||||
* @throws Exception raised if some path token cant be created
|
||||
*/
|
||||
public static function createDir($path, $protectArea) {
|
||||
[$extensionNameFromFile, $extPrefixedPath] = Typo3Lib::getExtNameFromOverrideFile($path);
|
||||
if (strpos($extensionNameFromFile, '-') !== FALSE) {
|
||||
$path = str_replace(
|
||||
$extensionNameFromFile,
|
||||
str_replace('-', '_', $extensionNameFromFile),
|
||||
$path
|
||||
);
|
||||
}
|
||||
if (!is_dir($path)) {
|
||||
$pathAsArray = explode('/', self::trimPath($protectArea, $path));
|
||||
$tmp = '';
|
||||
foreach ($pathAsArray as $dir) {
|
||||
$tmp .= $dir . '/';
|
||||
if (is_dir($protectArea . $tmp)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$concurrentDirectory = $protectArea . $tmp;
|
||||
GeneralUtility::mkdir_deep($concurrentDirectory);
|
||||
if (!is_dir($concurrentDirectory)) {
|
||||
throw new Exception('path "' . $protectArea . $tmp . '" can\'t be created.');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* deletes a directory (all subdirectories and files will be deleted)
|
||||
*
|
||||
* @param string $path full path
|
||||
* @return void
|
||||
* @throws Exception raised if a file or directory cant be deleted
|
||||
*/
|
||||
public static function deleteDir($path) {
|
||||
if (!$dh = @opendir($path)) {
|
||||
throw new Exception('directory "' . $path . '" cant be readed');
|
||||
}
|
||||
|
||||
while ($file = readdir($dh)) {
|
||||
$myFile = $path . '/' . $file;
|
||||
|
||||
// ignore links and point directories
|
||||
if (preg_match('/\.{1,2}/', $file) || is_link($myFile)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (is_file($myFile)) {
|
||||
if (!unlink($myFile)) {
|
||||
throw new Exception('file "' . $myFile . '" cant be deleted');
|
||||
}
|
||||
} elseif (is_dir($myFile)) {
|
||||
SgLib::deleteDir($myFile);
|
||||
}
|
||||
}
|
||||
closedir($dh);
|
||||
|
||||
if (!@rmdir($path)) {
|
||||
throw new Exception('directory "' . $path . '" cant be deleted');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* searches defined files in a given path recursively
|
||||
*
|
||||
* @param string $path search in this path
|
||||
* @param string $searchRegex optional: regular expression for files
|
||||
* @param integer $pathDepth optional: current path depth level (max 9)
|
||||
* @return array
|
||||
* @throws Exception raised if the search directory cant be read
|
||||
*/
|
||||
public static function searchFiles($path, $searchRegex = '', $pathDepth = 0) {
|
||||
// endless recursion protection
|
||||
$fileArray = [];
|
||||
if ($pathDepth >= 9) {
|
||||
return $fileArray;
|
||||
}
|
||||
|
||||
// open directory
|
||||
if (!$fhd = @opendir($path)) {
|
||||
throw new Exception('directory "' . $path . '" cant be read');
|
||||
}
|
||||
|
||||
// iterate through the directory entries
|
||||
while ($file = readdir($fhd)) {
|
||||
$filePath = $path . '/' . $file;
|
||||
|
||||
// ignore links and special directories (. and ..)
|
||||
if (preg_match('/^\.{1,2}$/', $file) || is_link($filePath)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// if it's a file and not excluded by the search filter, we can add it
|
||||
// to the file array
|
||||
if (is_file($filePath)) {
|
||||
if ($searchRegex == '') {
|
||||
$fileArray[] = $filePath;
|
||||
} elseif (preg_match($searchRegex, $file)) {
|
||||
$fileArray[] = $filePath;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// next dir
|
||||
if (is_dir($filePath)) {
|
||||
$fileArray = array_merge(
|
||||
$fileArray,
|
||||
(array) SgLib::searchFiles($filePath, $searchRegex, $pathDepth + 1)
|
||||
);
|
||||
}
|
||||
}
|
||||
closedir($fhd);
|
||||
|
||||
return $fileArray;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all available system languages defined in TYPO3
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function getSystemLanguages() {
|
||||
/** @var Locales $locales */
|
||||
$locales = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Localization\Locales::class);
|
||||
$availableLanguageKeys = $locales->getLocales();
|
||||
|
||||
foreach ($availableLanguageKeys as $index => $language) {
|
||||
if ($language === 'default') {
|
||||
$availableLanguageKeys[$index] = 'default';
|
||||
break;
|
||||
}
|
||||
}
|
||||
return $availableLanguageKeys;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert special HTML characters to HTML entities, but ignores CDATA section.
|
||||
*
|
||||
* @param string $value
|
||||
* @return string
|
||||
*/
|
||||
public static function htmlSpecialCharsIgnoringCdata($value) {
|
||||
$cdataStart = strpos($value, '<![CDATA[');
|
||||
$cdataEnd = strpos($value, ']]>');
|
||||
if ($cdataStart !== FALSE && $cdataEnd !== FALSE) {
|
||||
$cdataEnd += 3;
|
||||
$valueBefore = substr($value, 0, $cdataStart);
|
||||
$cdataValue = substr($value, $cdataStart, $cdataEnd - $cdataStart);
|
||||
$valueAfter = substr($value, $cdataEnd, strlen($value) - $cdataEnd);
|
||||
$value = htmlspecialchars($valueBefore) . '<![CDATA[' . $cdataValue . ']]>'
|
||||
. htmlspecialchars($valueAfter);
|
||||
} else {
|
||||
$value = htmlspecialchars($value);
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if CDATA tag exists in string.
|
||||
*
|
||||
* @param string $value
|
||||
* @return bool
|
||||
*/
|
||||
public static function checkForCdataInString($value) {
|
||||
$cdataStart = strpos($value, '<![CDATA[');
|
||||
$cdataEnd = strpos($value, ']]>');
|
||||
return ($cdataStart !== FALSE && $cdataEnd !== FALSE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes at end of PHP file, just before php closing tag or at the end of file if php closing tag does not exist.
|
||||
* If specified file does not exist, it will be crated.
|
||||
*
|
||||
* @param string $filePath
|
||||
* @param string $lineToAdd
|
||||
* @return void
|
||||
*/
|
||||
public static function appendToPHPFile($filePath, $lineToAdd) {
|
||||
if (!is_file($filePath)) {
|
||||
$emptyPhpFileContent = '<?php' . chr(0x0A) . '?>';
|
||||
file_put_contents($filePath, $emptyPhpFileContent);
|
||||
}
|
||||
$configuration = file_get_contents($filePath);
|
||||
if ($configuration === FALSE) {
|
||||
return;
|
||||
}
|
||||
$phpEndTagPosition = strrpos($configuration, '?>');
|
||||
if ($phpEndTagPosition) {
|
||||
$configuration = substr($configuration, 0, $phpEndTagPosition);
|
||||
} else {
|
||||
$configuration .= chr(0x0A);
|
||||
}
|
||||
$configuration .= chr(0x09) . $lineToAdd;
|
||||
if ($phpEndTagPosition) {
|
||||
$configuration .= chr(0x0A) . '?>';
|
||||
}
|
||||
file_put_contents($filePath, $configuration);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares two strings ignoring \r character and seeing \n as <br /> in first string.
|
||||
*
|
||||
* @param array|string $string1
|
||||
* @param string $string2
|
||||
* @return bool
|
||||
*/
|
||||
public static function strCmpIgnoreCR($string1, $string2) {
|
||||
return is_string($string1) && str_replace("\r", '', $string1) === $string2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes meta tag '@attributes' to 'attributes', if it exists.
|
||||
*
|
||||
* @param array $origMeta
|
||||
*/
|
||||
public static function fixMetaAttributes(array &$origMeta) {
|
||||
if (isset($origMeta['@attributes'])) {
|
||||
$origMeta['attributes'] = $origMeta['@attributes'];
|
||||
unset($origMeta['@attributes']);
|
||||
}
|
||||
}
|
||||
}
|
||||
186
typo3conf/ext/lfeditor/Classes/Utility/Typo3Lib.php
Normal file
186
typo3conf/ext/lfeditor/Classes/Utility/Typo3Lib.php
Normal file
@@ -0,0 +1,186 @@
|
||||
<?php
|
||||
|
||||
namespace SGalinski\Lfeditor\Utility;
|
||||
|
||||
/***************************************************************
|
||||
* 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 TYPO3\CMS\Core\Core\Environment;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Core\Utility\VersionNumberUtility;
|
||||
|
||||
/**
|
||||
* includes special typo3 methods
|
||||
*/
|
||||
class Typo3Lib {
|
||||
/**
|
||||
* @deprecated since version 5, will be removed as soon as TYPO3 8 support is dropped
|
||||
*/
|
||||
public const PATH_LOCAL_EXT = 'typo3conf/ext/';
|
||||
|
||||
/**
|
||||
* @deprecated since version 5, will be removed as soon as TYPO3 8 support is dropped
|
||||
*/
|
||||
public const PATH_GLOBAL_EXT = 'typo3/ext/';
|
||||
|
||||
/**
|
||||
* @deprecated since version 5, will be removed as soon as TYPO3 8 support is dropped
|
||||
*/
|
||||
public const PATH_SYS_EXT = 'typo3/sysext/';
|
||||
|
||||
/**
|
||||
* @deprecated since version 5, will be removed as soon as TYPO3 8 support is dropped
|
||||
*/
|
||||
public const PATH_L10N = 'typo3conf/l10n/';
|
||||
|
||||
/**
|
||||
* checks the file location type
|
||||
*
|
||||
* @param string $file
|
||||
* @return string
|
||||
*/
|
||||
public static function checkFileLocation($file) {
|
||||
$pathExtensions = Environment::getExtensionsPath() . '/';
|
||||
|
||||
if (strpos($file, $pathExtensions) !== FALSE) {
|
||||
return 'local';
|
||||
}
|
||||
|
||||
if (strpos($file, self::PATH_GLOBAL_EXT) !== FALSE) {
|
||||
trigger_error(
|
||||
'The typo3/ext folder does not exist anymore, so this functionality will be dropped',
|
||||
E_USER_DEPRECATED
|
||||
);
|
||||
return 'global';
|
||||
}
|
||||
|
||||
$pathSysExtensions = Environment::getFrameworkBasePath() . '/';
|
||||
|
||||
if (strpos($file, $pathSysExtensions) !== FALSE) {
|
||||
return 'system';
|
||||
}
|
||||
|
||||
$pathL10N = Environment::getLabelsPath() . '/';
|
||||
|
||||
if (strpos($file, $pathL10N) !== FALSE) {
|
||||
return 'l10n';
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $fileRef Absolute path of the language file
|
||||
* @return string Absolute prefix to the language file location
|
||||
*/
|
||||
public static function getLocalizedFilePrefix($fileRef) {
|
||||
// Analyze file reference
|
||||
if (GeneralUtility::isFirstPartOfStr($fileRef, Environment::getFrameworkBasePath() . '/')) {
|
||||
// Is system
|
||||
$validatedPrefix = Environment::getFrameworkBasePath() . '/';
|
||||
} elseif (GeneralUtility::isFirstPartOfStr($fileRef, Environment::getBackendPath() . '/ext/')) {
|
||||
// Is global
|
||||
$validatedPrefix = Environment::getBackendPath() . '/ext/';
|
||||
} elseif (GeneralUtility::isFirstPartOfStr($fileRef, Environment::getExtensionsPath() . '/')) {
|
||||
// Is local
|
||||
$validatedPrefix = Environment::getExtensionsPath() . '/';
|
||||
} else {
|
||||
$validatedPrefix = '';
|
||||
}
|
||||
|
||||
return $validatedPrefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string Absolute path to the l10n directory
|
||||
*/
|
||||
public static function getLabelsPath() {
|
||||
return Environment::getLabelsPath() . '/';
|
||||
}
|
||||
|
||||
/**
|
||||
* converts an absolute or relative typo3 style (EXT:) file path
|
||||
*
|
||||
* @param string $file absolute file or an typo3 relative file (EXT:)
|
||||
* @param boolean $absolute generate to relative(false) or absolute file
|
||||
* @return string converted file path
|
||||
*
|
||||
* @throws \Exception Conversion of file path failed
|
||||
*/
|
||||
public static function transTypo3File($file, $absolute) {
|
||||
$path = GeneralUtility::getFileAbsFileName($file);
|
||||
if (!$absolute) {
|
||||
$fileLocation = self::checkFileLocation($path);
|
||||
if ($fileLocation === 'local') {
|
||||
$pathToRemove = Environment::getExtensionsPath() . '/';
|
||||
} elseif ($fileLocation === 'system') {
|
||||
$pathToRemove = Environment::getFrameworkBasePath() . '/';
|
||||
} else {
|
||||
throw new \Exception('Can not convert absolute file "' . $file . '"');
|
||||
}
|
||||
|
||||
$path = 'EXT:' . SgLib::trimPath($pathToRemove, $path);
|
||||
}
|
||||
|
||||
return $path;
|
||||
}
|
||||
|
||||
/**
|
||||
* converts an absolute or relative typo3 style (EXT:) file path
|
||||
*
|
||||
* @param string $file absolute file or an typo3 relative file (EXT:)
|
||||
* @return array converted file path
|
||||
*
|
||||
* @throws \Exception Conversion of file path failed
|
||||
*/
|
||||
public static function getExtNameFromOverrideFile($file) {
|
||||
$absoluteWebPath = Environment::getPublicPath();
|
||||
$prefixedWithSettingsPath = str_replace($absoluteWebPath, '', $file);
|
||||
$alreadyExtPrefixedPath = str_replace('/typo3conf/LFEditor/OverrideFiles/', '', $prefixedWithSettingsPath);
|
||||
$extName = explode('/', $alreadyExtPrefixedPath)[0];
|
||||
return [$extName, 'EXT:' . $alreadyExtPrefixedPath];
|
||||
}
|
||||
|
||||
/**
|
||||
* generates portable file paths
|
||||
*
|
||||
* @param string $file file
|
||||
* @return string fixed file
|
||||
*/
|
||||
public static function fixFilePath($file) {
|
||||
return GeneralUtility::fixWindowsFilePath(str_replace('//', '/', $file));
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds configuration line to AdditionalConfiguration file.
|
||||
*
|
||||
* @param string $configLine line to be added.
|
||||
* @param string $additionalConfigurationFilePath
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function writeLineToAdditionalConfiguration($configLine, $additionalConfigurationFilePath) {
|
||||
SgLib::appendToPHPFile($additionalConfigurationFilePath, $configLine);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
namespace SGalinski\Lfeditor\ViewHelpers;
|
||||
|
||||
/***************************************************************
|
||||
* 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 TYPO3\CMS\Core\Page\PageRenderer;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Fluid\ViewHelpers\Be\AbstractBackendViewHelper;
|
||||
|
||||
/**
|
||||
* Abstract view helper
|
||||
*/
|
||||
class AbstractViewHelper extends AbstractBackendViewHelper {
|
||||
/**
|
||||
* Returns an instance of the page renderer
|
||||
*
|
||||
* @return PageRenderer
|
||||
*/
|
||||
public function getPageRenderer() {
|
||||
return GeneralUtility::makeInstance(PageRenderer::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the base url of the site
|
||||
*
|
||||
* Note: Works only in frontend mode
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getBaseUrl() {
|
||||
if ($GLOBALS['TSFE']->absRefPrefix !== '') {
|
||||
$baseUrl = $GLOBALS['TSFE']->absRefPrefix;
|
||||
} else {
|
||||
$baseUrl = $GLOBALS['TSFE']->baseUrl;
|
||||
}
|
||||
|
||||
return $baseUrl;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
namespace SGalinski\Lfeditor\ViewHelpers;
|
||||
|
||||
/***************************************************************
|
||||
* 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!
|
||||
***************************************************************/
|
||||
|
||||
/**
|
||||
* View helper to add custom css files
|
||||
*
|
||||
* Example:
|
||||
* {namespace lfe=SGalinski\Lfeditor\ViewHelpers}
|
||||
* <lfe:addCssFile cssFile="{f:uri.resource(path: 'StyleSheets/Frontend.css')}" />
|
||||
*/
|
||||
class AddCssFileViewHelper extends AbstractViewHelper {
|
||||
/**
|
||||
* Register the ViewHelper arguments
|
||||
*/
|
||||
public function initializeArguments() {
|
||||
parent::initializeArguments();
|
||||
$this->registerArgument('cssFile', 'string', 'The css file to include', TRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a custom css file
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function render() {
|
||||
$cssFile = (\TYPO3\CMS\Core\Http\ApplicationType::fromRequest($GLOBALS['TYPO3_REQUEST'])->isFrontend() ? $this->getBaseUrl() : '') . $this->arguments['cssFile'];
|
||||
$this->getPageRenderer()->addCssFile($cssFile, 'stylesheet', 'all', '', FALSE);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
namespace SGalinski\Lfeditor\ViewHelpers;
|
||||
|
||||
/***************************************************************
|
||||
* 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!
|
||||
***************************************************************/
|
||||
|
||||
/**
|
||||
* View helper to add custom javascript files
|
||||
*
|
||||
* Example:
|
||||
* {namespace lfe=SGalinski\Lfeditor\ViewHelpers}
|
||||
* <lfe:addJavaScriptFile javaScriptFile="{f:uri.resource(path: 'Scripts/Frontend.js')}" />
|
||||
*/
|
||||
class AddJavaScriptFileViewHelper extends AbstractViewHelper {
|
||||
/**
|
||||
* Register the ViewHelper arguments
|
||||
*/
|
||||
public function initializeArguments() {
|
||||
parent::initializeArguments();
|
||||
$this->registerArgument('javaScriptFile', 'string', 'The JavaScript file to include', TRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a custom javascript file
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function render() {
|
||||
$javaScriptFile = (\TYPO3\CMS\Core\Http\ApplicationType::fromRequest($GLOBALS['TYPO3_REQUEST'])->isFrontend() ? $this->getBaseUrl() : '') . $this->arguments['javaScriptFile'];
|
||||
$this->getPageRenderer()->addJsFile($javaScriptFile);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
namespace SGalinski\Lfeditor\ViewHelpers\Be\Menus;
|
||||
|
||||
/***************************************************************
|
||||
* 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 TYPO3Fluid\Fluid\Core\ViewHelper\AbstractTagBasedViewHelper;
|
||||
|
||||
/**
|
||||
* Class ActionMenuOptionGroupViewHelper
|
||||
*/
|
||||
class ActionMenuOptionGroupViewHelper extends AbstractTagBasedViewHelper {
|
||||
/**
|
||||
* Initialize
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function initializeArguments() {
|
||||
parent::initializeArguments();
|
||||
$this->tagName = 'optgroup';
|
||||
$this->registerUniversalTagAttributes();
|
||||
$this->registerTagAttribute('label', 'string', 'Specifies a label for an option-group');
|
||||
$this->registerTagAttribute('disabled', 'string', 'Specifies that an option-group should be disabled');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function render() {
|
||||
$this->tag->setContent($this->renderChildren());
|
||||
return $this->tag->render();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
<?php
|
||||
|
||||
namespace SGalinski\Lfeditor\ViewHelpers\Be\Menus;
|
||||
|
||||
/**
|
||||
*
|
||||
* 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 TYPO3Fluid\Fluid\Core\Compiler\TemplateCompiler;
|
||||
use TYPO3Fluid\Fluid\Core\Parser\SyntaxTree\ViewHelperNode;
|
||||
use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractTagBasedViewHelper;
|
||||
|
||||
/**
|
||||
* View helper which returns a select box, that can be used to switch between
|
||||
* multiple actions and controllers and looks similar to TYPO3s funcMenu.
|
||||
* Note: This view helper is experimental!
|
||||
*
|
||||
* = Examples =
|
||||
*
|
||||
* <code title="Simple">
|
||||
* <f:be.menus.actionMenu>
|
||||
* <f:be.menus.actionMenuItem label="Overview" controller="Blog" action="index" />
|
||||
* <f:be.menus.actionMenuItem label="Create new Blog" controller="Blog" action="new" />
|
||||
* <f:be.menus.actionMenuItem label="List Posts" controller="Post" action="index" arguments="{blog: blog}" />
|
||||
* </f:be.menus.actionMenu>
|
||||
* </code>
|
||||
* <output>
|
||||
* Selectbox with the options "Overview", "Create new Blog" and "List Posts"
|
||||
* </output>
|
||||
*
|
||||
* <code title="Localized">
|
||||
* <f:be.menus.actionMenu>
|
||||
* <f:be.menus.actionMenuItem label="{f:translate(key:'overview')}" controller="Blog" action="index" />
|
||||
* <f:be.menus.actionMenuItem label="{f:translate(key:'create_blog')}" controller="Blog" action="new" />
|
||||
* </f:be.menus.actionMenu>
|
||||
* </code>
|
||||
* <output>
|
||||
* localized selectbox
|
||||
* <output>
|
||||
*/
|
||||
class ActionMenuViewHelper extends AbstractTagBasedViewHelper {
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $tagName = 'select';
|
||||
|
||||
/**
|
||||
* An array of \TYPO3\CMS\Fluid\Core\Parser\SyntaxTree\AbstractNode
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $childNodes = [];
|
||||
|
||||
/**
|
||||
* Initialize arguments.
|
||||
*
|
||||
* @return void
|
||||
* @throws \TYPO3Fluid\Fluid\Core\ViewHelper\Exception
|
||||
*/
|
||||
public function initializeArguments(): void {
|
||||
parent::initializeArguments();
|
||||
$this->registerArgument('defaultController', 'string', 'defaultController');
|
||||
}
|
||||
|
||||
/**
|
||||
* Render FunctionMenu
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function render(): string {
|
||||
$this->tag->addAttribute('onchange', 'jumpToUrl(this.options[this.selectedIndex].value, this);');
|
||||
$options = '';
|
||||
foreach ($this->childNodes as $childNode) {
|
||||
$options .= $childNode->evaluate($this->renderingContext);
|
||||
}
|
||||
$this->tag->setContent($options);
|
||||
return $this->tag->render();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $argumentsName
|
||||
* @param string $closureName
|
||||
* @param string $initializationPhpCode
|
||||
* @param ViewHelperNode $node
|
||||
* @param TemplateCompiler $compiler
|
||||
* @return string
|
||||
*/
|
||||
public function compile(
|
||||
$argumentsName,
|
||||
$closureName,
|
||||
&$initializationPhpCode,
|
||||
ViewHelperNode $node,
|
||||
TemplateCompiler $compiler
|
||||
) {
|
||||
// @TODO: replace with a true compiling method to make compilable!
|
||||
$compiler->disable();
|
||||
/** @noinspection PhpUnreachableStatementInspection */
|
||||
return '';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
<?php
|
||||
|
||||
namespace SGalinski\Lfeditor\ViewHelpers;
|
||||
|
||||
/***************************************************************
|
||||
* Copyright notice
|
||||
*
|
||||
* (c) sgalinski Internet Services (https://www.sgalinski.de)
|
||||
*
|
||||
* All rights reserved
|
||||
*
|
||||
* This script is part of the AY project. The AY 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 TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Extbase\Utility\LocalizationUtility;
|
||||
|
||||
/**
|
||||
* View helper to render language labels to
|
||||
* json array to be used in js applications.
|
||||
*
|
||||
* Renders to AY.lang.'extension name' object
|
||||
*
|
||||
* Example:
|
||||
* {namespace rs=SGalinski\RsEvents\ViewHelpers}
|
||||
* <rs:inlineLanguageLabels labels="label01,label02" />
|
||||
*/
|
||||
class InlineLanguageLabelsViewHelper extends AbstractViewHelper {
|
||||
public function initializeArguments() {
|
||||
parent::initializeArguments();
|
||||
$this->registerArgument('labels', 'mixed', 'Comma separated list of label keys to include', FALSE, []);
|
||||
$this->registerArgument('htmlEscape', 'bool', 'Escape the output', FALSE, FALSE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the required javascript to make the language labels available
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function render(): string {
|
||||
$labels = $this->arguments['labels'];
|
||||
$htmlEscape = $this->arguments['htmlEscape'];
|
||||
$controllerContext = $this->renderingContext->getControllerContext();
|
||||
$extensionName = $controllerContext->getRequest()->getControllerExtensionName();
|
||||
if (\is_string($labels)) {
|
||||
$labels = GeneralUtility::trimExplode(',', $labels, TRUE);
|
||||
}
|
||||
|
||||
if (!\is_array($labels)) {
|
||||
throw new \InvalidArgumentException(
|
||||
'The argument "labels" was registered with type "array|string", but is of type "' .
|
||||
\gettype($labels) . '" in view helper "' . \get_class($this) . '".',
|
||||
1256475113
|
||||
);
|
||||
}
|
||||
|
||||
$languageArray = [];
|
||||
foreach ($labels as $key) {
|
||||
$value = LocalizationUtility::translate($key, $extensionName);
|
||||
$languageArray[$key] = ($htmlEscape ? \htmlentities($value) : $value);
|
||||
}
|
||||
|
||||
$javascriptCode = '
|
||||
var AY = AY || {};
|
||||
AY.lang = AY.lang || {};
|
||||
AY.lang.' . $extensionName . ' = AY.lang.' . $extensionName . ' || {};
|
||||
var languageLabels = ' . \json_encode($languageArray) . ';
|
||||
for (label in languageLabels) {
|
||||
AY.lang.' . $extensionName . '[label] = languageLabels[label];
|
||||
}
|
||||
';
|
||||
|
||||
$this->getPageRenderer()->addJsInlineCode($extensionName, $javascriptCode);
|
||||
return '';
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user