CRM-16395: Installation with localized default settings (4) (#10518)
authorMathieu Lu <mathieu@bidon.ca>
Tue, 20 Jun 2017 02:49:50 +0000 (22:49 -0400)
committerGitHub <noreply@github.com>
Tue, 20 Jun 2017 02:49:50 +0000 (22:49 -0400)
CRM-16395: Installation with localized default settings

This makes it possible to have a file in "civicrm/l10n/xx_YY/settings.default.json" with default settings that correspond to the locale during installation (ex: default country, currency, date formats, etc).

CRM/Admin/Form/Setting/Localization.php
CRM/Core/BAO/OptionGroup.php
CRM/Core/I18n.php
Civi/Core/Container.php
Civi/Core/LocalizationInitializer.php [new file with mode: 0644]
install/index.php
settings/Localization.setting.php

index 8e2b2718ab23ddb7b25a5337920f4178cc8b9f75..21cd8f8a3a49052a117c98fe0a4d0e6e742234cf 100644 (file)
@@ -191,40 +191,16 @@ class CRM_Admin_Form_Setting_Localization extends CRM_Admin_Form_Setting {
     // we do this only to initialize monetary decimal point and thousand separator
     $config = CRM_Core_Config::singleton();
 
-    // save enabled currencies and defaul currency in option group 'currencies_enabled'
+    // save enabled currencies and default currency in option group 'currencies_enabled'
     // CRM-1496
     if (empty($values['currencyLimit'])) {
       $values['currencyLimit'] = array($values['defaultCurrency']);
     }
-    elseif (!in_array($values['defaultCurrency'],
-      $values['currencyLimit']
-    )
-    ) {
+    elseif (!in_array($values['defaultCurrency'], $values['currencyLimit'])) {
       $values['currencyLimit'][] = $values['defaultCurrency'];
     }
 
-    // sort so that when we display drop down, weights have right value
-    sort($values['currencyLimit']);
-
-    // get labels for all the currencies
-    $options = array();
-
-    $currencySymbols = self::getCurrencySymbols();
-    for ($i = 0; $i < count($values['currencyLimit']); $i++) {
-      $options[] = array(
-        'label' => $currencySymbols[$values['currencyLimit'][$i]],
-        'value' => $values['currencyLimit'][$i],
-        'weight' => $i + 1,
-        'is_active' => 1,
-        'is_default' => $values['currencyLimit'][$i] == $values['defaultCurrency'],
-      );
-    }
-
-    $dontCare = NULL;
-    CRM_Core_OptionGroup::createAssoc('currencies_enabled',
-      $options,
-      $dontCare
-    );
+    self::updateEnabledCurrencies($values['currencyLimit'], $values['defaultCurrency']);
 
     // unset currencyLimit so we dont store there
     unset($values['currencyLimit']);
@@ -269,6 +245,38 @@ class CRM_Admin_Form_Setting_Localization extends CRM_Admin_Form_Setting {
     }
   }
 
+
+  /**
+   * Replace available currencies by the ones provided
+   *
+   * @param $currencies array of currencies ['USD', 'CAD']
+   * @param $default default currency
+   */
+  public static function updateEnabledCurrencies($currencies, $default) {
+
+    // sort so that when we display drop down, weights have right value
+    sort($currencies);
+
+    // get labels for all the currencies
+    $options = array();
+
+    $currencySymbols = CRM_Admin_Form_Setting_Localization::getCurrencySymbols();
+    for ($i = 0; $i < count($currencies); $i++) {
+      $options[] = array(
+        'label' => $currencySymbols[$currencies[$i]],
+        'value' => $currencies[$i],
+        'weight' => $i + 1,
+        'is_active' => 1,
+        'is_default' => $currencies[$i] == $default,
+      );
+    }
+
+    $dontCare = NULL;
+    CRM_Core_OptionGroup::createAssoc('currencies_enabled', $options, $dontCare);
+
+  }
+
+
   /**
    * @return array
    */
@@ -351,6 +359,26 @@ class CRM_Admin_Form_Setting_Localization extends CRM_Admin_Form_Setting {
     }
   }
 
+  public static function onChangeDefaultCurrency($oldCurrency, $newCurrency, $metadata) {
+    if ($oldCurrency == $newCurrency) {
+      return;
+    }
+
+    // ensure that default currency is always in the list of enabled currencies
+    $currencies = array_keys(CRM_Core_OptionGroup::values('currencies_enabled'));
+    if (!in_array($newCurrency, $currencies)) {
+      if (empty($currencies)) {
+        $currencies = array($values['defaultCurrency']);
+      }
+      else {
+        $currencies[] = $newCurrency;
+      }
+
+      CRM_Admin_Form_Setting_Localization::updateEnabledCurrencies($currencies, $newCurrency);
+    }
+
+  }
+
   /**
    * @return array
    */
index d0f0afc71b45f901d632606f9d4de40622ff9f57..b06e37251bcc43ec8ab18972c497309bcd8ea029 100644 (file)
@@ -219,4 +219,36 @@ class CRM_Core_BAO_OptionGroup extends CRM_Core_DAO_OptionGroup {
     return \Civi::$statics[__CLASS__]['titles_by_name'];
   }
 
+  /**
+   * Set the given values to active, and set all other values to inactive.
+   *
+   * @param string $optionGroupName
+   *   e.g "languages"
+   * @param array<string> $activeValues
+   *   e.g. array("en_CA","fr_CA")
+   */
+  public static function setActiveValues($optionGroupName, $activeValues) {
+    $params = array(
+      1 => array($optionGroupName, 'String'),
+    );
+
+    // convert activeValues into placeholders / params in the query
+    $placeholders = array();
+    $i = count($params) + 1;
+    foreach ($activeValues as $value) {
+      $placeholders[] = "%{$i}";
+      $params[$i] = array($value, 'String');
+      $i++;
+    }
+    $placeholders = implode(', ', $placeholders);
+
+    CRM_Core_DAO::executeQuery("
+UPDATE civicrm_option_value cov
+       LEFT JOIN civicrm_option_group cog ON cov.option_group_id = cog.id
+SET cov.is_active = CASE WHEN cov.name IN ({$placeholders}) THEN 1 ELSE 0 END
+WHERE cog.name = %1",
+      $params
+    );
+  }
+
 }
index ca7706cd9d5caf7f5c428b7b35fc1df71ebef29f..9e20536dfe3854345203734dca639356d89a4872 100644 (file)
@@ -163,6 +163,14 @@ class CRM_Core_I18n {
     if (!$all) {
       $all = CRM_Contact_BAO_Contact::buildOptions('preferred_language');
 
+      // get labels
+      $rows = array();
+      $labels = array();
+      CRM_Core_OptionValue::getValues(array('name' => 'languages'), $rows);
+      foreach ($rows as $id => $row) {
+        $labels[$row['name']] = $row['label'];
+      }
+
       // check which ones are available; add them to $all if not there already
       $codes = array();
       if (is_dir(CRM_Core_I18n::getResourceDir()) && $dir = opendir(CRM_Core_I18n::getResourceDir())) {
@@ -170,7 +178,7 @@ class CRM_Core_I18n {
           if (preg_match('/^[a-z][a-z]_[A-Z][A-Z]$/', $filename)) {
             $codes[] = $filename;
             if (!isset($all[$filename])) {
-              $all[$filename] = $filename;
+              $all[$filename] = $labels[$filename];
             }
           }
         }
@@ -186,6 +194,8 @@ class CRM_Core_I18n {
           unset($all[$code]);
         }
       }
+
+      ksort($all);
     }
 
     if ($enabled === NULL) {
index efe6a656c5d55531385ac462369881bb49afcd8d..0c35bcd1baa4804f5a0c96599f83310ba4ae10bc 100644 (file)
@@ -249,6 +249,7 @@ class Container {
     $dispatcher = new CiviEventDispatcher($container);
     $dispatcher->addListener(SystemInstallEvent::EVENT_NAME, array('\Civi\Core\InstallationCanary', 'check'));
     $dispatcher->addListener(SystemInstallEvent::EVENT_NAME, array('\Civi\Core\DatabaseInitializer', 'initialize'));
+    $dispatcher->addListener(SystemInstallEvent::EVENT_NAME, array('\Civi\Core\LocalizationInitializer', 'initialize'));
     $dispatcher->addListener('hook_civicrm_pre', array('\Civi\Core\Event\PreEvent', 'dispatchSubevent'), 100);
     $dispatcher->addListener('hook_civicrm_post', array('\Civi\Core\Event\PostEvent', 'dispatchSubevent'), 100);
     $dispatcher->addListener('hook_civicrm_post::Activity', array('\Civi\CCase\Events', 'fireCaseChange'));
diff --git a/Civi/Core/LocalizationInitializer.php b/Civi/Core/LocalizationInitializer.php
new file mode 100644 (file)
index 0000000..6eb8935
--- /dev/null
@@ -0,0 +1,104 @@
+<?php
+/*
+ +--------------------------------------------------------------------+
+ | CiviCRM version 4.7                                                |
+ +--------------------------------------------------------------------+
+ | Copyright CiviCRM LLC (c) 2004-2015                                |
+ +--------------------------------------------------------------------+
+ | This file is a part of CiviCRM.                                    |
+ |                                                                    |
+ | CiviCRM is free software; you can copy, modify, and distribute it  |
+ | under the terms of the GNU Affero General Public License           |
+ | Version 3, 19 November 2007 and the CiviCRM Licensing Exception.   |
+ |                                                                    |
+ | CiviCRM 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 Affero General Public License for more details.        |
+ |                                                                    |
+ | You should have received a copy of the GNU Affero General Public   |
+ | License and the CiviCRM Licensing Exception along                  |
+ | with this program; if not, contact CiviCRM LLC                     |
+ | at info[AT]civicrm[DOT]org. If you have questions about the        |
+ | GNU Affero General Public License or the licensing of CiviCRM,     |
+ | see the CiviCRM license FAQ at http://civicrm.org/licensing        |
+ +--------------------------------------------------------------------+
+ */
+
+namespace Civi\Core;
+
+use Civi;
+use Civi\Core\Event\SystemInstallEvent;
+
+/**
+ * Class LocalizationInitializer
+ * @package Civi\Core
+ */
+class LocalizationInitializer {
+
+  /**
+   * Load the locale settings based on the installation language
+   *
+   * @param \Civi\Core\Event\SystemInstallEvent $event
+   * @throws \CRM_Core_Exception
+   */
+  public static function initialize(SystemInstallEvent $event) {
+
+    // get the current installation language
+    global $tsLocale;
+    $seedLanguage = $tsLocale;
+    if (!$seedLanguage) {
+      return;
+    }
+
+    // get the corresponding settings file if any
+    $localeDir = \CRM_Core_I18n::getResourceDir();
+    $fileName = $localeDir . $seedLanguage . DIRECTORY_SEPARATOR . 'settings.default.json';
+
+    // initalization
+    $settingsParams = array();
+
+    if (file_exists($fileName)) {
+
+      // load the file and parse it
+      $json = file_get_contents($fileName);
+      $settings = json_decode($json, TRUE);
+
+      if (!empty($settings)) {
+        // get all valid settings
+        $results = civicrm_api3('Setting', 'getfields', array());
+        $validSettings = array_keys($results['values']);
+        // add valid settings to params to send to api
+        foreach ($settings as $setting => $value) {
+          if (in_array($setting, $validSettings)) {
+            $settingsParams[$setting] = $value;
+          }
+
+        }
+
+        // ensure we don't mess with multilingual
+        unset($settingsParams['languageLimit']);
+
+        // support for enabled languages (option group)
+        if (isset($settings['languagesOption']) && count($settings['languagesOption']) > 0) {
+          \CRM_Core_BAO_OptionGroup::setActiveValues('languages', $settings['languagesOption']);
+        }
+
+        // set default currency in currencies_enabled (option group)
+        if (isset($settings['defaultCurrency'])) {
+          \CRM_Admin_Form_Setting_Localization::updateEnabledCurrencies(array($settings['defaultCurrency']), $settings['defaultCurrency']);
+        }
+
+      }
+
+    }
+
+    // in any case, enforce the seedLanguage as the default language
+    $settingsParams['lcMessages'] = $seedLanguage;
+
+    // apply the config
+    civicrm_api3('Setting', 'create', $settingsParams);
+
+  }
+
+}
index ca739c9606ec98e3041bc16972416995562bfd6c..cdd7012d3c5190677715084f053a16aa985459b5 100644 (file)
@@ -177,7 +177,7 @@ foreach ($langs as $locale => $_) {
   }
 }
 
-// Set the locale (required by CRM_Core_Config)
+// Set the CMS
 // This is mostly sympbolic, since nothing we do during the install
 // really requires CIVICRM_UF to be defined.
 $installTypeToUF = array(
@@ -189,6 +189,7 @@ $installTypeToUF = array(
 $uf = (isset($installTypeToUF[$installType]) ? $installTypeToUF[$installType] : 'Drupal');
 define('CIVICRM_UF', $uf);
 
+// Set the Locale (required by CRM_Core_Config)
 global $tsLocale;
 
 $tsLocale = 'en_US';
@@ -1487,6 +1488,13 @@ class Installer extends InstallRequirements {
         // now enable civicrm module.
         module_enable(array('civicrm', 'civicrmtheme'));
 
+        // SystemInstallEvent will be called from here with the first call of CRM_Core_Config,
+        // which calls Core_BAO_ConfigSetting::applyLocale(), who will default to calling
+        // Civi::settings()->get('lcMessages');
+        // Therefore, we need to pass the seedLanguage before that.
+        global $civicrm_setting;
+        $civicrm_setting['domain']['lcMessages'] = $config['seedLanguage'];
+
         // clear block, page, theme, and hook caches
         drupal_flush_all_caches();
 
@@ -1497,15 +1505,6 @@ class Installer extends InstallRequirements {
         $GLOBALS['user'] = $original_user;
         drupal_save_session(TRUE);
 
-        //change the default language to one chosen
-        if (isset($config['seedLanguage']) && $config['seedLanguage'] != 'en_US') {
-          civicrm_api3('Setting', 'create', array(
-              'domain_id' => 'current_domain',
-              'lcMessages' => $config['seedLanguage'],
-            )
-          );
-        }
-
         $output .= '</ul>';
         $output .= '</div>';
         $output .= '</body>';
index dd1764d3f3d029b17a43a64cd095ad85308d24ff..76cc771d779be118871cc6ee77f999debf105d48 100644 (file)
@@ -142,6 +142,9 @@ return array(
     'pseudoconstant' => array(
       'callback' => 'CRM_Admin_Form_Setting_Localization::getCurrencySymbols',
     ),
+    'on_change' => array(
+      'CRM_Admin_Form_Setting_Localization::onChangeDefaultCurrency',
+    ),
   ),
   'defaultContactCountry' => array(
     'group_name' => 'Localization Preferences',