Initial commit - Typo3 11.5.41
This commit is contained in:
@@ -0,0 +1,160 @@
|
||||
<?php
|
||||
namespace SJBR\StaticInfoTables\Utility;
|
||||
|
||||
/*
|
||||
* Copyright notice
|
||||
*
|
||||
* (c) 2013-2022 StanislasRolland <typo3AAAA(arobas)sjbr.ca>
|
||||
* All rights reserved
|
||||
*
|
||||
* This script is part of the Typo3 project. The Typo3 project is
|
||||
* free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The GNU General Public License can be found at
|
||||
* http://www.gnu.org/copyleft/gpl.html.
|
||||
*
|
||||
* This script is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* This copyright notice MUST APPEAR in all copies of the script!
|
||||
*/
|
||||
|
||||
use Doctrine\DBAL\DBALException;
|
||||
use TYPO3\CMS\Core\Database\ConnectionPool;
|
||||
use TYPO3\CMS\Core\Database\Schema\SchemaMigrator;
|
||||
use TYPO3\CMS\Core\Database\Schema\SqlReader;
|
||||
use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Extensionmanager\Utility\InstallUtility;
|
||||
|
||||
/**
|
||||
* Utility used by the update script of the base extension and of the language packs
|
||||
*/
|
||||
class DatabaseUpdateUtility
|
||||
{
|
||||
/**
|
||||
* @var string Name of the extension this class belongs to
|
||||
*/
|
||||
protected $extensionName = 'StaticInfoTables';
|
||||
|
||||
/**
|
||||
* Do the language pack update
|
||||
*
|
||||
* @param string $extensionKey: extension key of the language pack
|
||||
* @return void
|
||||
*/
|
||||
public function doUpdate($extensionKey)
|
||||
{
|
||||
$result = [];
|
||||
$connectionPool = GeneralUtility::makeInstance(ConnectionPool::class);
|
||||
$insertStatements = [];
|
||||
$updateStatements = [];
|
||||
$extPath = ExtensionManagementUtility::extPath($extensionKey);
|
||||
$statements = explode(LF, @file_get_contents($extPath . 'ext_tables_static+adt.sql'));
|
||||
|
||||
foreach ($statements as $statement) {
|
||||
$statement = trim($statement);
|
||||
// Only handle update statements and extract the table at the same time. Extracting
|
||||
// the table name is required to perform the inserts on the right connection.
|
||||
if (preg_match('/^UPDATE\\s+`?(\\w+)`?(.*)/i', $statement, $matches)) {
|
||||
list(, $tableName, $sqlFragment) = $matches;
|
||||
$updateStatements[$tableName][] = sprintf(
|
||||
'UPDATE %s %s',
|
||||
$connectionPool->getConnectionForTable($tableName)->quoteIdentifier($tableName),
|
||||
rtrim($sqlFragment, ';')
|
||||
);
|
||||
}
|
||||
}
|
||||
foreach ($updateStatements as $tableName => $perTableStatements) {
|
||||
$connection = $connectionPool->getConnectionForTable($tableName);
|
||||
foreach ((array)$perTableStatements as $statement) {
|
||||
try {
|
||||
$connection->executeUpdate($statement);
|
||||
$result[$statement] = '';
|
||||
} catch (DBALException $e) {
|
||||
$result[$statement] = $e->getPrevious()->getMessage();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Imports a static tables SQL File (ext_tables_static+adt)
|
||||
*
|
||||
* @param string $extensionSitePath
|
||||
* @return void
|
||||
*/
|
||||
public function importStaticSqlFile($extensionSitePath)
|
||||
{
|
||||
$extTablesStaticSqlFile = $extensionSitePath . 'ext_tables_static+adt.sql';
|
||||
$extTablesStaticSqlContent = '';
|
||||
if (file_exists($extTablesStaticSqlFile)) {
|
||||
$extTablesStaticSqlContent .= GeneralUtility::getUrl($extTablesStaticSqlFile);
|
||||
}
|
||||
if ($extTablesStaticSqlContent !== '') {
|
||||
$connectionPool = GeneralUtility::makeInstance(ConnectionPool::class);
|
||||
// Drop all tables
|
||||
foreach (array_keys($GLOBALS['TYPO3_CONF_VARS']['EXTENSIONS']['static_info_tables']['tables'] ?? []) as $tableName) {
|
||||
$connection = $connectionPool->getConnectionForTable($tableName);
|
||||
try {
|
||||
$connection->executeUpdate($connection->getDatabasePlatform()
|
||||
->getDropTableSQL($connection->quoteIdentifier($tableName)));
|
||||
} catch (TableNotFoundException $e) {
|
||||
// Ignore table not found exception
|
||||
}
|
||||
}
|
||||
// Re-create all tables
|
||||
$this->processDatabaseUpdates(GeneralUtility::camelCaseToLowerCaseUnderscored($this->extensionName));
|
||||
$installTool = GeneralUtility::makeInstance(InstallUtility::class);
|
||||
$installTool->importStaticSql($extTablesStaticSqlContent);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes the tables SQL File (ext_tables)
|
||||
*
|
||||
* @param string $extensionKey
|
||||
* @return void
|
||||
*/
|
||||
public function processDatabaseUpdates($extensionKey)
|
||||
{
|
||||
$extensionSitePath = ExtensionManagementUtility::extPath($extensionKey);
|
||||
$extTablesSqlFile = $extensionSitePath . 'ext_tables.sql';
|
||||
$extTablesSqlContent = '';
|
||||
if (file_exists($extTablesSqlFile)) {
|
||||
$extTablesSqlContent .= GeneralUtility::getUrl($extTablesSqlFile);
|
||||
}
|
||||
if ($extTablesSqlContent !== '') {
|
||||
// Prevent the DefaultTcaSchema from enriching our definitions
|
||||
$tcaBackup = $GLOBALS['TCA'];
|
||||
$GLOBALS['TCA'] = [];
|
||||
$sqlReader = GeneralUtility::makeInstance(SqlReader::class);
|
||||
$schemaMigrator = GeneralUtility::makeInstance(SchemaMigrator::class);
|
||||
$sqlStatements = [];
|
||||
$sqlStatements[] = $extTablesSqlContent;
|
||||
$sqlStatements = $sqlReader->getCreateTableStatementArray(implode(LF . LF, array_filter($sqlStatements)));
|
||||
$updateStatements = $schemaMigrator->getUpdateSuggestions($sqlStatements);
|
||||
$updateStatements = array_merge_recursive(...array_values($updateStatements));
|
||||
$selectedStatements = [];
|
||||
foreach (['add', 'change', 'create_table', 'change_table'] as $action) {
|
||||
if (empty($updateStatements[$action])) {
|
||||
continue;
|
||||
}
|
||||
$selectedStatements = array_merge(
|
||||
$selectedStatements,
|
||||
array_combine(
|
||||
array_keys($updateStatements[$action]),
|
||||
array_fill(0, count($updateStatements[$action]), true)
|
||||
)
|
||||
);
|
||||
}
|
||||
$schemaMigrator->migrate($sqlStatements, $selectedStatements);
|
||||
$GLOBALS['TCA'] = $tcaBackup;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
<?php
|
||||
namespace SJBR\StaticInfoTables\Utility;
|
||||
|
||||
/*
|
||||
* This file is part of the TYPO3 CMS project.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*
|
||||
* The TYPO3 project - inspiring people to share!
|
||||
*/
|
||||
|
||||
use TYPO3\CMS\Core\Database\ConnectionPool;
|
||||
use TYPO3\CMS\Core\SingletonInterface;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
|
||||
/**
|
||||
* Utility for dealing with database related operations
|
||||
*/
|
||||
class DatabaseUtility implements SingletonInterface
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
const MULTI_LINEBREAKS = '
|
||||
|
||||
|
||||
';
|
||||
|
||||
/**
|
||||
* Dump content for static tables
|
||||
*
|
||||
* @param array $dbFields
|
||||
* @return string
|
||||
*/
|
||||
public function dumpStaticTables($dbFields)
|
||||
{
|
||||
$out = '';
|
||||
// Traverse the table list and dump each:
|
||||
foreach ($dbFields as $table => $fields) {
|
||||
if (isset($dbFields[$table]['fields']) && is_array($dbFields[$table]['fields'])) {
|
||||
$header = $this->dumpHeader();
|
||||
$tableHeader = $this->dumpTableHeader($table, $dbFields[$table], true);
|
||||
$insertStatements = $this->dumpTableContent($table, $dbFields[$table]['fields']);
|
||||
$out .= $header . self::MULTI_LINEBREAKS . $tableHeader . self::MULTI_LINEBREAKS . $insertStatements . self::MULTI_LINEBREAKS;
|
||||
}
|
||||
}
|
||||
return $out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Header comments of the SQL dump file
|
||||
*
|
||||
* @return string Table header
|
||||
*/
|
||||
protected function dumpHeader()
|
||||
{
|
||||
return trim('
|
||||
# TYPO3 Extension Manager dump 1.1
|
||||
#--------------------------------------------------------
|
||||
');
|
||||
}
|
||||
|
||||
/**
|
||||
* Dump CREATE TABLE definition
|
||||
*
|
||||
* @param string $table
|
||||
* @param array $fieldKeyInfo
|
||||
* @param bool $dropTableIfExists
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function dumpTableHeader($table, array $fieldKeyInfo, $dropTableIfExists = false)
|
||||
{
|
||||
$lines = [];
|
||||
$dump = '';
|
||||
// Create field definitions
|
||||
if (isset($fieldKeyInfo['fields']) && is_array($fieldKeyInfo['fields'])) {
|
||||
foreach ($fieldKeyInfo['fields'] as $fieldN => $data) {
|
||||
$lines[] = ' ' . $fieldN . ' ' . $data;
|
||||
}
|
||||
}
|
||||
// Create index key definitions
|
||||
if (isset($fieldKeyInfo['keys']) && is_array($fieldKeyInfo['keys'])) {
|
||||
foreach ($fieldKeyInfo['keys'] as $fieldN => $data) {
|
||||
$lines[] = ' ' . $data;
|
||||
}
|
||||
}
|
||||
// Compile final output:
|
||||
if (!empty($lines)) {
|
||||
$dump = trim('
|
||||
#
|
||||
# Table structure for table "' . $table . '"
|
||||
#
|
||||
' . ($dropTableIfExists ? 'DROP TABLE IF EXISTS ' . $table . ';
|
||||
' : '') . 'CREATE TABLE ' . $table . ' (
|
||||
' . implode((',' . LF), $lines) . '
|
||||
);');
|
||||
}
|
||||
return $dump;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dump table content
|
||||
* Is DBAL compliant, but the dump format is written as MySQL standard.
|
||||
* If the INSERT statements should be imported in a DBMS using other
|
||||
* quoting than MySQL they must first be translated.
|
||||
*
|
||||
* @param string $table Table name
|
||||
* @param array $fieldStructure Field structure
|
||||
*
|
||||
* @return string SQL Content of dump (INSERT statements)
|
||||
*/
|
||||
protected function dumpTableContent($table, array $fieldStructure)
|
||||
{
|
||||
// Substitution of certain characters (borrowed from phpMySQL):
|
||||
$search = ['\\', '\'', "\0", "\n", "\r", "\x1A"];
|
||||
$replace = ['\\\\', '\\\'', '\\0', '\\n', '\\r', '\\Z'];
|
||||
$lines = [];
|
||||
// Names of inserted fields
|
||||
$fieldList = implode (', ', array_keys($fieldStructure));
|
||||
// Select all rows from the table:
|
||||
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
|
||||
->getQueryBuilderForTable($table);
|
||||
$queryBuilder->getRestrictions()
|
||||
->removeAll();
|
||||
$result = $queryBuilder->select('*')
|
||||
->from($table)
|
||||
->execute();
|
||||
// Traverse the selected rows and dump each row as a line in the file:
|
||||
while ($row = $result->fetch()) {
|
||||
$values = [];
|
||||
foreach ($fieldStructure as $field => $structure) {
|
||||
$values[] = isset($row[$field]) ? '\'' . str_replace($search, $replace, $row[$field]) . '\'' : 'NULL';
|
||||
}
|
||||
$lines[] = 'INSERT INTO ' . $table . ' (' . $fieldList . ')' . ' VALUES (' . implode(', ', $values) . ');';
|
||||
}
|
||||
// Implode lines and return:
|
||||
return implode(LF, $lines);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
<?php
|
||||
namespace SJBR\StaticInfoTables\Utility;
|
||||
|
||||
/***************************************************************
|
||||
* Copyright notice
|
||||
*
|
||||
* (c) 2013-2017 StanislasRolland <typo3@sjbr.ca>
|
||||
* All rights reserved
|
||||
*
|
||||
* This script is part of the Typo3 project. The Typo3 project is
|
||||
* free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The GNU General Public License can be found at
|
||||
* http://www.gnu.org/copyleft/gpl.html.
|
||||
*
|
||||
* This script is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* This copyright notice MUST APPEAR in all copies of the script!
|
||||
***************************************************************/
|
||||
/**
|
||||
* HTML form element utility functions
|
||||
*/
|
||||
class HtmlElementUtility
|
||||
{
|
||||
/**
|
||||
* Buils a HTML drop-down selector of countries, country subdivisions, currencies or languages
|
||||
*
|
||||
* @param array $items: An array of couples ('name', 'value) where the names will be the texts of an <option> tags and values will be the values of the tags
|
||||
* @param array $selected: The values of the code of the entries to be pre-selected in the drop-down selector
|
||||
* @param array $outSelected: resulting array of keys of selected items
|
||||
* @param string $name: A value for the name attribute of the <select> tag
|
||||
* @param string $class: A value for the class attribute of the <select> tag
|
||||
* @param string $id: A value for the id attribute of the <select> tag
|
||||
* @param string $title: A value for the title attribute of the <select> tag
|
||||
* @param string $onChange: A value for the onChange attribute of the <select> tag
|
||||
* @param int $size: max elements that can be selected. Default: 1
|
||||
*
|
||||
* @return string A set of HTML <select> and <option> tags
|
||||
*/
|
||||
public static function selectConstructor($items, $selected = [], &$outSelected = [], $name = '', $class = '', $id = '', $title = '', $onChange = '', $size = 1)
|
||||
{
|
||||
$selector = '';
|
||||
if (is_array($items) && count($items) > 0) {
|
||||
$idAttribute = (trim($id)) ? 'id="' . htmlspecialchars(trim($id)) . '" ' : '';
|
||||
$nameAttribute = (trim($name)) ? 'name="' . htmlspecialchars(trim($name)) . '" ' : '';
|
||||
$titleAttribute = (trim($title)) ? 'title="' . htmlspecialchars(trim($title)) . '" ' : '';
|
||||
$classAttribute = (trim($class)) ? 'class="' . htmlspecialchars(trim($class)) . '" ' : '';
|
||||
|
||||
if ($onChange) {
|
||||
$onChangeAttribute = $onChange;
|
||||
$onChangeAttribute = str_replace('"', '\'', $onChangeAttribute);
|
||||
$onChangeAttribute = self::quoteJsValue($onChangeAttribute);
|
||||
$onChangeAttribute = 'onchange=' . $onChangeAttribute . ' ';
|
||||
} else {
|
||||
$onChangeAttribute = '';
|
||||
}
|
||||
|
||||
if ($size > 1) {
|
||||
$multiple = 'multiple="multiple" ';
|
||||
$name .= '[]';
|
||||
} else {
|
||||
$multiple = '';
|
||||
}
|
||||
|
||||
$selector = '<select size="' . $size . '" ' . $idAttribute . $nameAttribute . $titleAttribute . $classAttribute . $onChangeAttribute . $multiple . '>' . LF;
|
||||
$selector .= self::optionsConstructor($items, $selected, $outSelected);
|
||||
$selector .= '</select>' . LF;
|
||||
}
|
||||
return $selector;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a list of <option> tags
|
||||
*
|
||||
* @param array $items: An array where the values will be the texts of an <option> tags and keys will be the values of the tags
|
||||
* @param string $selected: array of pre-selected values: if the value appears as a key, the <option> tag will bear a 'selected' attribute
|
||||
* @param array $outSelected: resulting array of keys of selected items
|
||||
*
|
||||
* @return string A string of HTML <option> tags
|
||||
*/
|
||||
public static function optionsConstructor($items, $selected = [], &$outSelected = [])
|
||||
{
|
||||
$options = '';
|
||||
foreach ($items as $item) {
|
||||
$options .= '<option value="' . $item['value'] . '"';
|
||||
if (in_array($item['value'], $selected)) {
|
||||
$options .= ' selected="selected"';
|
||||
$outSelected[] = $item['value'];
|
||||
}
|
||||
$options .= '>' . $item['name'] . '</option>' . LF;
|
||||
}
|
||||
if (!isset($outSelected) || count($outSelected) == 0) {
|
||||
reset($items);
|
||||
$outSelected = [$items[0]['value']];
|
||||
}
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Quotes a string for usage as JS parameter.
|
||||
*
|
||||
* @param string The string to encode.
|
||||
* @param mixed $value
|
||||
*
|
||||
* @return string The encoded value already quoted
|
||||
*/
|
||||
protected static function quoteJsValue($value)
|
||||
{
|
||||
$value = addcslashes($value, '"' . LF . CR);
|
||||
$value = htmlspecialchars($value);
|
||||
return '"' . $value . '"';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
<?php
|
||||
namespace SJBR\StaticInfoTables\Utility;
|
||||
|
||||
/*
|
||||
* Copyright notice
|
||||
*
|
||||
* (c) 2013-2021 Stanislas Rolland <typo3AAAA(arobas)sjbr.ca>
|
||||
* All rights reserved
|
||||
*
|
||||
* This script is part of the Typo3 project. The Typo3 project is
|
||||
* free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The GNU General Public License can be found at
|
||||
* http://www.gnu.org/copyleft/gpl.html.
|
||||
*
|
||||
* This script is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* This copyright notice MUST APPEAR in all copies of the script!
|
||||
*/
|
||||
|
||||
use SJBR\StaticInfoTables\Domain\Model\Language;
|
||||
use TYPO3\CMS\Core\Localization\Locales;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Extbase\Utility\LocalizationUtility;
|
||||
|
||||
/**
|
||||
* Locale-related functions
|
||||
*/
|
||||
class LocaleUtility
|
||||
{
|
||||
/**
|
||||
* @var string Name of the extension this class belongs to
|
||||
*/
|
||||
protected $extensionName = 'StaticInfoTables';
|
||||
|
||||
/**
|
||||
* Get the typo3-supported locale options
|
||||
*
|
||||
* @return array An array of language objects
|
||||
*/
|
||||
public function getLocales()
|
||||
{
|
||||
$localeArray = [];
|
||||
$locales = GeneralUtility::makeInstance(Locales::class);
|
||||
$languages = $locales->getLanguages();
|
||||
foreach ($languages as $locale => $language) {
|
||||
// No language pack for English
|
||||
if ($locale != 'default') {
|
||||
$languageObject = new Language();
|
||||
$languageObject->setCollatingLocale($locale);
|
||||
$localizedLanguage = LocalizationUtility::translate('lang_' . $locale, $this->extensionName);
|
||||
$label = ($localizedLanguage ? $localizedLanguage : $language) . ' (' . $locale . ')';
|
||||
$languageObject->setNameEn($label);
|
||||
$localeArray[$label] = $languageObject;
|
||||
}
|
||||
}
|
||||
ksort($localeArray);
|
||||
return $localeArray;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get language name from locale
|
||||
*
|
||||
* @param string $locale
|
||||
* @return string Language name
|
||||
*/
|
||||
public function getLanguageFromLocale($locale)
|
||||
{
|
||||
$locales = GeneralUtility::makeInstance(Locales::class);
|
||||
$languages = $locales->getLanguages();
|
||||
return $languages[$locale];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,378 @@
|
||||
<?php
|
||||
namespace SJBR\StaticInfoTables\Utility;
|
||||
|
||||
/*
|
||||
* Copyright notice
|
||||
*
|
||||
* (c) 2009 Sebastian Kurfürst <sebastian@typo3.org>
|
||||
* (c) 2013-2022 Stanislas Rolland <typo3AAAA@sjbr.ca>
|
||||
* All rights reserved
|
||||
*
|
||||
* This script is part of the TYPO3 project. The TYPO3 project is
|
||||
* free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The GNU General Public License can be found at
|
||||
* http://www.gnu.org/copyleft/gpl.html.
|
||||
*
|
||||
* This script is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* This copyright notice MUST APPEAR in all copies of the script!
|
||||
*/
|
||||
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use SJBR\StaticInfoTables\Domain\Model\Language;
|
||||
use SJBR\StaticInfoTables\Domain\Repository\LanguageRepository;
|
||||
use TYPO3\CMS\Core\Database\ConnectionPool;
|
||||
use TYPO3\CMS\Core\Http\ApplicationType;
|
||||
use TYPO3\CMS\Core\Localization\LanguageService;
|
||||
use TYPO3\CMS\Core\Localization\Locales;
|
||||
use TYPO3\CMS\Core\Site\Entity\SiteLanguage;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Core\Utility\MathUtility;
|
||||
use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
|
||||
|
||||
/**
|
||||
* Localization helper which should be used to fetch localized labels for static info entities.
|
||||
*/
|
||||
class LocalizationUtility
|
||||
{
|
||||
/**
|
||||
* Key of the language to use
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected static $languageKey = 'default';
|
||||
|
||||
/**
|
||||
* Pointer to alternative fall-back language to use
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected static $alternativeLanguageKeys = [];
|
||||
|
||||
/**
|
||||
* Collating locale for the language in use
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected static $collatingLocale = '';
|
||||
|
||||
/**
|
||||
* Returns the localized label for a static info entity
|
||||
*
|
||||
* @param array $identifiers An array with key 1- 'uid' containing a uid and/or 2- 'iso' containing one or two iso codes (i.e. country zone code and country code, or language code and country code)
|
||||
* @param string $tableName The name of the table
|
||||
* @param bool local name only - if set local labels are returned
|
||||
* @param mixed $local
|
||||
* @return string The value from the label field of the table
|
||||
*/
|
||||
public static function translate($identifiers, $tableName, $local = false)
|
||||
{
|
||||
$value = '';
|
||||
self::setLanguageKeys();
|
||||
$isoLanguage = self::getIsoLanguageKey(self::$languageKey);
|
||||
$value = self::getLabelFieldValue($identifiers, $tableName, $isoLanguage, $local);
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the localized value for the label field
|
||||
*
|
||||
* @param array $identifiers An array with key 1- 'uid' containing a uid and/or 2- 'iso' containing one or two iso codes (i.e. country zone code and country code, or language code and country code)
|
||||
* @param string $tableName The name of the table
|
||||
* @param string language ISO code
|
||||
* @param bool local name only - if set local labels are returned
|
||||
* @param mixed $language
|
||||
* @param mixed $local
|
||||
*
|
||||
* @return string the value for the label field
|
||||
*/
|
||||
public static function getLabelFieldValue($identifiers, $tableName, $language, $local = false)
|
||||
{
|
||||
$value = '';
|
||||
$labelFields = self::getLabelFields($tableName, $language, $local);
|
||||
if (count($labelFields)) {
|
||||
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($tableName);
|
||||
$queryBuilder->from($tableName)->select('uid');
|
||||
foreach ($labelFields as $labelField => $map) {
|
||||
$queryBuilder->addSelect($labelField);
|
||||
}
|
||||
$whereCount = 0;
|
||||
if ($identifiers['uid'] ?? false) {
|
||||
$queryBuilder->where(
|
||||
$queryBuilder->expr()->eq('uid', $queryBuilder->createNamedParameter((int)$identifiers['uid']), \PDO::PARAM_INT)
|
||||
);
|
||||
$whereCount++;
|
||||
} elseif (!empty($identifiers['iso'])) {
|
||||
$isoCode = is_array($identifiers['iso']) ? $identifiers['iso'] : [$identifiers['iso']];
|
||||
foreach ($isoCode as $index => $code) {
|
||||
if ($code) {
|
||||
$field = self::getIsoCodeField($tableName, $code, $index);
|
||||
if ($field) {
|
||||
if ($whereCount) {
|
||||
$queryBuilder->andWhere(
|
||||
$queryBuilder->expr()->eq($field, $queryBuilder->createNamedParameter($code))
|
||||
);
|
||||
$whereCount++;
|
||||
} else {
|
||||
$queryBuilder->where(
|
||||
$queryBuilder->expr()->eq($field, $queryBuilder->createNamedParameter($code))
|
||||
);
|
||||
$whereCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Get the entity
|
||||
if ($whereCount) {
|
||||
$row = $queryBuilder->execute()->fetch();
|
||||
if ($row) {
|
||||
foreach ($labelFields as $labelField => $map) {
|
||||
if ($row[$labelField]) {
|
||||
$value = $row[$labelField];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the label fields for a given language
|
||||
*
|
||||
* @param string table name
|
||||
* @param string ISO language code to be used
|
||||
* @param bool If set, we are looking for the "local" title field
|
||||
* @param mixed $tableName
|
||||
* @param mixed $lang
|
||||
* @param mixed $local
|
||||
* @return array field names
|
||||
*/
|
||||
public static function getLabelFields($tableName, $lang, $local = false)
|
||||
{
|
||||
$labelFields = [];
|
||||
if (isset($GLOBALS['TYPO3_CONF_VARS']['EXTENSIONS']['static_info_tables']['tables'][$tableName]['label_fields'])
|
||||
&& is_array($GLOBALS['TYPO3_CONF_VARS']['EXTENSIONS']['static_info_tables']['tables'][$tableName]['label_fields'])) {
|
||||
$alternativeLanguages = [];
|
||||
if (count(self::$alternativeLanguageKeys)) {
|
||||
$alternativeLanguages = array_reverse(self::$alternativeLanguageKeys);
|
||||
}
|
||||
foreach ($GLOBALS['TYPO3_CONF_VARS']['EXTENSIONS']['static_info_tables']['tables'][$tableName]['label_fields'] as $field => $map) {
|
||||
if ($local) {
|
||||
$labelField = str_replace('##', 'local', $field);
|
||||
$property = str_replace('##', 'Local', $map['mapOnProperty']);
|
||||
} else {
|
||||
$labelField = str_replace('##', strtolower($lang), $field);
|
||||
$property = str_replace('##', ucfirst(strtolower($lang)), $map['mapOnProperty']);
|
||||
}
|
||||
// Make sure the resulting field name exists in the table
|
||||
if (isset($GLOBALS['TCA'][$tableName]['columns'][$labelField])
|
||||
&& is_array($GLOBALS['TCA'][$tableName]['columns'][$labelField])
|
||||
) {
|
||||
$labelFields[$labelField] = ['mapOnProperty' => $property];
|
||||
}
|
||||
// Add fields for alternative languages
|
||||
if (strpos($field, '##') !== false && count($alternativeLanguages)) {
|
||||
foreach ($alternativeLanguages as $language) {
|
||||
$labelField = str_replace('##', strtolower($language), $field);
|
||||
$property = str_replace('##', ucfirst(strtolower($language)), $map['mapOnProperty']);
|
||||
// Make sure the resulting field name exists in the table
|
||||
if (is_array($GLOBALS['TCA'][$tableName]['columns'][$labelField])) {
|
||||
$labelFields[$labelField] = ['mapOnProperty' => $property];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $labelFields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a iso code field for the passed table name, iso code and index
|
||||
*
|
||||
* @param string table name
|
||||
* @param string iso code
|
||||
* @param int index in the table's isocode_field configuration array
|
||||
* @param mixed $table
|
||||
* @param mixed $isoCode
|
||||
* @param mixed $index
|
||||
* @return string field name
|
||||
*/
|
||||
public static function getIsoCodeField($table, $isoCode, $index = 0)
|
||||
{
|
||||
$isoCodeField = '';
|
||||
$isoCodeFieldTemplate = $GLOBALS['TYPO3_CONF_VARS']['EXTENSIONS']['static_info_tables']['tables'][$table]['isocode_field'][$index] ?? '';
|
||||
if ($isoCode && $table && $isoCodeFieldTemplate) {
|
||||
$field = str_replace('##', self::isoCodeType($isoCode), $isoCodeFieldTemplate);
|
||||
if (is_array($GLOBALS['TCA'][$table]['columns'][$field])) {
|
||||
$isoCodeField = $field;
|
||||
}
|
||||
}
|
||||
return $isoCodeField;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type of an iso code: nr, 2, 3
|
||||
*
|
||||
* @param string iso code
|
||||
* @param mixed $isoCode
|
||||
*
|
||||
* @return string iso code type
|
||||
*/
|
||||
protected static function isoCodeType($isoCode)
|
||||
{
|
||||
$type = '';
|
||||
$isoCodeAsInteger = MathUtility::canBeInterpretedAsInteger($isoCode);
|
||||
if ($isoCodeAsInteger) {
|
||||
$type = 'nr';
|
||||
} elseif (strlen($isoCode) == 2) {
|
||||
$type = '2';
|
||||
} elseif (strlen($isoCode) == 3) {
|
||||
$type = '3';
|
||||
}
|
||||
return $type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the ISO language key corresponding to a TYPO3 language key
|
||||
*
|
||||
* @param string $key The TYPO3 language key
|
||||
*
|
||||
* @return string the ISO language key
|
||||
*/
|
||||
public static function getIsoLanguageKey($key)
|
||||
{
|
||||
return $key === 'default' ? 'EN' : $key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current TYPO3 language
|
||||
*
|
||||
* @return string the TYP3 language key
|
||||
*/
|
||||
public static function getCurrentLanguage()
|
||||
{
|
||||
if (self::$languageKey === 'default') {
|
||||
self::setLanguageKeys();
|
||||
}
|
||||
return self::$languageKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the currently active language/language_alt keys.
|
||||
* Default values are "default" for language key and "" for language_alt key.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected static function setLanguageKeys()
|
||||
{
|
||||
self::$languageKey = 'default';
|
||||
self::$alternativeLanguageKeys = [];
|
||||
if (($GLOBALS['TYPO3_REQUEST'] ?? null) instanceof ServerRequestInterface
|
||||
&& ApplicationType::fromRequest($GLOBALS['TYPO3_REQUEST'])->isFrontend()
|
||||
) {
|
||||
$tsfe = static::getTypoScriptFrontendController();
|
||||
$siteLanguage = self::getCurrentSiteLanguage();
|
||||
// Get values from site language, which takes precedence over TypoScript settings
|
||||
if ($siteLanguage instanceof SiteLanguage) {
|
||||
self::$languageKey = $siteLanguage->getTypo3Language();
|
||||
} elseif (isset($tsfe->config['config']['language'])) {
|
||||
self::$languageKey = $tsfe->config['config']['language'];
|
||||
}
|
||||
if (isset($tsfe->config['config']['language_alt'])) {
|
||||
self::$alternativeLanguageKeys[] = $tsfe->config['config']['language_alt'];
|
||||
}
|
||||
if (empty(self::$alternativeLanguageKeys)) {
|
||||
$locales = GeneralUtility::makeInstance(Locales::class);
|
||||
if (in_array(self::$languageKey, $locales->getLocales())) {
|
||||
foreach ($locales->getLocaleDependencies(self::$languageKey) as $language) {
|
||||
self::$alternativeLanguageKeys[] = $language;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!empty($GLOBALS['BE_USER']->uc['lang'])) {
|
||||
self::$languageKey = $GLOBALS['BE_USER']->uc['lang'];
|
||||
} elseif (!empty(static::getLanguageService()->lang)) {
|
||||
self::$languageKey = static::getLanguageService()->lang;
|
||||
}
|
||||
// Get standard locale dependencies for the backend
|
||||
$locales = GeneralUtility::makeInstance(Locales::class);
|
||||
if (in_array(self::$languageKey, $locales->getLocales())) {
|
||||
foreach ($locales->getLocaleDependencies(self::$languageKey) as $language) {
|
||||
self::$alternativeLanguageKeys[] = $language;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!self::$languageKey || self::$languageKey === 'default') {
|
||||
self::$languageKey = 'EN';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the collating locale
|
||||
*
|
||||
* @return mixed the set locale or false
|
||||
*/
|
||||
public static function setCollatingLocale()
|
||||
{
|
||||
if (self::$collatingLocale === '') {
|
||||
$languageCode = self::getCurrentLanguage();
|
||||
$languageRepository = GeneralUtility::makeInstance(LanguageRepository::class);
|
||||
$languageCodeParts = explode('_', $languageCode, 2);
|
||||
$languageIsoCodeA2 = $languageCodeParts[0] ?? '';
|
||||
$countryIsoCodeA2 = $languageCodeParts[1] ?? '';
|
||||
|
||||
$language = $languageRepository->findOneByIsoCodes($languageIsoCodeA2, $countryIsoCodeA2 ?? '');
|
||||
// If $language is NULL, current language was not found in the Language repository. Most probably, the repository is empty.
|
||||
self::$collatingLocale = ($language instanceof Language) ? $language->getCollatingLocale() : 'en_GB';
|
||||
}
|
||||
return setlocale(
|
||||
LC_COLLATE,
|
||||
[
|
||||
self::$collatingLocale . '.UTF-8',
|
||||
self::$collatingLocale . '.UTF8',
|
||||
self::$collatingLocale . '.utf8',
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the currently configured "site language" if a site is configured (= resolved)
|
||||
* in the current request.
|
||||
*
|
||||
* @return SiteLanguage|null
|
||||
*/
|
||||
protected static function getCurrentSiteLanguage(): ?SiteLanguage
|
||||
{
|
||||
if ($GLOBALS['TYPO3_REQUEST'] instanceof ServerRequestInterface) {
|
||||
return $GLOBALS['TYPO3_REQUEST']->getAttribute('language', null);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return TypoScriptFrontendController
|
||||
*/
|
||||
protected static function getTypoScriptFrontendController()
|
||||
{
|
||||
return $GLOBALS['TSFE'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return LanguageService
|
||||
*/
|
||||
protected static function getLanguageService()
|
||||
{
|
||||
return $GLOBALS['LANG'];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the TYPO3 CMS project.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*
|
||||
* The TYPO3 project - inspiring people to share!
|
||||
*/
|
||||
|
||||
namespace SJBR\StaticInfoTables\Utility;
|
||||
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Core\Utility\MathUtility;
|
||||
|
||||
/**
|
||||
* Class with helper functions for version number handling
|
||||
*/
|
||||
class VersionNumberUtility
|
||||
{
|
||||
/**
|
||||
* Splits a version range into an array.
|
||||
*
|
||||
* If a single version number is given, it is considered a minimum value.
|
||||
* If a dash is found, the numbers left and right are considered as minimum and maximum. Empty values are allowed.
|
||||
* If no version can be parsed "0.0.0" — "0.0.0" is the result
|
||||
*
|
||||
* @param string $version A string with a version range.
|
||||
* @return array
|
||||
*/
|
||||
public static function splitVersionRange($version)
|
||||
{
|
||||
$versionRange = [];
|
||||
if (strpos($version, '-') !== false) {
|
||||
$versionRange = explode('-', $version, 2);
|
||||
} else {
|
||||
$versionRange[0] = $version;
|
||||
$versionRange[1] = '';
|
||||
}
|
||||
if (!$versionRange[0]) {
|
||||
$versionRange[0] = '0.0.0';
|
||||
}
|
||||
if (!$versionRange[1]) {
|
||||
$versionRange[1] = '0.0.0';
|
||||
}
|
||||
return $versionRange;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the version number x.x.x and returns an array with the various parts.
|
||||
* It also forces each … 0 to 999
|
||||
*
|
||||
* @param string $version Version code, x.x.x
|
||||
* @return array
|
||||
*/
|
||||
public static function convertVersionStringToArray($version)
|
||||
{
|
||||
$parts = GeneralUtility::intExplode('.', $version . '..');
|
||||
$parts[0] = MathUtility::forceIntegerInRange($parts[0], 0, 999);
|
||||
$parts[1] = MathUtility::forceIntegerInRange($parts[1], 0, 999);
|
||||
$parts[2] = MathUtility::forceIntegerInRange($parts[2], 0, 999);
|
||||
$result = [];
|
||||
$result['version'] = $parts[0] . '.' . $parts[1] . '.' . $parts[2];
|
||||
$result['version_int'] = (int)($parts[0] * 1000000 + $parts[1] * 1000 + $parts[2]);
|
||||
$result['version_main'] = $parts[0];
|
||||
$result['version_sub'] = $parts[1];
|
||||
$result['version_dev'] = $parts[2];
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to raise a version number
|
||||
*
|
||||
* @param string $raise one of "main", "sub", "dev" - the version part to raise by one
|
||||
* @param string $version (like 4.1.20)
|
||||
* @return string
|
||||
*/
|
||||
public static function raiseVersionNumber($raise, $version)
|
||||
{
|
||||
if (!in_array($raise, ['main', 'sub', 'dev'])) {
|
||||
throw new Exception('RaiseVersionNumber expects one of "main", "sub" or "dev".', 1342639555);
|
||||
}
|
||||
$parts = GeneralUtility::intExplode('.', $version . '..');
|
||||
$parts[0] = MathUtility::forceIntegerInRange($parts[0], 0, 999);
|
||||
$parts[1] = MathUtility::forceIntegerInRange($parts[1], 0, 999);
|
||||
$parts[2] = MathUtility::forceIntegerInRange($parts[2], 0, 999);
|
||||
switch ((string)$raise) {
|
||||
case 'main':
|
||||
$parts[0]++;
|
||||
$parts[1] = 0;
|
||||
$parts[2] = 0;
|
||||
break;
|
||||
case 'sub':
|
||||
$parts[1]++;
|
||||
$parts[2] = 0;
|
||||
break;
|
||||
case 'dev':
|
||||
$parts[2]++;
|
||||
break;
|
||||
}
|
||||
return $parts[0] . '.' . $parts[1] . '.' . $parts[2];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user