From 40557979f082694e53996791289e331b7fe484e3 Mon Sep 17 00:00:00 2001 From: Coleman Watts Date: Fri, 21 Jun 2019 16:44:27 -0400 Subject: [PATCH] Reset language at end of localized api call --- Civi/API/Subscriber/APIv3SchemaAdapter.php | 3 ++ Civi/API/Subscriber/I18nSubscriber.php | 49 ++++++++++++++++++---- tests/phpunit/api/v3/MultilingualTest.php | 2 +- 3 files changed, 45 insertions(+), 9 deletions(-) diff --git a/Civi/API/Subscriber/APIv3SchemaAdapter.php b/Civi/API/Subscriber/APIv3SchemaAdapter.php index e6428711eb..3831cdf4d8 100644 --- a/Civi/API/Subscriber/APIv3SchemaAdapter.php +++ b/Civi/API/Subscriber/APIv3SchemaAdapter.php @@ -82,6 +82,9 @@ class APIv3SchemaAdapter implements EventSubscriberInterface { */ public function onApiPrepare_validate(\Civi\API\Event\Event $event) { $apiRequest = $event->getApiRequest(); + if ($apiRequest['version'] > 3) { + return; + } // Not sure why this is omitted for generic actions. It would make sense // to omit 'getfields', but that's only one generic action. diff --git a/Civi/API/Subscriber/I18nSubscriber.php b/Civi/API/Subscriber/I18nSubscriber.php index 5b60b1eb70..02c4d7e797 100644 --- a/Civi/API/Subscriber/I18nSubscriber.php +++ b/Civi/API/Subscriber/I18nSubscriber.php @@ -36,12 +36,20 @@ use Symfony\Component\EventDispatcher\EventSubscriberInterface; */ class I18nSubscriber implements EventSubscriberInterface { + /** + * Used for rolling back language to its original setting after the api call. + * + * @var array + */ + public $originalLang = []; + /** * @return array */ public static function getSubscribedEvents() { return [ Events::PREPARE => ['onApiPrepare', Events::W_MIDDLE], + Events::RESPOND => ['onApiRespond', Events::W_LATE], ]; } @@ -64,7 +72,25 @@ class I18nSubscriber implements EventSubscriberInterface { $language = \CRM_Utils_Array::value('language', $params); } if ($language) { - $this->setLocale($language); + $this->setLocale($language, $apiRequest['id']); + } + } + + /** + * Reset language to the default. + * + * @param \Civi\API\Event\Event $event + * + * @throws \API_Exception + */ + public function onApiRespond(\Civi\API\Event\Event $event) { + $apiRequest = $event->getApiRequest(); + + if (!empty($this->originalLang[$apiRequest['id']])) { + global $tsLocale; + global $dbLocale; + $tsLocale = $this->originalLang[$apiRequest['id']]['tsLocale']; + $dbLocale = $this->originalLang[$apiRequest['id']]['dbLocale']; } } @@ -73,9 +99,10 @@ class I18nSubscriber implements EventSubscriberInterface { * Some code duplication from CRM/Core/BAO/ConfigSetting.php retrieve() * to avoid regressions from refactoring. * @param $lcMessagesRequest + * @param int $requestId * @throws \API_Exception */ - public function setLocale($lcMessagesRequest) { + public function setLocale($lcMessagesRequest, $requestId) { // We must validate whether the locale is valid, otherwise setting a bad // dbLocale could probably lead to sql-injection. $domain = new \CRM_Core_DAO_Domain(); @@ -102,14 +129,20 @@ class I18nSubscriber implements EventSubscriberInterface { } } - global $dbLocale; - - // set suffix for table names - use views if more than one language if ($lcMessages) { - $dbLocale = $multiLang && $lcMessages ? "_{$lcMessages}" : ''; - - // FIXME: an ugly hack to fix CRM-4041 + global $dbLocale; global $tsLocale; + + // Store original value to be restored in $this->onApiRespond + $this->originalLang[$requestId] = [ + 'tsLocale' => $tsLocale, + 'dbLocale' => $dbLocale, + ]; + + // Set suffix for table names - use views if more than one language + $dbLocale = "_{$lcMessages}"; + + // Also set tsLocale - CRM-4041 $tsLocale = $lcMessages; } } diff --git a/tests/phpunit/api/v3/MultilingualTest.php b/tests/phpunit/api/v3/MultilingualTest.php index 328b4f6e83..586ee7a65b 100644 --- a/tests/phpunit/api/v3/MultilingualTest.php +++ b/tests/phpunit/api/v3/MultilingualTest.php @@ -90,10 +90,10 @@ class api_v3_MultilingualTest extends CiviUnitTestCase { 'options' => ['language' => 'fr_CA'], )); + // Ensure that after language is changed in previous call it will go back to the default. $default = $this->callAPISuccess('OptionValue', 'getsingle', array( 'option_group_id' => $group['id'], 'name' => 'IM', - 'option.language' => 'en_US', )); $this->assertEquals($french['label'], 'Messagerie instantanée'); -- 2.25.1