Page Menu
Home
In-Portal Phabricator
Search
Configure Global Search
Log In
Files
F1174862
in-portal
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Subscribers
None
File Metadata
Details
File Info
Storage
Attached
Created
Fri, Oct 3, 1:20 AM
Size
19 KB
Mime Type
text/x-diff
Expires
Sun, Oct 5, 1:20 AM (1 d, 10 h)
Engine
blob
Format
Raw Data
Handle
761785
Attached To
rINP In-Portal
in-portal
View Options
Index: branches/5.0.x/core/units/helpers/language_import_helper.php
===================================================================
--- branches/5.0.x/core/units/helpers/language_import_helper.php (revision 13334)
+++ branches/5.0.x/core/units/helpers/language_import_helper.php (revision 13335)
@@ -1,613 +1,613 @@
<?php
/**
* @version $Id$
* @package In-Portal
* @copyright Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
* @license GNU/GPL
* In-Portal is Open Source software.
* This means that this software may have been modified pursuant
* the GNU General Public License, and as distributed it includes
* or is derivative of works licensed under the GNU General Public License
* or other free or open source software licenses.
* See http://www.in-portal.org/license for copyright notices and details.
*/
defined('FULL_PATH') or die('restricted access!');
define('LANG_OVERWRITE_EXISTING', 1);
define('LANG_SKIP_EXISTING', 2);
class LanguageImportHelper extends kHelper {
/**
* Current Language in import
*
* @var LanguagesItem
*/
var $lang_object = null;
/**
* Current user's IP address
*
* @var string
*/
var $ip_address = '';
/**
* Event type + name mapping to id (from system)
*
* @var Array
*/
var $events_hash = Array ();
/**
* Language pack import mode
*
* @var int
*/
var $import_mode = LANG_SKIP_EXISTING;
/**
* Language IDs, that were imported
*
* @var Array
*/
var $_languages = Array ();
/**
* Temporary table names to perform import on
*
* @var Array
*/
var $_tables = Array ();
/**
* Phrase types allowed for import/export operations
*
* @var Array
*/
var $phrase_types_allowed = Array ();
/**
* Encoding, used for language pack exporting
*
* @var string
*/
var $_exportEncoding = 'base64';
/**
* Debug language pack import process
*
* @var bool
*/
var $_debugMode = false;
function LanguageImportHelper()
{
parent::kHelper();
// "core/install/english.lang", phrase count: 3318, xml parse time on windows: 10s, insert time: 0.058s
set_time_limit(0);
ini_set('memory_limit', -1);
$this->lang_object =& $this->Application->recallObject('lang.import', null, Array ('skip_autoload' => true));
if (!(defined('IS_INSTALL') && IS_INSTALL)) {
// perform only, when not in installation mode
$this->_updateEventsCache();
}
$this->ip_address = getenv('HTTP_X_FORWARDED_FOR') ? getenv('HTTP_X_FORWARDED_FOR') : getenv('REMOTE_ADDR');
// $this->_debugMode = $this->Application->isDebugMode();
}
/**
* Performs import of given language pack (former Parse method)
*
* @param string $filename
* @param string $phrase_types
* @param Array $module_ids
* @param int $import_mode
* @return bool
*/
function performImport($filename, $phrase_types, $module_ids, $import_mode = LANG_SKIP_EXISTING)
{
// define the XML parsing routines/functions to call based on the handler path
if (!file_exists($filename) || !$phrase_types /*|| !$module_ids*/) {
return false;
}
if ($this->_debugMode) {
$start_time = getmicrotime();
$this->Application->Debugger->appendHTML(__CLASS__ . '::' . __FUNCTION__ . '("' . $filename . '")');
}
if (defined('IS_INSTALL') && IS_INSTALL) {
// new events could be added during module upgrade
$this->_updateEventsCache();
}
$this->_initImportTables();
$phrase_types = explode('|', substr($phrase_types, 1, -1) );
// $module_ids = explode('|', substr($module_ids, 1, -1) );
$this->phrase_types_allowed = array_flip($phrase_types);
$this->import_mode = $import_mode;
$this->_parseXML($filename);
// copy data from temp tables to live
foreach ($this->_languages as $language_id) {
$this->_performUpgrade($language_id, 'phrases', 'PhraseKey');
$this->_performUpgrade($language_id, 'emailmessages', 'EventId');
}
$this->_initImportTables(true);
if ($this->_debugMode) {
$this->Application->Debugger->appendHTML(__CLASS__ . '::' . __FUNCTION__ . '("' . $filename . '"): ' . (getmicrotime() - $start_time));
}
return true;
}
/**
* Creates XML file with exported language data (former Create method)
*
* @param string $filename filename to export into
* @param Array $phrase_types phrases types to export from modules passed in $module_ids
* @param Array $language_ids IDs of languages to export
* @param Array $module_ids IDs of modules to export phrases from
*/
function performExport($filename, $phrase_types, $language_ids, $module_ids)
{
$fp = fopen($filename,'w');
if (!$fp || !$phrase_types || !$module_ids || !$language_ids) {
return false;
}
$phrase_types = explode('|', substr($phrase_types, 1, -1) );
$module_ids = explode('|', substr($module_ids, 1, -1) );
$this->events_hash = array_flip($this->events_hash);
$lang_table = $this->Application->getUnitOption('lang','TableName');
$phrases_table = $this->Application->getUnitOption('phrases','TableName');
$emailevents_table = $this->Application->getUnitOption('emailmessages','TableName');
$mainevents_table = $this->Application->getUnitOption('emailevents','TableName');
$phrase_tpl = "\t\t\t".'<PHRASE Label="%s" Module="%s" Type="%s">%s</PHRASE>'."\n";
$event_tpl = "\t\t\t".'<EVENT MessageType="%s" Event="%s" Type="%s">%s</EVENT>'."\n";
- $sql = 'SELECT * FROM %s WHERE LanguageId = %s';
$ret = '<LANGUAGES>'."\n";
foreach ($language_ids as $language_id) {
// languages
+ $sql = 'SELECT * FROM %s WHERE LanguageId = %s';
$row = $this->Conn->GetRow( sprintf($sql, $lang_table, $language_id) );
$ret .= "\t".'<LANGUAGE PackName="'.$row['PackName'].'" Encoding="'.$this->_exportEncoding.'"><DATEFORMAT>'.$row['DateFormat'].'</DATEFORMAT>';
$ret .= '<TIMEFORMAT>'.$row['TimeFormat'].'</TIMEFORMAT><INPUTDATEFORMAT>'.$row['InputDateFormat'].'</INPUTDATEFORMAT>';
$ret .= '<INPUTTIMEFORMAT>'.$row['InputTimeFormat'].'</INPUTTIMEFORMAT><DECIMAL>'.$row['DecimalPoint'].'</DECIMAL>';
$ret .= '<THOUSANDS>'.$row['ThousandSep'].'</THOUSANDS><CHARSET>'.$row['Charset'].'</CHARSET><DOCS_URL>'.$row['UserDocsUrl'].'</DOCS_URL>';
$ret .= '<UNITSYSTEM>'.$row['UnitSystem'].'</UNITSYSTEM>'."\n";
// phrases
$phrases_sql = 'SELECT * FROM '.$phrases_table.' WHERE LanguageId = %s AND PhraseType IN (%s) AND Module IN (%s) ORDER BY Phrase';
if( in_array('In-Portal',$module_ids) ) array_push($module_ids, ''); // for old language packs
$rows = $this->Conn->Query( sprintf($phrases_sql,$language_id, implode(',',$phrase_types), '\''.implode('\',\'',$module_ids).'\'' ) );
if($rows)
{
$ret .= "\t\t".'<PHRASES>'."\n";
foreach($rows as $row)
{
$data = $this->_exportEncoding == 'base64' ? base64_encode($row['Translation']) : '<![CDATA['.$row['Translation'].']]>';
$ret .= sprintf($phrase_tpl, $row['Phrase'], $row['Module'], $row['PhraseType'], $data );
}
$ret .= "\t\t".'</PHRASES>'."\n";
}
// email events
if ( in_array('In-Portal',$module_ids) ) {
unset( $module_ids[array_search('',$module_ids)] ); // for old language packs
}
$module_sql = preg_replace('/(.*),/U', 'INSTR(Module,\'\\1\') OR ', implode(',', $module_ids).',');
$module_sql = substr($module_sql, 0, -4);
$sql = 'SELECT EventId FROM '.$mainevents_table.' WHERE '.$module_sql;
$event_ids = $this->Conn->GetCol($sql);
if($event_ids)
{
$ret .= "\t\t".'<EVENTS>'."\n";
$event_sql = ' SELECT em.*
FROM '.$emailevents_table.' em
LEFT JOIN '.$mainevents_table.' e ON e.EventId = em.EventId
WHERE em.LanguageId = %s AND em.EventId IN (%s)
ORDER BY e.Event, e.Type';
$rows = $this->Conn->Query( sprintf($event_sql,$language_id, $event_ids ? implode(',',$event_ids) : '' ) );
foreach($rows as $row)
{
if (!array_key_exists($row['EventId'], $this->events_hash)) {
// don't export existing translations of missing events
continue;
}
list($event_name, $event_type) = explode('_', $this->events_hash[ $row['EventId'] ] );
$data = $this->_exportEncoding == 'base64' ? base64_encode($row['Template']) : '<![CDATA['.$row['Template'].']]>';
$ret .= sprintf($event_tpl, $row['MessageType'], $event_name, $event_type, $data );
}
$ret .= "\t\t".'</EVENTS>'."\n";
}
$ret .= "\t".'</LANGUAGE>'."\n";
}
$ret .= '</LANGUAGES>';
fwrite($fp, $ret);
fclose($fp);
return true;
}
/**
* Sets language pack encoding (not charset) used during export
*
* @param string $encoding
*/
function setExportEncoding($encoding)
{
$this->_exportEncoding = $encoding;
}
/**
* Performs upgrade of given language pack part
*
* @param int $language_id
* @param string $prefix
* @param string $unique_field
*/
function _performUpgrade($language_id, $prefix, $unique_field)
{
// TODO: find a way to compare (intersect,diff) phrases in non-case sensitive way, but keeping original case in result
$live_records = $this->_getTableData($language_id, $prefix, $unique_field, false);
$temp_records = $this->_getTableData($language_id, $prefix, $unique_field, true);
if ($this->import_mode == LANG_OVERWRITE_EXISTING) {
// remove existing records before copy
$common_records = array_intersect($temp_records, $live_records);
if ($common_records) {
$live_records = array_diff($live_records, $common_records); // remove overlaping records
$common_records = array_map(Array(&$this->Conn, 'qstr'), $common_records);
$sql = 'DELETE FROM ' . $this->Application->getUnitOption($prefix, 'TableName') . '
WHERE (LanguageId = ' . $language_id . ') AND (' . $unique_field . ' IN (' . implode(',', $common_records) . '))';
$this->Conn->Query($sql);
}
}
$temp_records = array_diff($temp_records, $live_records);
if (!$temp_records) {
// no new records found in temp table while comparing it to live table
return ;
}
$temp_records = array_map(Array(&$this->Conn, 'qstr'), $temp_records);
$sql = 'INSERT INTO ' . $this->Application->getUnitOption($prefix, 'TableName') . '
SELECT *
FROM ' . $this->_tables[$prefix] . '
WHERE (LanguageId = ' . $language_id . ')';
if ($live_records) {
// subsctract live records from temp table during coping
$sql .= ' AND (' . $unique_field . ' IN (' . implode(',', $temp_records) . '))';
}
$this->Conn->Query($sql);
}
/**
* Returns data from given table used for language pack upgrade
*
* @param int $language_id
* @param string $prefix
* @param string $unique_field
* @param bool $temp_mode
* @return Array
*/
function _getTableData($language_id, $prefix, $unique_field, $temp_mode = false)
{
$table_name = $this->Application->getUnitOption($prefix, 'TableName');
if ($temp_mode) {
$table_name = $this->Application->GetTempName($table_name, 'prefix:' . $prefix);
}
$sql = 'SELECT ' . $unique_field . '
FROM ' . $table_name . '
WHERE LanguageId = ' . $language_id;
return $this->Conn->GetCol($sql);
}
function _parseXML($filename)
{
if ($this->_debugMode) {
$start_time = getmicrotime();
$this->Application->Debugger->appendHTML(__CLASS__ . '::' . __FUNCTION__ . '("' . $filename . '")');
}
$fdata = file_get_contents($filename);
$xml_parser =& $this->Application->recallObject('kXMLHelper');
/* @var $xml_parser kXMLHelper */
$root_node =& $xml_parser->Parse($fdata);
if (!is_object($root_node) || !is_a($root_node, 'kXMLNode')) {
// invalid language pack contents
return false;
}
if ($root_node->Children) {
$this->_processLanguages($root_node->firstChild);
}
if ($this->_debugMode) {
$this->Application->Debugger->appendHTML(__CLASS__ . '::' . __FUNCTION__ . '("' . $filename . '"): ' . (getmicrotime() - $start_time));
}
return true;
}
/**
* Creates temporary tables, used during language import
*
* @param bool $drop_only
*/
function _initImportTables($drop_only = false)
{
$this->_tables['phrases'] = $this->_prepareTempTable('phrases', $drop_only);
$this->_tables['emailmessages'] = $this->_prepareTempTable('emailmessages', $drop_only);
}
/**
* Create temp table for prefix, if table already exists, then delete it and create again
*
* @param string $prefix
*/
function _prepareTempTable($prefix, $drop_only = false)
{
$idfield = $this->Application->getUnitOption($prefix, 'IDField');
$table = $this->Application->getUnitOption($prefix,'TableName');
$temp_table = $this->Application->GetTempName($table);
$sql = 'DROP TABLE IF EXISTS %s';
$this->Conn->Query( sprintf($sql, $temp_table) );
if (!$drop_only) {
$sql = 'CREATE TABLE %s SELECT * FROM %s WHERE 0';
$this->Conn->Query( sprintf($sql, $temp_table, $table) );
$sql = 'ALTER TABLE %1$s CHANGE %2$s %2$s INT(11) NOT NULL DEFAULT "0"';
$this->Conn->Query( sprintf($sql, $temp_table, $idfield) );
}
return $temp_table;
}
/**
* Prepares mapping between event name+type and their ids in database
*
*/
function _updateEventsCache()
{
$sql = 'SELECT EventId, CONCAT(Event,"_",Type) AS EventMix
FROM ' . TABLE_PREFIX . 'Events';
$this->events_hash = $this->Conn->GetCol($sql, 'EventMix');
}
/**
* Processes parsed XML
*
* @param kXMLNode $language_node
*/
function _processLanguages(&$language_node)
{
$field_mapping = Array (
'DATEFORMAT' => 'DateFormat',
'TIMEFORMAT' => 'TimeFormat',
'INPUTDATEFORMAT' => 'InputDateFormat',
'INPUTTIMEFORMAT' => 'InputTimeFormat',
'DECIMAL' => 'DecimalPoint',
'THOUSANDS' => 'ThousandSep',
'CHARSET' => 'Charset',
'UNITSYSTEM' => 'UnitSystem',
'DOCS_URL' => 'UserDocsUrl',
);
do {
$language_id = false;
$fields_hash = Array (
'PackName' => $language_node->Attributes['PACKNAME'],
'LocalName' => $language_node->Attributes['PACKNAME'],
'Encoding' => $language_node->Attributes['ENCODING'],
'Charset' => 'iso-8859-1',
);
$sub_node =& $language_node->firstChild;
/* @var $sub_node kXMLNode */
do {
switch ($sub_node->Name) {
case 'PHRASES':
if ($sub_node->Children) {
if (!$language_id) {
$language_id = $this->_processLanguage($fields_hash);
}
if ($this->_debugMode) {
$start_time = getmicrotime();
}
$this->_processPhrases($sub_node->firstChild, $language_id, $fields_hash['Encoding']);
if ($this->_debugMode) {
$this->Application->Debugger->appendHTML(__CLASS__ . '::' . '_processPhrases: ' . (getmicrotime() - $start_time));
}
}
break;
case 'EVENTS':
if ($sub_node->Children) {
if (!$language_id) {
$language_id = $this->_processLanguage($fields_hash);
}
$this->_processEvents($sub_node->firstChild, $language_id, $fields_hash['Encoding']);
}
break;
default:
$fields_hash[ $field_mapping[$sub_node->Name] ] = $sub_node->Data;
break;
}
} while (($sub_node =& $sub_node->NextSibling()));
} while (($language_node =& $language_node->NextSibling()));
}
/**
* Performs phases import
*
* @param kXMLNode $phrase_node
* @param int $language_id
* @param string $language_encoding
*/
function _processPhrases(&$phrase_node, $language_id, $language_encoding)
{
do {
$fields_hash = Array (
'LanguageId' => $language_id,
'Phrase' => $phrase_node->Attributes['LABEL'],
'PhraseKey' => mb_strtoupper($phrase_node->Attributes['LABEL']),
'PhraseType' => $phrase_node->Attributes['TYPE'],
'Module' => array_key_exists('MODULE', $phrase_node->Attributes) ? $phrase_node->Attributes['MODULE'] : 'Core',
'LastChanged' => adodb_mktime(),
'LastChangeIP' => $this->ip_address,
'Translation' => $phrase_node->Data,
);
if (array_key_exists($fields_hash['PhraseType'], $this->phrase_types_allowed)) {
if ($language_encoding != 'plain') {
$fields_hash['Translation'] = base64_decode($fields_hash['Translation']);
}
$this->Conn->doInsert($fields_hash, $this->_tables['phrases'], 'INSERT', false);
}
} while (($phrase_node =& $phrase_node->NextSibling()));
$this->Conn->doInsert($fields_hash, $this->_tables['phrases'], 'INSERT');
}
/**
* Performs email event import
*
* @param kXMLNode $event_node
* @param int $language_id
* @param string $language_encoding
*/
function _processEvents(&$event_node, $language_id, $language_encoding)
{
$email_message_helper =& $this->Application->recallObject('EmailMessageHelper');
/* @var $email_message_helper EmailMessageHelper */
do {
$event_id = $this->_getEventId($event_node->Attributes['EVENT'], $event_node->Attributes['TYPE']);
if ($event_id) {
$fields_hash = Array (
'LanguageId' => $language_id,
'EventId' => $event_id,
'MessageType' => $event_node->Attributes['MESSAGETYPE'],
);
if ($language_encoding == 'plain') {
$fields_hash['Template'] = rtrim($event_node->Data);
}
else {
$fields_hash['Template'] = base64_decode($event_node->Data);
}
$parsed = $email_message_helper->parseTemplate($fields_hash['Template']);
$fields_hash['Subject'] = $parsed['Subject'];
$this->Conn->doInsert($fields_hash, $this->_tables['emailmessages'], 'INSERT', false);
}
} while (($event_node =& $event_node->NextSibling()));
if ($fields_hash) {
// at least one corresponding event declaration found by email event name+type given in translation
$this->Conn->doInsert($fields_hash, $this->_tables['emailmessages'], 'INSERT');
}
}
/**
* Creates/updates language based on given fields and returns it's id
*
* @param Array $fields_hash
* @return int
*/
function _processLanguage($fields_hash)
{
// 1. get language from database
$sql = 'SELECT ' . $this->lang_object->IDField . '
FROM ' . $this->lang_object->TableName . '
WHERE PackName = ' . $this->Conn->qstr($fields_hash['PackName']);
$language_id = $this->Conn->GetOne($sql);
if ($language_id) {
// 2. language found -> update, when allowed
$this->lang_object->Load($language_id);
if ($this->import_mode == LANG_OVERWRITE_EXISTING) {
// update live language record based on data from xml
$this->lang_object->SetFieldsFromHash($fields_hash);
$this->lang_object->Update();
}
}
else {
// 3. language not found -> create
$this->lang_object->SetFieldsFromHash($fields_hash);
$this->lang_object->SetDBField('Enabled', STATUS_ACTIVE);
if ($this->lang_object->Create()) {
$language_id = $this->lang_object->GetID();
if (defined('IS_INSTALL') && IS_INSTALL) {
// language created during install becomes admin interface language
$this->lang_object->setPrimary(true, true);
}
}
}
// 4. collect ID of every processed language
if (!in_array($language_id, $this->_languages)) {
$this->_languages[] = $language_id;
}
return $language_id;
}
/**
* Returns event id based on it's name and type
*
* @param string $event_name
* @param string $event_type
* @return int
*/
function _getEventId($event_name, $event_type)
{
$cache_key = $event_name . '_' . $event_type;
return array_key_exists($cache_key, $this->events_hash) ? $this->events_hash[$cache_key] : 0;
}
}
\ No newline at end of file
Event Timeline
Log In to Comment