From 4d30177fef0eabdd33c57fd72158145fa5192b54 Mon Sep 17 00:00:00 2001 From: Pascal Rinker Date: Thu, 10 Feb 2022 17:07:06 +0100 Subject: [PATCH] [TASK] Support new Avalex API 3.0 with multilanguage texts --- Classes/AvalexPlugin.php | 21 ++++- Classes/Service/ApiService.php | 100 +++++++---------------- Classes/Service/CurlService.php | 114 ++++++++++++++++++++++++++ Classes/Service/LanguageService.php | 121 ++++++++++++++++++++++++++++ Classes/Utility/AvalexUtility.php | 5 ++ ext_autoload.php | 4 +- ext_emconf.php | 22 ++--- ext_localconf.php | 14 ++++ ext_tables.sql | 26 ++++++ 9 files changed, 342 insertions(+), 85 deletions(-) create mode 100644 Classes/Service/CurlService.php create mode 100644 Classes/Service/LanguageService.php diff --git a/Classes/AvalexPlugin.php b/Classes/AvalexPlugin.php index 070b6ee..9b7a3d9 100644 --- a/Classes/AvalexPlugin.php +++ b/Classes/AvalexPlugin.php @@ -70,14 +70,26 @@ public function render($_, $conf) { $endpoint = $this->checkEndpoint($conf['endpoint']); $rootPage = tx_avalex_AvalexUtility::getRootForPage(); - $cacheIdentifier = sprintf('avalex_%s_%d_%d', $endpoint, $rootPage, $GLOBALS['TSFE']->id); + $cacheIdentifier = sprintf( + 'avalex_%s_%d_%d_%s', + $endpoint, + $rootPage, + $GLOBALS['TSFE']->id, + tx_avalex_AvalexUtility::getFrontendLocale() + ); if ($this->cache->has($cacheIdentifier)) { $content = (string)$this->cache->get($cacheIdentifier); } else { + /** @var tx_avalex_AvalexConfigurationRepository $avalexConfigurationRepository */ + $avalexConfigurationRepository = t3lib_div::makeInstance( + 'tx_avalex_AvalexConfigurationRepository' + ); + $configuration = $avalexConfigurationRepository->findByWebsiteRoot($rootPage, 'uid, api_key, domain'); + $language = t3lib_div::makeInstance('tx_avalex_LanguageService', $configuration)->getLanguageForEndpoint($endpoint); /** @var tx_avalex_ApiService $apiService */ $apiService = t3lib_div::makeInstance('tx_avalex_ApiService'); - $content = $apiService->getHtmlForCurrentRootPage($endpoint, $rootPage); - $curlInfo = $apiService->getCurlInfo(); + $content = $apiService->getHtmlForCurrentRootPage($endpoint, $language, $configuration); + $curlInfo = $apiService->getCurlService()->getCurlInfo(); if ($curlInfo['http_code'] === 200) { // set cache for successful calls only $configuration = tx_avalex_AvalexUtility::getExtensionConfiguration(); @@ -86,7 +98,8 @@ public function render($_, $conf) $cacheIdentifier, $content, array(), - $configuration['cacheLifetime'] ? $configuration['cacheLifetime'] : 3600); + $configuration['cacheLifetime'] ? $configuration['cacheLifetime'] : 3600 + ); } } return $content; diff --git a/Classes/Service/ApiService.php b/Classes/Service/ApiService.php index b0488f0..57d8d4f 100644 --- a/Classes/Service/ApiService.php +++ b/Classes/Service/ApiService.php @@ -18,14 +18,9 @@ class tx_avalex_ApiService { /** - * @var array - */ - protected $curlInfo = array(); - - /** - * @var string + * @var tx_avalex_CurlService */ - protected $curlOutput = ''; + protected $curlService; /** * @var array @@ -40,47 +35,22 @@ public function __construct() $this->hookObjectsArray[$key] = $hookObject; } } - } - - /** - * Checks the JSON response - * - * @return bool Returns true if given data is valid or false in case of an error - */ - public function checkResponse() - { - $success = true; - if ($this->curlInfo['http_code'] !== 200) { - $success = false; - t3lib_div::sysLog( - sprintf( - 'The avalex API answered with code "%d" and message: "%s".', - $this->curlInfo['http_code'], - $this->curlOutput - ), - t3lib_div::SYSLOG_SEVERITY_ERROR - ); - } - return $success; + $this->curlService = t3lib_div::makeInstance('tx_avalex_CurlService'); } /** * Get HTML content for current page * - * @param string $endpoint API endpoint to be used e.g. imprint - * @param int $rootPage + * @param string $endpoint API endpoint to be used e.g. imprint + * @param string $language two digit iso code (en, de, ...) + * @param array $configuration required values: api_key: '', domain: '' + * * @return string */ - public function getHtmlForCurrentRootPage($endpoint, $rootPage) + public function getHtmlForCurrentRootPage($endpoint, $language, array $configuration) { $endpoint = (string)$endpoint; - $rootPage = (int)$rootPage; - - /** @var tx_avalex_AvalexConfigurationRepository $avalexConfigurationRepository */ - $avalexConfigurationRepository = t3lib_div::makeInstance( - 'tx_avalex_AvalexConfigurationRepository' - ); - $configuration = $avalexConfigurationRepository->findByWebsiteRoot($rootPage, 'uid, api_key, domain'); + $language = (string)$language; // Hook: Allow to modify $apiKey and $domain before curl sends the request to avalex foreach ($this->hookObjectsArray as $hookObject) { @@ -89,32 +59,32 @@ public function getHtmlForCurrentRootPage($endpoint, $rootPage) } } - $curlResource = curl_init(); - - curl_setopt_array($curlResource, array( - CURLOPT_URL => sprintf( - '%s%s?apikey=%s&domain=%s', - tx_avalex_AvalexUtility::getApiUrl(), - $endpoint, - $configuration['api_key'], - $configuration['domain'] - ), - CURLOPT_RETURNTRANSFER => true, + $requestSuccessful = $this->curlService->request(sprintf( + '%s%s?apikey=%s&domain=%s&lang=%s', + tx_avalex_AvalexUtility::getApiUrl(), + $endpoint, + $configuration['api_key'], + $configuration['domain'], + $language )); - $this->curlOutput = (string)curl_exec($curlResource); - $this->curlInfo = curl_getinfo($curlResource); - - curl_close($curlResource); + $curlInfo = $this->curlService->getCurlInfo(); - if ($this->checkResponse()) { - $content = $this->curlOutput; + if ($requestSuccessful === false) { + // curl error + $content = sprintf( + $GLOBALS['LANG']->sL('LLL:EXT:avalex/Resources/Private/Language/locallang.xml:error.request_failed'), + $this->curlService->getCurlErrno(), + $this->curlService->getCurlError() + ); + } elseif ((int)$curlInfo['http_code'] === 200) { + $content = $this->curlService->getCurlOutput(); } else { // render error message wrapped with translated notice in frontend if request !== 200 $content = sprintf( $GLOBALS['LANG']->sL('LLL:EXT:avalex/Resources/Private/Language/locallang.xml:error.request_failed'), - (int)$this->curlInfo['http_code'], - $this->curlOutput + (int)$curlInfo['http_code'], + $this->curlService->getCurlOutput() ); } @@ -129,18 +99,10 @@ public function getHtmlForCurrentRootPage($endpoint, $rootPage) } /** - * @return array - */ - public function getCurlInfo() - { - return $this->curlInfo; - } - - /** - * @return string + * @return tx_avalex_CurlService */ - public function getCurlOutput() + public function getCurlService() { - return $this->curlOutput; + return $this->curlService; } } diff --git a/Classes/Service/CurlService.php b/Classes/Service/CurlService.php new file mode 100644 index 0000000..61208c6 --- /dev/null +++ b/Classes/Service/CurlService.php @@ -0,0 +1,114 @@ +request('https://domain.tld/api-request'); + * Get http status code: + * $this->getCurlInfo()['http_code']; + * Get response content: + * $this->getCurlOutput(); + */ +class tx_avalex_CurlService +{ + /** + * @var array + */ + protected $curlInfo = array(); + + /** + * @var string + */ + protected $curlOutput = ''; + + /** + * @var string + */ + protected $curlError = ''; + + /** + * @var int + */ + protected $curlErrno = 0; + + /** + * @param $url + * @return bool true on success otherwise false + */ + public function request($url) + { + $curlResource = curl_init(); + + curl_setopt_array($curlResource, array( + CURLOPT_URL => (string)$url, + CURLOPT_RETURNTRANSFER => true, + )); + + $this->curlOutput = (string)curl_exec($curlResource); + $this->curlInfo = curl_getinfo($curlResource); + $this->curlError = curl_error($curlResource); + $this->curlErrno = curl_errno($curlResource); + + curl_close($curlResource); + + if ($this->curlError) { + t3lib_div::sysLog( + sprintf( + 'tx_avalex_CurlService::request with URL "%s" failed! Curl error (%d): "%s"', + $url, + $this->curlErrno, + $this->curlError + ), + 'avalex_legacy', + t3lib_div::SYSLOG_SEVERITY_ERROR + ); + return false; + } + return true; + } + + /** + * @return array + */ + public function getCurlInfo() + { + return $this->curlInfo; + } + + /** + * @return string + */ + public function getCurlOutput() + { + return $this->curlOutput; + } + + /** + * @return string + */ + public function getCurlError() + { + return $this->curlError; + } + + /** + * @return int + */ + public function getCurlErrno() + { + return $this->curlErrno; + } +} diff --git a/Classes/Service/LanguageService.php b/Classes/Service/LanguageService.php new file mode 100644 index 0000000..3c897ad --- /dev/null +++ b/Classes/Service/LanguageService.php @@ -0,0 +1,121 @@ +cache = $GLOBALS['typo3CacheManager']->getCache('avalex_languages'); + } catch (t3lib_cache_exception_NoSuchCache $exception) { + $this->cache = $GLOBALS['typo3CacheFactory']->create( + 'avalex_languages', + $GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']['avalex_languages']['frontend'], + $GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']['avalex_languages']['backend'], + $GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']['avalex_languages']['options'] + ); + } + + $this->frontendLanguage = tx_avalex_AvalexUtility::getFrontendLocale(); + $this->configuration = array( + 'domain' => (string)$configuration['domain'], + 'api_key' => (string)$configuration['api_key'] + ); + } + + /** + * @param string $endpoint + * @return string + */ + public function getLanguageForEndpoint($endpoint) + { + $endpointWithoutPrefix = substr((string)$endpoint, 4); + // avalex default language + $language = 'de'; + $avalexLanguageResponse = $this->getLanguageResponseFromCache() + ? $this->getLanguageResponseFromCache() + : $this->fetchLanguageResponse(); + if ( + array_key_exists($this->frontendLanguage, $avalexLanguageResponse) + && array_key_exists($endpointWithoutPrefix, $avalexLanguageResponse[$this->frontendLanguage]) + ) { + $language = $this->frontendLanguage; + } + return $language; + } + + /** + * @return array + */ + protected function getLanguageResponseFromCache() + { + $language = ''; + $cacheIdentifier = $this->getCacheIdentifier(); + if ($this->cache->has($cacheIdentifier)) { + $language = (array)$this->cache->get($cacheIdentifier); + } + return $language; + } + + /** + * @return array + */ + protected function fetchLanguageResponse() + { + // avalex default language + $response = array(); + $curlService = t3lib_div::makeInstance('tx_avalex_CurlService'); + if ($curlService->request(sprintf( + '%savx-get-domain-langs?apikey=%s&domain=%s&version=3.0.1', + tx_avalex_AvalexUtility::getApiUrl(), + $this->configuration['api_key'], + $this->configuration['domain'] + ))) { + $response = json_decode($curlService->getCurlOutput(), true); + if (is_array($response)) { + $this->cache->set($this->getCacheIdentifier(), $response, array(), 21600); + } else { + $response = array(); + } + } + return $response; + } + + protected function getCacheIdentifier() + { + return md5(sprintf('%s_%s', $this->configuration['domain'], $this->configuration['api_key'])); + } +} diff --git a/Classes/Utility/AvalexUtility.php b/Classes/Utility/AvalexUtility.php index 7a36ec8..c7228e8 100644 --- a/Classes/Utility/AvalexUtility.php +++ b/Classes/Utility/AvalexUtility.php @@ -89,4 +89,9 @@ public static function getListTypes() { return array('avalex_avalex', 'avalex_imprint', 'avalex_bedingungen', 'avalex_widerruf'); } + + public static function getFrontendLocale() + { + return strtolower($GLOBALS['TSFE']->sys_language_isocode); + } } diff --git a/ext_autoload.php b/ext_autoload.php index 981c233..062cccf 100644 --- a/ext_autoload.php +++ b/ext_autoload.php @@ -13,5 +13,7 @@ 'tx_avalex_postapirequesthookinterface' => $extensionClassesPath . 'Hooks/ApiService/PostApiRequestHookInterface.php', 'tx_avalex_preapirequesthookinterface' => $extensionClassesPath . 'Hooks/ApiService/PreApiRequestHookInterface.php', 'tx_avalex_apiservicesetdefaultdomainhook' => $extensionClassesPath . 'Hooks/ApiServiceSetDefaultDomainHook.php', - 'tx_avalex_domainevaluation' => $extensionClassesPath . 'Evaluation/DomainEvaluation.php' + 'tx_avalex_domainevaluation' => $extensionClassesPath . 'Evaluation/DomainEvaluation.php', + 'tx_avalex_curlservice' => $extensionClassesPath . 'Service/CurlService.php', + 'tx_avalex_languageservice' => $extensionClassesPath . 'Service/LanguageService.php' ); diff --git a/ext_emconf.php b/ext_emconf.php index 664ad06..50e6d90 100644 --- a/ext_emconf.php +++ b/ext_emconf.php @@ -1,14 +1,14 @@ 'avalex legacy', @@ -21,7 +21,7 @@ 'uploadfolder' => '', 'createDirs' => '', 'clearCacheOnLoad' => 0, - 'version' => '4.3.0', + 'version' => '4.4.0', 'constraints' => array( 'depends' => array( 'typo3' => '4.3.0-6.1.99', @@ -33,7 +33,7 @@ ), ), 'clearcacheonload' => '', - '_md5_values_when_last_written' => 'a:25:{s:16:"ext_autoload.php";s:4:"409f";s:21:"ext_conf_template.txt";s:4:"b272";s:12:"ext_icon.gif";s:4:"5c06";s:17:"ext_localconf.php";s:4:"4404";s:14:"ext_tables.php";s:4:"06d3";s:14:"ext_tables.sql";s:4:"259a";s:24:"Classes/AvalexPlugin.php";s:4:"d984";s:48:"Classes/Domain/Repository/AbstractRepository.php";s:4:"7ea2";s:59:"Classes/Domain/Repository/AvalexConfigurationRepository.php";s:4:"84e1";s:39:"Classes/Evaluation/DomainEvaluation.php";s:4:"8550";s:41:"Classes/Exception/InvalidUidException.php";s:4:"d4b5";s:48:"Classes/Hooks/ApiServiceSetDefaultDomainHook.php";s:4:"1173";s:29:"Classes/Hooks/DataHandler.php";s:4:"d916";s:56:"Classes/Hooks/ApiService/PostApiRequestHookInterface.php";s:4:"a5d0";s:55:"Classes/Hooks/ApiService/PreApiRequestHookInterface.php";s:4:"b22f";s:54:"Classes/Hooks/PageLayoutView/AvalexPreviewRenderer.php";s:4:"d5c7";s:30:"Classes/Service/ApiService.php";s:4:"acad";s:33:"Classes/Utility/AvalexUtility.php";s:4:"ad9b";s:45:"Configuration/TCA/tx_avalex_configuration.php";s:4:"731c";s:40:"Resources/Private/Language/locallang.xml";s:4:"0039";s:43:"Resources/Private/Language/locallang_db.xml";s:4:"e377";s:40:"Resources/Public/Icons/avalex_avalex.gif";s:4:"90b5";s:45:"Resources/Public/Icons/avalex_bedingungen.gif";s:4:"6e0e";s:41:"Resources/Public/Icons/avalex_imprint.gif";s:4:"36da";s:42:"Resources/Public/Icons/avalex_widerruf.gif";s:4:"1105";}', + '_md5_values_when_last_written' => 'a:27:{s:16:"ext_autoload.php";s:4:"8ed9";s:21:"ext_conf_template.txt";s:4:"b272";s:12:"ext_icon.gif";s:4:"5c06";s:17:"ext_localconf.php";s:4:"4a0b";s:14:"ext_tables.php";s:4:"06d3";s:14:"ext_tables.sql";s:4:"00e2";s:24:"Classes/AvalexPlugin.php";s:4:"16ac";s:48:"Classes/Domain/Repository/AbstractRepository.php";s:4:"7ea2";s:59:"Classes/Domain/Repository/AvalexConfigurationRepository.php";s:4:"84e1";s:39:"Classes/Evaluation/DomainEvaluation.php";s:4:"8550";s:41:"Classes/Exception/InvalidUidException.php";s:4:"d4b5";s:48:"Classes/Hooks/ApiServiceSetDefaultDomainHook.php";s:4:"1173";s:29:"Classes/Hooks/DataHandler.php";s:4:"d916";s:56:"Classes/Hooks/ApiService/PostApiRequestHookInterface.php";s:4:"a5d0";s:55:"Classes/Hooks/ApiService/PreApiRequestHookInterface.php";s:4:"b22f";s:54:"Classes/Hooks/PageLayoutView/AvalexPreviewRenderer.php";s:4:"d5c7";s:30:"Classes/Service/ApiService.php";s:4:"5baa";s:31:"Classes/Service/CurlService.php";s:4:"6e53";s:35:"Classes/Service/LanguageService.php";s:4:"fd7e";s:33:"Classes/Utility/AvalexUtility.php";s:4:"6a23";s:45:"Configuration/TCA/tx_avalex_configuration.php";s:4:"731c";s:40:"Resources/Private/Language/locallang.xml";s:4:"0039";s:43:"Resources/Private/Language/locallang_db.xml";s:4:"e377";s:40:"Resources/Public/Icons/avalex_avalex.gif";s:4:"90b5";s:45:"Resources/Public/Icons/avalex_bedingungen.gif";s:4:"6e0e";s:41:"Resources/Public/Icons/avalex_imprint.gif";s:4:"36da";s:42:"Resources/Public/Icons/avalex_widerruf.gif";s:4:"1105";}', ); ?> \ No newline at end of file diff --git a/ext_localconf.php b/ext_localconf.php index 9564d95..b1e31ab 100644 --- a/ext_localconf.php +++ b/ext_localconf.php @@ -71,6 +71,20 @@ } } +if (!is_array($GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']['avalex_languages'])) { + $GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']['avalex_languages'] = array( + 'frontend' => 't3lib_cache_frontend_VariableFrontend', + 'backend' => 't3lib_cache_backend_DbBackend', + 'options' => array() + ); + if (version_compare(TYPO3_version, '4.6', '<')) { + $GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']['avalex_languages']['options'] = array( + 'cacheTable' => 'tx_avalex_languages_cache', + 'tagsTable' => 'tx_avalex_languages_cache_tags', + ); + } +} + $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['cms/layout/class.tx_cms_layout.php']['tt_content_drawItem']['avalex_newcontentelement'] = 'tx_avalex_AvalexPreviewRenderer'; if (!is_array($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['avalex']['JWeiland\\Avalex\\Service\\ApiService'])) { diff --git a/ext_tables.sql b/ext_tables.sql index b23dcb1..9a639bc 100644 --- a/ext_tables.sql +++ b/ext_tables.sql @@ -24,6 +24,32 @@ CREATE TABLE tx_avalex_cache_tags ( KEY cache_tag (tag) ) ENGINE=InnoDB; +# +# Table structure for table 'tx_avalex_languages_cache' +# +CREATE TABLE tx_avalex_languages_cache ( + id int(11) unsigned NOT NULL auto_increment, + identifier varchar(250) DEFAULT '' NOT NULL, + crdate int(11) unsigned DEFAULT '0' NOT NULL, + content mediumtext, + tags mediumtext, + lifetime int(11) unsigned DEFAULT '0' NOT NULL, + PRIMARY KEY (id), + KEY cache_id (identifier) +) ENGINE=InnoDB; + +# +# Table structure for table 'tx_avalex_languages_cache_tags' +# +CREATE TABLE tx_avalex_languages_cache_tags ( + id int(11) unsigned NOT NULL auto_increment, + identifier varchar(128) DEFAULT '' NOT NULL, + tag varchar(128) DEFAULT '' NOT NULL, + PRIMARY KEY (id), + KEY cache_id (identifier), + KEY cache_tag (tag) +) ENGINE=InnoDB; + # # Table structure for table 'tx_avalex_configuration' #