Ver Fonte

Merge branch 'master' of https://github.com/unaio/una

AntonLV há 8 anos atrás
pai
commit
7f79ffa95e

+ 1 - 1
inc/version.inc.php

@@ -7,6 +7,6 @@
  * @{
  * @{
  */
  */
 
 
-define('BX_DOL_VERSION', '9.0.0-RC8'); ///< system files version, for DB version @see bx_get_ver, DB and files version must match
+define('BX_DOL_VERSION', '9.0.0-DEV13'); ///< system files version, for DB version @see bx_get_ver, DB and files version must match
 
 
 /** @} */
 /** @} */

+ 1 - 1
install/index.php

@@ -10,7 +10,7 @@
 define ('BX_DOL_INSTALL',  true);
 define ('BX_DOL_INSTALL',  true);
 define ('BX_SKIP_INSTALL_CHECK', true);
 define ('BX_SKIP_INSTALL_CHECK', true);
 
 
-define ('BX_DOL_VER', '9.0.0-RC8');
+define ('BX_DOL_VER', '9.0.0-DEV13');
 
 
 define ('BX_INSTALL_DEFAULT_LANGUAGE', 'en');
 define ('BX_INSTALL_DEFAULT_LANGUAGE', 'en');
 
 

Diff do ficheiro suprimidas por serem muito extensas
+ 0 - 0
modules/boonex/dolphin_migration/template/images/icons/std-icon.svg


+ 9 - 0
upgrade/files/9.0.0.RC7-9.0.0.RC8/check.php

@@ -0,0 +1,9 @@
+<?php
+
+$mixCheckResult = 'Update can not be applied';
+
+$sVer = $this->oDb->getOne("SELECT `version` FROM `sys_modules` WHERE `name` = 'system'");
+if ('9.0.0.RC7' == $sVer || '9.0.0-RC7' == $sVer)
+    $mixCheckResult = true;
+
+return $mixCheckResult;

+ 410 - 0
upgrade/files/9.0.0.RC7-9.0.0.RC8/files/inc/classes/BxDolLanguages.php

@@ -0,0 +1,410 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaCore UNA Core
+ * @{
+ */
+
+define('BX_DOL_LANGUAGE_DEFAULT', 'en');
+
+define('BX_DOL_LANGUAGE_DIRECTION_LTR', 'LTR');
+define('BX_DOL_LANGUAGE_DIRECTION_RTL', 'RTL');
+
+define('BX_DOL_LANGUAGE_CATEGORY_SYSTEM', 1);
+define('BX_DOL_LANGUAGE_CATEGORY_CUSTOM', 2);
+
+class BxDolLanguages extends BxDolFactory implements iBxDolSingleton
+{
+    protected $oDb;
+    protected $sCurrentLanguage;
+
+    protected function __construct()
+    {
+        if (isset($GLOBALS['bxDolClasses'][get_class($this)]))
+            trigger_error ('Multiple instances are not allowed for the class: ' . get_class($this), E_USER_ERROR);
+
+        parent::__construct();
+
+        $this->oDb = BxDolLanguagesQuery::getInstance();
+    }
+
+    /**
+     * Prevent cloning the instance
+     */
+    public function __clone()
+    {
+        if (isset($GLOBALS['bxDolClasses'][get_class($this)]))
+            trigger_error('Clone is not allowed for the class: ' . get_class($this), E_USER_ERROR);
+    }
+
+    /**
+     * Get singleton instance of the class
+     */
+    static function getInstance()
+    {
+        if(!isset($GLOBALS['bxDolClasses'][__CLASS__])) {
+            $GLOBALS['bxDolClasses'][__CLASS__] = new BxDolLanguages();
+            $GLOBALS['bxDolClasses'][__CLASS__]->init();
+        }
+
+        return $GLOBALS['bxDolClasses'][__CLASS__];
+    }
+
+    function getCurrentLangName($bSetCookie = true)
+    {
+        $sLang = '';
+
+        if(!$sLang && !empty($_GET['lang']))
+            $sLang = $this->tryToGetLang($_GET['lang'], $bSetCookie);
+
+        if(!$sLang && !empty($_POST['lang']))
+            $sLang = $this->tryToGetLang($_POST['lang'], $bSetCookie);
+
+        if(!$sLang && !empty($_COOKIE['lang']))
+            $sLang = $this->tryToGetLang($_COOKIE['lang']);
+
+        if(!$sLang && !empty($_SERVER['HTTP_ACCEPT_LANGUAGE']))
+            $sLang = $this->tryToGetLang($_SERVER['HTTP_ACCEPT_LANGUAGE']);
+
+        if(!$sLang)
+            $sLang = $this->tryToGetLang(getParam('lang_default'));
+
+        if(!$sLang)
+            $sLang = $this->tryToGetLang(BX_DOL_LANGUAGE_DEFAULT);
+
+        setlocale(LC_TIME, $sLang . '_' . strtoupper($sLang) . '.utf-8', $sLang . '_' . strtoupper($sLang) . '.utf8', $sLang . '.utf-8', $sLang . '.utf8', $sLang);
+        return $sLang;
+    }
+
+    function getCurrentLangId()
+    {
+        return $this->getLangId($this->getCurrentLanguage());
+    }
+
+    function getLangId($sLang)
+    {
+        return $this->oDb->getLanguageId($sLang);
+    }
+
+    function getLangFlag($sLang = '')
+    {
+        if (!$sLang)
+            $sLang = $this->getCurrentLanguage();
+
+        return $this->oDb->getLanguageFlag($sLang);
+    }
+
+    function getLangDirection($sLang = '')
+    {
+        if (!$sLang)
+            $sLang = $this->getCurrentLanguage();
+
+        return strtoupper($this->oDb->getLanguageDirection($sLang));
+    }
+
+    function getLangCountryCode($sLang = '')
+    {
+        if (!$sLang)
+            $sLang = $this->getCurrentLanguage();
+
+        return $this->oDb->getLangCountryCode($sLang);
+    }
+    
+    function getDefaultLangName()
+    {
+        return getParam('lang_default');
+    }
+
+    function getLanguages($bIdAsKey = false, $bActiveOnly = false)
+    {
+        return $this->oDb->getLanguages($bIdAsKey, $bActiveOnly);
+    }
+
+    function getLanguageCategory($sName)
+    {
+        $iId = 0;
+        $this->oDb->getCategoriesBy(array('type' => 'id_by_name', 'value' => $sName), $iId);
+
+        return (int)$iId;
+    }
+
+    /**
+     * It tries to match current language with provided languages array, if nothing is found $sFallbackLanguage is returned.
+     * @param $aLangs - array of languages, example: array('ru' => 1, 'kg' => 1);
+     * @param $sFallbackLanguage - language to return of nothis is found
+     * @return language code string
+     */
+    function detectLanguageFromArray($aLangs, $sFallbackLanguage = 'en')
+    {
+        if (isset($aLangs[$GLOBALS['sCurrentLanguage']])) {
+            return $GLOBALS['sCurrentLanguage'];
+        } 
+        elseif ($sLangCountry = $this->getLangCountryCode()) {
+            if (isset($aLangs[$sLangCountry]))
+                return $sLangCountry;
+            $sLangCountry = str_replace('_', '-', $sLangCountry);
+            if (isset($aLangs[$sLangCountry]))
+                return $sLangCountry;            
+        }
+
+        return $sFallbackLanguage;
+    }
+
+    /**
+     * Get current language.
+     */
+    function getCurrentLanguage()
+    {
+        return $GLOBALS['sCurrentLanguage'];
+    }
+
+    function _t()
+    {
+        global $LANG;
+
+        $key = func_get_arg(0);
+        if(isset($LANG[$key])) {
+            $str = $LANG[$key];
+
+            if(($iNumArgs = func_num_args()) > 1)
+                for($i = 1; $i < $iNumArgs; $i++)
+                    $str = str_replace('{' . ($i - 1) . '}', func_get_arg($i), $str);
+
+            return $str;
+        } else
+            return $key;
+    }
+
+    function _t_err()
+    {
+        return MsgBox(call_user_func_array(array($this, '_t'), func_get_args()));
+    }
+
+    function _t_action()
+    {
+        return MsgBox(call_user_func_array(array($this, '_t'), func_get_args()));
+    }
+
+    function _t_ext($key, $args)
+    {
+        global $LANG;
+
+        if(isset($LANG[$key])) {
+            $str = $LANG[$key];
+
+            if(!is_array($args))
+                return str_replace('{0}', $args, $str);
+
+            foreach ($args as $key => $val)
+                $str = str_replace('{'.$key.'}', $val, $str);
+
+            return $str;
+        } else
+            return $key;
+    }
+
+    function _t_format_size ($iSize)
+    {
+        $a = array (
+            1024 => '_sys_format_size_b',
+            1024*1024 => '_sys_format_size_kb',
+            1024*1024*1024 => '_sys_format_size_mb',
+            1024*1024*1024*1024 => '_sys_format_size_gb',
+            1024*1024*1024*1024*1024 => '_sys_format_size_tb',
+        );
+        foreach($a as $i => $sKey)
+            if($iSize < $i)
+                return $this->_t($sKey, round($iSize / ($i / 1024), 1));
+        return $this->_t('_sys_format_size_b', 0);
+    }
+
+    function _t_format_duration ($iTime)
+    {
+        $iTime = (int)$iTime;
+
+        $sFormat = '%M:%S';
+        if($iTime > 3600)
+            $sFormat = '%H:' . $sFormat;
+
+        return strftime($sFormat, $iTime);
+    }
+
+    function _t_format_currency ($fPrice)
+    {
+        return $this->_t('_sys_currency', getParam('currency_sign'), sprintf("%.2f", (float)$fPrice));
+    }
+
+    function _t_format_extensions ($mixedExtensions)
+    {
+        if (!is_array($mixedExtensions))
+            $a = explode(',', $mixedExtensions);
+        else
+            $a = $mixedExtensions;
+        if (!$a)
+            return '';
+        return '.' . implode(', .', $a);
+    }
+
+    protected function init()
+    {
+        /**
+         * Trying to initialize default language.
+         */
+        $GLOBALS['sCurrentLanguage'] = $GLOBALS['bxDolClasses'][__CLASS__]->getCurrentLangName(false);
+        if($GLOBALS['sCurrentLanguage'] != '') {
+            $sPath = BX_DIRECTORY_PATH_CACHE . 'lang-' . $GLOBALS['sCurrentLanguage'] . '.php';
+            if(!file_exists($sPath))
+                BxDolStudioLanguagesUtils::getInstance()->compileLanguage();
+
+            require($sPath);
+
+            if($this->getLangDirection($GLOBALS['sCurrentLanguage']) == BX_DOL_LANGUAGE_DIRECTION_RTL)
+                BxDolTemplate::getInstance()->addCss('rtl.css');
+        }
+
+        $GLOBALS['bxDolClasses'][__CLASS__]->getCurrentLangName(true);
+        if(isset($_GET['lang'])) {
+            if(BxDolPermalinks::getInstance()->redirectIfNecessary(array('lang')))
+                exit;
+        }
+    }
+
+    protected function tryToGetLang($sLangs, $bSetCookie = false)
+    {
+        $sLangs = trim($sLangs);
+        if(!$sLangs)
+            return '';
+
+        $sLangs = preg_replace( '/[^a-zA-Z0-9,;-]/m', '', $sLangs ); // we do not need 'q=0.3'. we are using live queue :)
+        $sLangs = strtolower($sLangs);
+
+        if(!$sLangs)
+            return '';
+
+        $aLangs = explode(',', $sLangs); // ru,en-us;q=0.7,en;q=0.3 => array( 'ru' , 'en-us;q=0.7' , 'en;q=0.3' );
+        foreach($aLangs as $sLang) {
+            if(!$sLang)
+                continue;
+
+            list($sLang) = explode(';', $sLang, 2); // en-us;q=0.7 => en-us
+            if(!$sLang)
+                continue;
+
+            // check with country
+            if($this->checkLangExists($sLang)) {
+                if( $bSetCookie && (!isset($_COOKIE['lang']) || $_COOKIE['lang'] != $sLang) && (!isset($GLOBALS['glLangSet']) || $GLOBALS['glLangSet'] != $sLang)) {
+                    $this->setLangCookie( $sLang );
+                    $GLOBALS['glLangSet'] = $sLang;
+                }
+                return $sLang;
+            }
+
+            //drop country
+            if(strpos($sLang, '-') === false)
+                continue;
+
+            list($sLang, $sCntr) = explode('-', $sLang, 2); // en-us => en
+            if(!$sLang or !$sCntr)
+                continue; //no lang or nothing changed
+
+            //check again. without country
+            if($this->checkLangExists($sLang)) {
+                if($bSetCookie)
+                    $this->setLangCookie($sLang);
+                return $sLang;
+            }
+        }
+        return '';
+    }
+    protected function checkLangExists( $sLang )
+    {
+        if(!preg_match('/^[A-Za-z0-9_]+$/', $sLang))
+            return false;
+
+        $iLangId = $this->oDb->getLanguageId($sLang, false);
+        if(!$iLangId)
+            return false;
+
+        if(file_exists( BX_DIRECTORY_PATH_CACHE . "lang-{$sLang}.php"))
+            return true;
+
+        if(BxDolStudioLanguagesUtils::getInstance()->compileLanguage($iLangId))
+            return true;
+
+        return false;
+    }
+
+    protected function setLangCookie( $sLang )
+    {
+        $sLang = bx_process_input($sLang);
+
+        if(isLogged()) {
+            $iLangId = $this->oDb->getLanguageId($sLang, false);
+            if(!$iLangId)
+                $iLangId = 0;
+
+            $iAccountId = getLoggedId();
+            $oAccountQuery = BxDolAccountQuery::getInstance();
+            $oAccountQuery->updateLanguage($iAccountId, $iLangId);
+        }
+
+        setcookie( 'lang', '',     time() - 60*60*24,    '/' );
+        setcookie( 'lang', $sLang, time() + 60*60*24*365, '/' );
+    }
+}
+
+if (!function_exists('_t')) {
+    function _t()
+    {
+        return call_user_func_array(array(BxDolLanguages::getInstance(), '_t'), func_get_args());
+    }
+}
+
+function _t_err()
+{
+    return call_user_func_array(array(BxDolLanguages::getInstance(), '_t_err'), func_get_args());
+}
+
+function _t_action()
+{
+    return call_user_func_array(array(BxDolLanguages::getInstance(), '_t_action'), func_get_args());
+}
+
+function _t_ext($key, $args)
+{
+    return BxDolLanguages::getInstance()->_t_ext($key, $args);
+}
+
+function _t_format_size($iSize)
+{
+    return BxDolLanguages::getInstance()->_t_format_size($iSize);
+}
+
+function _t_format_duration($iTime)
+{
+    return BxDolLanguages::getInstance()->_t_format_duration($iTime);
+}
+
+function _t_format_currency($fPrice)
+{
+    return BxDolLanguages::getInstance()->_t_format_currency($fPrice);
+}
+
+function _t_format_extensions($mixedExtensions)
+{
+    return BxDolLanguages::getInstance()->_t_format_extensions($mixedExtensions);
+}
+
+function bx_lang_name()
+{
+    return BxDolLanguages::getInstance()->getCurrentLanguage();
+}
+
+function bx_lang_direction($sLanguage = '')
+{
+    return BxDolLanguages::getInstance()->getLangDirection($sLanguage);
+}
+
+/** @} */

+ 411 - 0
upgrade/files/9.0.0.RC7-9.0.0.RC8/files/inc/classes/BxDolLanguagesQuery.php

@@ -0,0 +1,411 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaCore UNA Core
+ * @{
+ */
+
+class BxDolLanguagesQuery extends BxDolDb implements iBxDolSingleton
+{
+    protected function __construct()
+    {
+        if (isset($GLOBALS['bxDolClasses'][get_class($this)]))
+            trigger_error ('Multiple instances are not allowed for the class: ' . get_class($this), E_USER_ERROR);
+
+        parent::__construct();
+    }
+
+    /**
+     * Prevent cloning the instance
+     */
+    public function __clone()
+    {
+        if (isset($GLOBALS['bxDolClasses'][get_class($this)]))
+            trigger_error('Clone is not allowed for the class: ' . get_class($this), E_USER_ERROR);
+    }
+
+    /**
+     * Get singleton instance of the class
+     */
+    static function getInstance()
+    {
+        if(!isset($GLOBALS['bxDolClasses'][__CLASS__]))
+            $GLOBALS['bxDolClasses'][__CLASS__] = new BxDolLanguagesQuery();
+
+        return $GLOBALS['bxDolClasses'][__CLASS__];
+    }
+
+    function getLanguageId($sName, $bFromCache = true)
+    {
+        return (int)$this->getLanguageField($sName, 'ID', $bFromCache);
+    }
+
+    function getLanguageName($iId, $bFromCache = true)
+    {
+        return $this->getLanguageFieldById($iId, 'Name', $bFromCache);
+    }
+
+    function getLanguageFlag($sName, $bFromCache = true)
+    {
+        return $this->getLanguageField($sName, 'Flag', $bFromCache);
+    }
+
+    function getLanguageDirection($sName, $bFromCache = true)
+    {
+        return $this->getLanguageField($sName, 'Direction', $bFromCache);
+    }
+
+    function getLangCountryCode($sName, $bFromCache = true)
+    {
+        return $this->getLanguageField($sName, 'LanguageCountry', $bFromCache);
+    }
+    
+    protected function getLanguageField($sName, $sField, $bFromCache = true)
+    {
+        $sSql = $this->prepare("SELECT `" . $sField . "` FROM `sys_localization_languages` WHERE `Name`=? AND `Enabled`='1' LIMIT 1", $sName);
+
+        if($bFromCache)
+            return $this->fromCache('checkLangExists_' . $sName . '_' . $sField, 'getOne', $sSql);
+        else
+            return $this->getOne($sSql);
+    }
+
+    protected function getLanguageFieldById($iId, $sField, $bFromCache = true)
+    {
+        $sSql = $this->prepare("SELECT `" . $sField . "` FROM `sys_localization_languages` WHERE `ID`=? AND `Enabled`='1' LIMIT 1", $iId);
+
+        if($bFromCache)
+            return $this->fromCache('checkLangExists_' . $iId . '_' . $sField, 'getOne', $sSql);
+        else
+            return $this->getOne($sSql);
+    }
+
+    function getLanguages($bIdAsKey = false, $bActiveOnly = false)
+    {
+        return $this->getLanguagesWithKey($bIdAsKey ? 'ID' : 'Name', $bActiveOnly);
+    }
+
+    function getLanguagesWithKey($sKey = 'Name', $bActiveOnly = false)
+    {
+        $sSql = "SELECT * FROM `sys_localization_languages` WHERE 1 " . ($bActiveOnly ? " AND `Enabled`='1'" : "") . " ORDER BY `Title` ASC";
+        return $this->getPairs($sSql, $sKey, 'Title');
+    }
+
+    function getLanguagesBy($aParams, &$aItems, $bReturnCount = true)
+    {
+        $aMethod = array('name' => 'getAll', 'params' => array(0 => 'query'));
+        $sSelectClause = $sJoinClause = $sWhereClause = $sOrderClause = $sLimitClause = "";
+
+        if(!isset($aParams['order']) || empty($aParams['order']))
+           $sOrderClause = " `tl`.`ID` ASC ";
+
+        switch($aParams['type']) {
+            case 'by_id':
+                $aMethod['name'] = 'getRow';
+                $aMethod['params'][1] = array(
+                	'id' => $aParams['value']
+                );
+
+                $sWhereClause .= " AND `tl`.`ID`=:id";
+                break;
+
+            case 'by_name':
+                $aMethod['name'] = 'getRow';
+                $aMethod['params'][1] = array(
+                	'name' => $aParams['value']
+                );
+
+                $sWhereClause .= " AND `tl`.`Name`=:name";
+                break;
+
+            case 'default':
+                $aMethod['name'] = 'getRow';
+                $aMethod['params'][1] = array(
+                	'name' => getParam('lang_default')
+                );
+
+                $sWhereClause .= " AND `tl`.`Name`=:name";
+                break;
+
+            case 'active':
+                $sWhereClause = " AND `tl`.`Enabled`='1'";
+                break;
+
+            case 'all':
+                $sOrderClause = " `tl`.`Name` ASC ";
+                break;
+
+            case 'all_by_id':
+            	$aMethod['params'][1] = array(
+                	'id' => $aParams['value']
+                );
+
+                $sWhereClause .= " AND `tl`.`ID`=:id";
+                $sOrderClause = " `tl`.`Name` ASC ";
+                break;
+
+			case 'all_by_name':
+				$aMethod['params'][1] = array(
+                	'name' => $aParams['value']
+                );
+
+                $sWhereClause .= " AND `tl`.`Name`=:name";
+                $sOrderClause = " `tl`.`Name` ASC ";
+                break;
+
+            case 'all_key_id':
+                $aMethod['name'] = 'getAllWithKey';
+                $aMethod['params'][1] = 'id';
+
+                if(isset($aParams['language']) && (int)$aParams['language'] != 0) {
+                	$aMethod['params'][2] = array(
+	                	'id' => $aParams['language']
+	                );
+
+                    $sWhereClause .= " AND `tl`.`ID`=:id";
+                }
+                break;
+        }
+
+        $aMethod['params'][0] = "SELECT SQL_CALC_FOUND_ROWS
+                `tl`.`ID` AS `id`,
+                `tl`.`Name` AS `name`,
+                `tl`.`Flag` AS `flag`,
+                `tl`.`Title` AS `title`,
+                `tl`.`Enabled` AS `enabled`" . $sSelectClause . "
+            FROM `sys_localization_languages` AS `tl`" . $sJoinClause . "
+            WHERE 1" . $sWhereClause . "
+            ORDER BY" . $sOrderClause . $sLimitClause;
+        $aItems = call_user_func_array(array($this, $aMethod['name']), $aMethod['params']);
+
+        if(!$bReturnCount)
+            return count($aItems) > 0;
+
+        return (int)$this->getOne("SELECT FOUND_ROWS()");
+    }
+
+    function getKeys()
+    {
+        $sSql = "SELECT `ID`, `IDCategory`, `Key` FROM `sys_localization_keys`";
+        return $this->getAllWithKey($sSql, 'ID');
+    }
+
+    function getKeysBy($aParams, &$aItems)
+    {
+        $aMethod = array('name' => 'getAll', 'params' => array(0 => 'query'));
+        $sSelectClause = $sJoinClause = $sWhereClause = $sGroupClause = $sOrderClause = $sLimitClause = "";
+
+        $sSelectClause = "`tk`.`ID` AS `id`, `tk`.`IDCategory` AS `category_id`, `tk`.`Key` AS `key`";
+
+        if(!isset($aParams['order']) || empty($aParams['order']))
+           $sOrderClause = " `tk`.`Key` ASC ";
+
+        switch($aParams['type']) {
+            case 'by_ids':
+                $sSelectClause .= ", `tc`.`Name` AS `category_name`, `ts`.`IDLanguage` AS `language_id`, `tl`.`Name` AS `language_name`, `tl`.`Title` AS `language_title`, `ts`.`String` AS `string`";
+                $sJoinClause = " LEFT JOIN `sys_localization_categories` AS `tc` ON `tk`.`IDCategory`=`tc`.`ID` LEFT JOIN `sys_localization_strings` AS `ts` ON `tk`.`ID`=`ts`.`IDKey` LEFT JOIN `sys_localization_languages` AS `tl` ON `ts`.`IDLanguage`=`tl`.`ID` ";
+                $sWhereClause .= " AND `tk`.`ID` IN ('" . implode("','", $aParams['value']) . "')";
+
+                if(isset($aParams['language']) && (int)$aParams['language'] != 0) {
+                	$aMethod['params'][1] = array(
+	                	'id' => $aParams['language']
+	                );
+
+                    $sWhereClause .= " AND `tl`.`ID`=:id";
+                }
+                break;
+
+            case 'by_name':
+                $aMethod['name'] = 'getRow';
+                $aMethod['params'][1] = array(
+                	'key' => $aParams['value']
+                );
+
+                $sWhereClause = " AND `tk`.`Key`=:key ";
+                break;
+
+			case 'by_language_name_key_key':
+            	$aMethod['name'] = 'getAllWithKey';
+            	$aMethod['params'][1] = 'key';
+            	$aMethod['params'][2] = array(
+                	'name' => $aParams['value']
+                );
+
+                $sSelectClause .= ", `ts`.`String` AS `string` ";
+                $sJoinClause = " LEFT JOIN `sys_localization_strings` AS `ts` ON `tk`.`ID`=`ts`.`IDKey` LEFT JOIN `sys_localization_languages` AS `tl` ON `ts`.`IDLanguage`=`tl`.`ID` ";
+                $sWhereClause = " AND `tl`.`Name`=:name ";
+                break;
+
+            case 'by_language_id_key_key':
+            	$aMethod['name'] = 'getAllWithKey';
+            	$aMethod['params'][1] = 'key';
+            	$aMethod['params'][2] = array(
+                	'language_id' => (int)$aParams['value']
+                );
+
+                $sSelectClause .= ", `ts`.`String` AS `string` ";
+                $sJoinClause = " LEFT JOIN `sys_localization_strings` AS `ts` ON `tk`.`ID`=`ts`.`IDKey` ";
+                $sWhereClause = " AND `ts`.`IDLanguage`=:language_id ";
+                break;
+
+            case 'search':
+                $aMethod['name'] = 'getColumn';
+                $aMethod['params'][1] = array();
+
+                $sSelectClause = "DISTINCT `tk`.`ID` AS `id`";
+                $sJoinClause = " LEFT JOIN `sys_localization_categories` AS `tc` ON `tk`.`IDCategory`=`tc`.`ID` LEFT JOIN `sys_localization_strings` AS `ts` ON `tk`.`ID`=`ts`.`IDKey` LEFT JOIN `sys_localization_languages` AS `tl` ON `ts`.`IDLanguage`=`tl`.`ID` ";
+
+                if(isset($aParams['category']) && (int)$aParams['category'] != 0) {
+                	$aMethod['params'][1]['category_id'] = $aParams['category'];
+
+                    $sWhereClause .= " AND `tc`.`ID`=:category_id";
+                }
+
+                if(isset($aParams['language']) && (int)$aParams['language'] != 0) {
+                	$aMethod['params'][1]['language_id'] = $aParams['language'];
+
+                    $sWhereClause .= " AND `tl`.`ID`=:language_id";
+                }
+
+                if(isset($aParams['keyword']) && $aParams['keyword'] != '' && $aParams['keyword'] != _t('_adm_pgt_txt_keyword')) {
+                	$aMethod['params'][1]['key'] = '%' . $aParams['keyword'] . '%';
+                	$aMethod['params'][1]['string'] = '%' . $aParams['keyword'] . '%';
+
+                    $sWhereClause .= " AND (`tk`.`Key` LIKE :key OR `ts`.`String` LIKE :string)";
+                }
+
+                $iStart = 0;
+                if(isset($aParams['start']) && (int)$aParams['start'] != 0)
+                    $iStart = $aParams['start'];
+
+                $iLength = 20;
+                if(isset($aParams['length']) && (int)$aParams['length'] != 0)
+                    $iLength = $aParams['length'];
+
+				$aMethod['params'][1]['start'] = $iStart;
+				$aMethod['params'][1]['length'] = $iLength;
+                $sLimitClause .= " LIMIT :start, :length";
+                break;
+
+            case 'counter_by_category':
+                $aMethod['name'] = 'getPairs';
+                $aMethod['params'][1] = 'category_id';
+                $aMethod['params'][2] = 'counter';
+                $sSelectClause .= ", COUNT(*) AS `counter`";
+                $sGroupClause = "GROUP BY `tk`.`IDCategory`";
+                break;
+        }
+
+        $aMethod['params'][0] = "SELECT " . $sSelectClause . "
+            FROM `sys_localization_keys` AS `tk`" . $sJoinClause . "
+            WHERE 1" . $sWhereClause . " " . $sGroupClause . "
+            ORDER BY" . $sOrderClause . $sLimitClause;
+        $aItems = call_user_func_array(array($this, $aMethod['name']), $aMethod['params']);
+
+        return $aItems !== false;
+    }
+
+    function getCategories()
+    {
+        $sSql = "SELECT `ID`, `Name` FROM `sys_localization_categories` ORDER BY `Name`";
+        return $this->getPairs($sSql, 'ID', 'Name');
+    }
+
+    function getCategoriesBy($aParams, &$aItems, $bReturnCount = true)
+    {
+        $aMethod = array('name' => 'getAll', 'params' => array(0 => 'query'));
+        $sSelectClause = $sJoinClause = $sWhereClause = $sOrderClause = $sLimitClause = "";
+
+        $sSelectClause = "`tc`.`ID` AS `id`, `tc`.`Name` AS `name`";
+
+        if(!isset($aParams['order']) || empty($aParams['order']))
+           $sOrderClause = " `tc`.`ID` ASC ";
+
+        switch($aParams['type']) {
+            case 'id_by_name':
+                $aMethod['name'] = 'getOne';
+                $aMethod['params'][1] = array(
+                	'name' => $aParams['value']
+                );
+
+                $sSelectClause = "`tc`.`ID` AS `id`";
+                $sWhereClause = " AND `tc`.`Name`=:name";
+                break;
+            case 'by_name':
+                $aMethod['name'] = 'getRow';
+                $aMethod['params'][1] = array(
+                	'name' => $aParams['value']
+                );
+
+                $sWhereClause = " AND `tc`.`Name`=:name";
+                break;
+
+            case 'all':
+                $sOrderClause = " `tc`.`Name` ASC ";
+                break;
+        }
+
+        $aMethod['params'][0] = "SELECT " . ($bReturnCount ? "SQL_CALC_FOUND_ROWS" : "") . "
+                " . $sSelectClause . "
+            FROM `sys_localization_categories` AS `tc`" . $sJoinClause . "
+            WHERE 1" . $sWhereClause . "
+            ORDER BY" . $sOrderClause . $sLimitClause;
+        $aItems = call_user_func_array(array($this, $aMethod['name']), $aMethod['params']);
+
+        if(!$bReturnCount)
+            return !empty($aItems);
+
+        return (int)$this->getOne("SELECT FOUND_ROWS()");
+    }
+
+    function getStringsBy($aParams, &$aItems, $bReturnCount = true)
+    {
+        $aMethod = array('name' => 'getAll', 'params' => array(0 => 'query'));
+        $sSelectClause = $sJoinClause = $sWhereClause = $sOrderClause = $sLimitClause = "";
+
+        if(!isset($aParams['order']) || empty($aParams['order']))
+           $sOrderClause = "`ts`.`IDKey` ASC";
+
+        switch($aParams['type']) {
+            case 'by_key_language_id':
+                $aMethod['name'] = 'getRow';
+                $aMethod['params'][1] = array(
+                	'key' => $aParams['key'],
+                	'language_id' => $aParams['language_id']
+                );
+
+                $sJoinClause = "LEFT JOIN `sys_localization_keys` AS `tk` ON `ts`.`IDKey`=`tk`.`ID`";
+                $sWhereClause .= "AND `tk`.`Key`=:key AND `ts`.`IDLanguage`=:language_id";
+                break;
+
+            case 'all_by_key_key_language_id':
+                $aMethod['name'] = 'getAllWithKey';
+                $aMethod['params'][1] = 'language_id';
+                $aMethod['params'][2] = array(
+                	'key' => $aParams['value']
+                );
+
+                $sJoinClause = "LEFT JOIN `sys_localization_keys` AS `tk` ON `ts`.`IDKey`=`tk`.`ID`";
+                $sWhereClause .= "AND `tk`.`Key`=:key";
+                break;
+        }
+
+        $aMethod['params'][0] = "SELECT SQL_CALC_FOUND_ROWS
+                `ts`.`IDKey` AS `key_id`,
+                `ts`.`IDLanguage` AS `language_id`,
+                `ts`.`String` AS `string` " . $sSelectClause . "
+            FROM `sys_localization_strings` AS `ts` " . $sJoinClause . "
+            WHERE 1 " . $sWhereClause . "
+            ORDER BY " . $sOrderClause . " " . $sLimitClause;
+        $aItems = call_user_func_array(array($this, $aMethod['name']), $aMethod['params']);
+
+        if(!$bReturnCount)
+            return count($aItems) > 0;
+
+        return (int)$this->getOne("SELECT FOUND_ROWS()");
+    }
+}
+
+/** @} */

+ 298 - 0
upgrade/files/9.0.0.RC7-9.0.0.RC8/files/inc/classes/BxDolLiveUpdates.php

@@ -0,0 +1,298 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaCore UNA Core
+ * @{
+ */
+
+class BxDolLiveUpdates extends BxDolFactory implements iBxDolSingleton
+{
+	protected $_oQuery;
+
+	/*
+	 * List of all systems (active and inactive) with full description.
+	 */
+    protected $_aSystems;
+
+    /*
+     * List of active systems without any additional info.
+     */
+    protected $_aSystemsActive;
+
+    /*
+     * List of dynamically added transient systems without any additional info. 
+     * It depends on the page where a user is.  
+     */
+    protected $_aSystemsTransient;  
+
+    protected $_iProfileId;
+
+    protected $_iInterval;
+
+	protected $_oCacheObject;
+	protected $_sCacheKey;
+	protected $_iCacheTTL;
+
+    protected $_sJsClass;
+    protected $_sJsObject;
+
+    protected function __construct()
+    {
+        parent::__construct();
+
+        /**
+         * Note. Currently Live Updates are associated with profiles (Profile ID) and therefore they are used for logged in members only.
+         * If it's needed Session ID can be used instead of Profile ID. In this case Live Updates can be used for visitors too. Don't forget
+         * to update BxBaseLiveUpdates::init if Session ID will be used.
+         */
+        $this->_iProfileId = (int)bx_get_logged_profile_id();
+        if(!$this->_iProfileId)
+            return;
+
+        $this->_oQuery = new BxDolLiveUpdatesQuery();
+
+        $this->_iInterval = (int)$this->_oQuery->getParam('sys_live_updates_interval');
+        
+        $this->_oCacheObject = $this->_oQuery->getDbCacheObject();
+        $this->_sCacheKey = 'sys_live_updates_' . $this->_iProfileId;
+        $this->_iCacheTTL = 86400;
+
+        $this->_sJsClass = 'BxDolLiveUpdates';
+    	$this->_sJsObject = 'oLiveUpdates';
+
+    	$this->_aSystems = $this->_getCachedSystems();
+    	$this->_aSystemsActive = array_keys($this->_aSystems);
+    	$this->_aSystemsTransient = array();
+    }
+
+    /**
+     * get live updates instanse
+     * @return ready to use class instance
+     */
+    public static function getInstance()
+    {
+		if(!isset($GLOBALS['bxDolClasses'][__CLASS__]))
+			$GLOBALS['bxDolClasses'][__CLASS__] = new BxTemplLiveUpdates();
+
+		return $GLOBALS['bxDolClasses'][__CLASS__];
+    }
+
+    /**
+     * 
+     * Is called via Ajax Requests only. 
+     */
+    public function perform()
+    {
+		$iIndex = (int)bx_get('index');
+
+		$mixedCacheKey = bx_get('hash');
+		if($mixedCacheKey !== false)
+		    $this->_sCacheKey = base64_decode(bx_process_input($mixedCacheKey));
+
+		$mixedSystemsActive = bx_get('systems_active');
+		if($mixedSystemsActive !== false)
+			$this->_aSystemsActive = array_keys($mixedSystemsActive);
+
+        $mixedSystemsTransient = bx_get('systems_transient');
+		if($mixedSystemsTransient !== false)
+			$this->_aSystemsTransient = array_keys($mixedSystemsTransient);
+
+		$this->_aSystems = $this->_getCachedSystems();
+    	if(empty($this->_aSystems) || !is_array($this->_aSystems))
+    		return array();
+
+        $aCurrent = $mixedSystemsActive;
+        if(empty($aCurrent) || !is_array($aCurrent))
+		    $aCurrent = $this->_getCachedData();
+
+		$aRequested = $this->_getRequestedData($iIndex, true, $aCurrent);
+
+		$aResult = array();
+		$bUpdateCache = false;
+		foreach($aRequested as $sName => $aData) {
+			if(isset($aCurrent[$sName])) {
+                if((int)$aCurrent[$sName] == (int)$aData['count'])			    
+    				continue;
+
+				$aResultData = array('count_new' => $aData['count'], 'count_old' => $aCurrent[$sName]);
+				if(isset($aData['data']))
+					$aResultData = array_merge($aResultData, $aData['data']);
+	
+				$aResult[] = array(
+					'system' => $sName, 
+					'data' => $aResultData,
+					'method' => $aData['method']
+				);
+			}
+
+			$aCurrent[$sName] = $aData['count'];
+			$bUpdateCache = true;
+		}
+
+		if($bUpdateCache)
+			$this->_updateCached('data', $aCurrent);
+
+    	return $aResult;
+    }
+
+    /**
+     * 
+     * Add transient live update for current user on this current page. 
+     * @param string $sName - unique name.
+     * @param integer $iFrequency - call frequency.
+     * @param string $sServiceCall - serialized service call.
+     * @param boolean $bActive - add active/not active live update.
+     */
+    public function add($sName, $iFrequency, $sServiceCall, $bActive = true)
+    {
+        if(!$this->_iProfileId)
+            return false;
+
+        if(empty($this->_aSystemsTransient))
+            $this->_sCacheKey .= $this->_getPageId();
+
+        if(!in_array($sName, $this->_aSystemsTransient))
+    		$this->_aSystemsTransient[] = $sName;
+
+    	if(!in_array($sName, $this->_aSystemsActive))
+    		$this->_aSystemsActive[] = $sName;
+
+    	if(empty($this->_aSystems[$sName])) {
+	    	$this->_aSystems[$sName] = array(
+	    		'name' => $sName,
+	    		'frequency' => $iFrequency,
+	    		'service_call' => $sServiceCall,
+	    		'active' => $bActive ? 1 : 0
+	    	);
+
+	    	$this->_updateCached('systems', $this->_aSystems);
+    	}
+
+    	$mixedResponce = $this->_getRequestedDataBySystem($this->_aSystems[$sName]);
+
+    	$iCount = 0;
+    	if($mixedResponce !== false && isset($mixedResponce['count']))
+    	    $iCount = (int)$mixedResponce['count'];
+
+    	$aCachedData = $this->_getCachedData();
+		$aCachedData[$sName] = $iCount;
+		$this->_updateCached('data', $aCachedData);
+
+    	return $iCount;
+    }
+
+    protected function _getCacheInfo()
+    {
+    	return array(
+    		$this->_oCacheObject,
+    		$this->_oQuery->genDbCacheKey($this->_sCacheKey),
+    		$this->_iCacheTTL
+    	);
+    }
+
+    protected function _getCached($sType)
+    {
+    	list($oCache, $sCacheKey, $iCacheTtl) = $this->_getCacheInfo();
+
+    	$aCached = $oCache->getData($sCacheKey, $iCacheTtl);
+    	if(empty($aCached[$sType])) {
+    		switch($sType) {
+    			case 'systems':
+    				$aCached[$sType] = $this->_oQuery->getSystems();
+    				break;
+
+    			case 'data':
+    				if(!isset($aCached[$sType]))
+    					$aCached[$sType] = array();
+
+    				$aRequested = $this->_getRequestedData();
+    				foreach($this->_aSystems as $sName => $aSystem)
+    					$aCached[$sType][$sName] = !empty($aRequested[$sName]['count']) ? (int)$aRequested[$sName]['count'] : 0;
+    				break;
+    		}
+
+    		if(!empty($aCached[$sType]))
+    			$oCache->setData($sCacheKey, $aCached, $iCacheTtl);
+    	}
+
+    	return $aCached[$sType];
+    }
+
+	protected function _getCachedSystems()
+    {
+    	$aSystems = $this->_getCached('systems');
+    	if(!empty($aSystems) && !empty($this->_aSystemsActive))
+    		$aSystems = array_intersect_key($aSystems, array_flip($this->_aSystemsActive));
+
+    	return $aSystems;
+    }
+
+    protected function _getCachedData()
+    {
+    	return $this->_getCached('data');
+    }
+
+    protected function _clearCached()
+    {
+        list($oCache, $sCacheKey, $iCacheTtl) = $this->_getCacheInfo();
+
+        $oCache->delData($sCacheKey);
+    }
+
+	protected function _updateCached($sKey, $aData)
+    {
+    	list($oCache, $sCacheKey, $iCacheTtl) = $this->_getCacheInfo();
+
+    	$aCached = $oCache->getData($sCacheKey, $iCacheTtl);
+    	$aCached[$sKey] = $aData;
+
+    	$oCache->setData($sCacheKey, $aCached, $iCacheTtl);
+    }
+
+    protected function _getRequestedData($iIndex = 0, $bIndexCheck = false, $aCachedData = array())
+    {
+    	$aResult = array();
+
+    	foreach($this->_aSystems as $sName => $aSystem) {
+    		if(empty($aSystem) || !is_array($aSystem) || (int)$aSystem['active'] != 1)
+    			continue;
+
+			if($bIndexCheck && $iIndex % (int)$aSystem['frequency'] != 0)
+				continue;
+
+			$bCachedDataBySystem = !empty($aCachedData) && isset($aCachedData[$sName]);
+			$mixedResponce = $this->_getRequestedDataBySystem($aSystem, ($bCachedDataBySystem ? (int)$aCachedData[$sName] : 0), !$bCachedDataBySystem);
+			if($mixedResponce === false)
+				continue;
+
+			$aResult[$sName] = $mixedResponce;
+    	}
+
+    	return $aResult;
+    }
+
+    protected function _getRequestedDataBySystem($aSystem, $iCachedData = 0, $bInit = true)
+    {
+		if(!BxDolService::isSerializedService($aSystem['service_call']))
+			return false;
+
+		$aResponce = BxDolService::callSerialized($aSystem['service_call'], array('count' => (int)$iCachedData, 'init' => ($bInit ? 1 : 0)));
+		if(empty($aResponce) || !is_array($aResponce) || !isset($aResponce['count']) || (!$bInit && !isset($aResponce['method'])))
+			return false;
+
+		return $aResponce;
+    }
+
+    protected function _getPageId()
+    {
+        $aPageParams = array();
+        parse_str($_SERVER['QUERY_STRING'], $aPageParams);
+        $aPageParams = array_diff_assoc($aPageParams, array('start', 'per_page', 'order', 'filter'));
+
+        return '_' . md5(bx_append_url_params($_SERVER['PHP_SELF'], $aPageParams));
+    }
+}
+
+/** @} */

+ 12 - 0
upgrade/files/9.0.0.RC7-9.0.0.RC8/files/inc/version.inc.php

@@ -0,0 +1,12 @@
+<?php defined('BX_DOL') or defined('BX_DOL_INSTALL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaCore UNA Core
+ * @{
+ */
+
+define('BX_DOL_VERSION', '9.0.0-RC8'); ///< system files version, for DB version @see bx_get_ver, DB and files version must match
+
+/** @} */

+ 298 - 0
upgrade/files/9.0.0.RC7-9.0.0.RC8/files/studio/classes/BxDolStudioUpdater.php

@@ -0,0 +1,298 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaStudio UNA Studio
+ * @{
+ */
+
+class BxDolStudioUpdater extends BxDolStudioInstaller
+{
+	protected $_aModule;
+
+    public function __construct($aConfig)
+    {
+        parent::__construct($aConfig);
+
+        $this->_aModule = $this->oDb->getModuleByUri($aConfig['module_uri']);
+        $this->_sModulePath = $this->_sBasePath . $aConfig['module_dir'];
+
+        $this->_aActions = array_merge($this->_aActions, array(
+            'check_module_exists' => array(
+                'title' => _t('_adm_txt_modules_check_module_exists'),
+            ),
+            'check_module_matches' => array(
+                'title' => _t('_adm_txt_modules_check_module_matches'),
+            ),
+            'check_module_version' => array(
+                'title' => _t('_adm_txt_modules_check_module_version'),
+            ),
+            'check_module_hash' => array(
+                'title' => _t('_adm_txt_modules_check_module_hash'),
+            ),
+            'update_files' => array(
+                'title' => _t('_adm_txt_modules_update_files'),
+            ),
+            'restore_languages' => array(
+                'title' => _t('_adm_txt_modules_restore_languages'),
+            ),
+        ));
+    }
+
+    public function update($aParams)
+    {
+    	$bHtmlResponce = isset($aParams['html_response']) && (bool)$aParams['html_response'];
+
+        $aResult = array(
+            'operation_title' => _t('_adm_txt_modules_operation_update', $this->_aConfig['title'], $this->_aConfig['version_from'], $this->_aConfig['version_to'])
+        );
+
+        //--- Check for module to update ---//
+        $aModuleInfo = $this->oDb->getModulesBy(array('type' => 'path_and_uri', 'path' => $this->_aConfig['module_dir'], 'uri' => $this->_aConfig['module_uri']));
+        if(!$aModuleInfo)
+            return array_merge($aResult, array(
+                'message' => $this->_displayResult('check_module_exists', false, '_adm_err_modules_module_not_found', $bHtmlResponce),
+                'result' => false
+            ));
+
+		if(isset($aParams['module_name']) && strcmp($aParams['module_name'], $aModuleInfo['name']) !== 0)
+			return array_merge($aResult, array(
+                'message' => $this->_displayResult('check_module_matches', false, '_adm_err_modules_module_not_match', $bHtmlResponce),
+                'result' => false
+            ));
+
+		//--- Check version compatibility ---//
+        if(!$this->_isCompatibleWith())
+            return array(
+                'message' => $this->_displayResult('check_script_version', false, _t('_adm_err_modules_wrong_version_script_update', $aModuleInfo['title']), $bHtmlResponce),
+                'result' => false
+            );
+
+        //--- Check version ---//
+        if(version_compare($aModuleInfo['version'], $this->_aConfig['version_from']) != 0)
+            return array_merge($aResult, array(
+                'message' => $this->_displayResult('check_module_version', false, '_adm_err_modules_wrong_version', $bHtmlResponce),
+                'result' => false
+            ));
+
+        //--- Check hash ---//
+        $aFiles = array();
+        $this->hashFiles(BX_DIRECTORY_PATH_ROOT . 'modules/' . $this->_aConfig['module_dir'], $aFiles);
+
+        list($aFilesChanged, $fChangedPercent) = $this->hashCheck($aFiles, $aModuleInfo['id']);
+        $bAutoupdateForceModifiedFiles = getParam('sys_autoupdate_force_modified_files') == 'on';
+
+    	if(!empty($aFilesChanged) && !$bAutoupdateForceModifiedFiles) 
+    		return array_merge($aResult, array(
+                'message' => $this->_displayResult('check_module_hash', false, '_adm_err_modules_module_was_modified', $bHtmlResponce),
+                'result' => false
+            ));
+		else if($fChangedPercent > BX_FORCE_AUTOUPDATE_MAX_CHANGED_FILES_PERCENT && $bAutoupdateForceModifiedFiles) 
+			return array_merge($aResult, array(
+                'message' => $this->_displayResult('check_module_hash', false, _t('_sys_upgrade_files_checksum_failed_too_many', round($fChangedPercent * 100)), $bHtmlResponce),
+                'result' => false
+            ));
+
+        //--- Perform action and check results ---//
+        $aResult = array_merge($aResult, $this->_perform('install', $aParams));
+        if($aResult['result']) {
+            $this->oDb->updateModule(array('version' => $this->_aConfig['version_to']), array('id' => $aModuleInfo['id']));
+
+            //--- Remove update pàckage ---//
+            $this->delete($aParams);
+        }
+
+        return $aResult;
+    }
+
+    //--- Action Methods ---//
+    protected function actionUpdateFiles($bInstall = true)
+    {
+        $sPath = $this->_sHomePath . 'source/';
+        if(!file_exists($sPath))
+            return BX_DOL_STUDIO_INSTALLER_FAILED;
+
+		$oFile = $this->_getFileManager();
+		if(empty($oFile))
+			return BX_DOL_STUDIO_INSTALLER_FAILED;
+
+		if(!$oFile->copy($sPath . '*', 'modules/' . $this->_aConfig['module_dir']))
+			return BX_DOL_STUDIO_INSTALLER_FAILED;
+
+		if(!empty($this->_aConfig['delete_files']) && is_array($this->_aConfig['delete_files']))
+			foreach($this->_aConfig['delete_files'] as $sFile)
+				if(!$oFile->delete('modules/' . $this->_aConfig['module_dir'] . $sFile))
+					return BX_DOL_STUDIO_INSTALLER_FAILED;
+
+		//--- Update files' tracks
+		$aModuleInfo = $this->oDb->getModulesBy(array('type' => 'path_and_uri', 'path' => $this->_aConfig['module_dir'], 'uri' => $this->_aConfig['module_uri']));
+
+		$this->oDb->deleteModuleTrackFiles($aModuleInfo['id']);
+		
+		$aFiles = array();
+		$this->hashFiles(BX_DIRECTORY_PATH_ROOT . 'modules/' . $this->_aConfig['module_dir'], $aFiles);
+		foreach($aFiles as $aFile)
+			$this->oDb->insertModuleTrack($aModuleInfo['id'], $aFile);
+
+        return BX_DOL_STUDIO_INSTALLER_SUCCESS;
+    }
+
+    protected function actionExecuteSql($sOperation)
+    {
+    	$aModule = $this->oDb->getModuleByUri($this->_aConfig['module_uri']);
+    	if(empty($aModule))
+    		return BX_DOL_STUDIO_INSTALLER_FAILED;
+
+    	$sPathInstall = $this->_sHomePath . 'install/sql/install.sql';
+    	$sPathEnable = $this->_sHomePath . 'install/sql/enable.sql';
+
+    	$mixedResult = true;
+    	if(file_exists($sPathInstall))
+        	$mixedResult = $this->oDb->executeSQL($sPathInstall, $this->getMarkersForDb());
+
+		if($mixedResult === true && (int)$aModule['enabled'] == 1 && file_exists($sPathEnable))
+			$mixedResult = $this->oDb->executeSQL($sPathEnable, $this->getMarkersForDb());
+
+        return $mixedResult === true ? BX_DOL_STUDIO_INSTALLER_SUCCESS : array('code' => BX_DOL_STUDIO_INSTALLER_FAILED, 'content' => $mixedResult);
+    }
+
+    protected function actionUpdateLanguages($bInstall = true)
+    {
+        $aConfig = self::getModuleConfig($this->_sHomePath . 'install/config.php');
+        if(empty($aConfig) || !is_array($aConfig))
+            return BX_DOL_STUDIO_INSTALLER_FAILED;
+
+        $oLanguages = BxDolStudioLanguagesUtils::getInstance();
+        $aLanguages = $oLanguages->getLanguages();
+
+        $aCategories = array();
+        if(!empty($aConfig['language_category']) && is_array($aConfig['language_category'])) {
+        	$aCategories = $aConfig['language_category'];
+        	foreach($aCategories as $iIndex => $aCategory)
+				$aCategories[$iIndex]['id'] = !empty($aCategory['name']) ? $oLanguages->getLanguageCategory($aCategory['name']) : 0;
+        }
+		else
+			$aCategories[] = array(
+				'id' => !empty($aConfig['language_category']) ? $oLanguages->getLanguageCategory($aConfig['language_category']) : 0,
+				'name' => $aConfig['language_category'],
+				'path' => ''
+			);
+
+        foreach($aLanguages as $sName => $sTitle)
+        	foreach($aCategories as $iIndex => $aCategory)
+            	$this->_updateLanguage($bInstall, $sName, $aCategory['id'], $aCategory['path']);
+
+        return $oLanguages->compileLanguage(0, true) ? BX_DOL_STUDIO_INSTALLER_SUCCESS : BX_DOL_STUDIO_INSTALLER_FAILED;
+    }
+
+    /*
+     * Restore module's language files.
+     * 
+     * Note. Mainly the action is needed for Updates in 'language' type modules. 
+     * It should be used after 'update_files' action if some changes were done in module's language files. 
+     */
+    protected function actionRestoreLanguages($bInstall = true)
+    {
+    	$aConfig = self::getModuleConfig($this->_sHomePath . 'install/config.php');
+        if(empty($aConfig) || !is_array($aConfig) || empty($aConfig['module_uri']))
+            return BX_DOL_STUDIO_INSTALLER_FAILED;
+
+        $oLanguages = BxDolStudioLanguagesUtils::getInstance();
+        $aLanguages = $oLanguages->getLanguages();
+
+        $bResult = true;
+        foreach($aLanguages as $sName => $sTitle)
+        	$bResult &= $oLanguages->restoreLanguage($sName, $aConfig['module_uri']);
+
+        return $bResult ? BX_DOL_STUDIO_INSTALLER_SUCCESS : BX_DOL_STUDIO_INSTALLER_FAILED;
+    }
+
+    /**
+     * NOTE. The action is ONLY needed for dependent module to let 
+     * Notifications based module(s) know that he(they) should 
+     * update (request and save) handlers from this dependent module.
+     */
+	protected function actionUpdateRelations($sOperation)
+    {
+        if(!in_array($sOperation, array('install'))) 
+        	return BX_DOL_STUDIO_INSTALLER_FAILED;
+
+		if(empty($this->_aConfig['relations']) || !is_array($this->_aConfig['relations']))
+            return BX_DOL_STUDIO_INSTALLER_SUCCESS;
+
+		foreach($this->_aConfig['relations'] as $sModule) {
+			if(!$this->oDb->isModuleByName($sModule))
+				continue;
+
+			$aRelation = $this->oDb->getRelationsBy(array('type' => 'module', 'value' => $sModule));
+			if(empty($aRelation) || empty($aRelation['on_enable']) || empty($aRelation['on_disable']) || !BxDolRequest::serviceExists($aRelation['module'], $aRelation['on_enable']) || !BxDolRequest::serviceExists($aRelation['module'], $aRelation['on_disable']))
+				continue;
+
+			BxDolService::call($aRelation['module'], $aRelation['on_disable'], array($this->_aConfig['module_uri']));
+			BxDolService::call($aRelation['module'], $aRelation['on_enable'], array($this->_aConfig['module_uri']));
+		}
+
+        return BX_DOL_STUDIO_INSTALLER_SUCCESS;
+    }
+
+	/**
+     * NOTE. The action is ONLY needed for Notifications based modules 
+     * to update (request and save) handlers from all dependent modules.
+     */
+    protected function actionUpdateRelationsForAll($sOperation)
+    {
+    	if(!in_array($sOperation, array('install'))) 
+        	return BX_DOL_STUDIO_INSTALLER_FAILED;
+
+		$aRelation = $this->oDb->getRelationsBy(array('type' => 'module', 'value' => $this->_aModule['name']));
+		if(empty($aRelation) || empty($aRelation['on_enable']) || empty($aRelation['on_disable']) || !BxDolRequest::serviceExists($this->_aModule['name'], $aRelation['on_enable']) || !BxDolRequest::serviceExists($this->_aModule['name'], $aRelation['on_disable']))
+			return BX_DOL_STUDIO_INSTALLER_SUCCESS;
+
+    	$aModules = $this->oDb->getModulesBy(array('type' => 'all', 'active' => 1));
+	    foreach($aModules as $aModule) {
+	    	$aConfig = self::getModuleConfig($aModule);
+			if(empty($aConfig['relations']) || !is_array($aConfig['relations']) || !in_array($this->_aModule['name'], $aConfig['relations']))
+				continue;
+
+			BxDolService::call($this->_aModule['name'], $aRelation['on_disable'], array($aModule['uri']));
+			BxDolService::call($this->_aModule['name'], $aRelation['on_enable'], array($aModule['uri']));
+		}
+
+		return BX_DOL_STUDIO_INSTALLER_SUCCESS;
+    }
+
+    protected function _updateLanguage($bInstall, $sLanguage, $iCategory = 0, $sPath = '')
+    {
+        $oLanguages = BxDolStudioLanguagesUtils::getInstance();
+
+        $sPathAbsolute = $this->_sHomePath . 'install/langs/' . $sPath . $sLanguage . '.xml';
+        $aLanguageInfo = $oLanguages->readLanguage($sPathAbsolute, 'update');
+        if(empty($aLanguageInfo))
+            return false;
+
+        $iLanguage = $oLanguages->getLangId($sLanguage);
+
+        if(!empty($aLanguageInfo['category']))
+        	$iCategory = $oLanguages->getLanguageCategory($aLanguageInfo['category']);
+
+        //--- Process delete. Note. Deletion is performed for all languages. ---//
+        if(isset($aLanguageInfo['strings_del']))
+        	foreach($aLanguageInfo['strings_del'] as $sKey => $sValue)
+        		$oLanguages->deleteLanguageString($sKey, 0, false);
+
+        //--- Process add. Note. Key's category will be updated if it doesn't match. ---//
+        if(isset($aLanguageInfo['strings_add']))
+        	foreach($aLanguageInfo['strings_add'] as $sKey => $sValue)
+        		$oLanguages->addLanguageString($sKey, $sValue, $iLanguage, $iCategory, false);
+
+        //--- Process update. Note. Key's category will be updated if it doesn't match. ---//
+        if(isset($aLanguageInfo['strings_upd']))
+        	foreach($aLanguageInfo['strings_upd'] as $sKey => $sValue)
+        		$oLanguages->updateLanguageString($sKey, $sValue, $iLanguage, $iCategory, false);
+
+        return true;
+    }
+}
+
+/** @} */

+ 3 - 0
upgrade/files/9.0.0.RC7-9.0.0.RC8/script.php

@@ -0,0 +1,3 @@
+<?php
+
+    return true;

+ 6 - 0
upgrade/files/9.0.0.RC7-9.0.0.RC8/sql.sql

@@ -0,0 +1,6 @@
+
+
+-- Last step is to update current version
+
+UPDATE `sys_modules` SET `version` = '9.0.0-RC8' WHERE (`version` = '9.0.0.RC7' OR `version` = '9.0.0-RC7') AND `name` = 'system';
+

Alguns ficheiros não foram mostrados porque muitos ficheiros mudaram neste diff