Page Menu
Home
In-Portal Phabricator
Search
Configure Global Search
Log In
Files
F1031296
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
Tue, Jun 17, 4:20 AM
Size
104 KB
Mime Type
text/x-diff
Expires
Thu, Jun 19, 4:20 AM (1 h, 4 m)
Engine
blob
Format
Raw Data
Handle
666063
Attached To
rINP In-Portal
in-portal
View Options
Index: branches/5.2.x/core/units/helpers/language_import_helper.php
===================================================================
--- branches/5.2.x/core/units/helpers/language_import_helper.php (revision 15157)
+++ branches/5.2.x/core/units/helpers/language_import_helper.php (revision 15158)
@@ -1,1164 +1,1148 @@
<?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.
*/
/**
* Language pack format version description
*
* v1
* ==========
* All language properties are separate nodes inside <LANGUAGE> node. There are
* two more nodes PHRASES and EVENTS for phrase and email event translations.
*
* v2
* ==========
* All data, that will end up in Language table is now attributes of LANGUAGE node
* and is name exactly as field name, that will be used to store that data.
*
* v4
* ==========
* Hint & Column translation added to each phrase translation
*/
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';
/**
* Exported data limits (all or only specified ones)
*
* @var Array
*/
var $_exportLimits = Array (
'phrases' => false,
'emailevents' => false,
);
/**
* Debug language pack import process
*
* @var bool
*/
var $_debugMode = false;
/**
* Latest version of language pack format. Versions are not backwards compatible!
*
* @var int
*/
var $_latestVersion = 4;
/**
* Prefix-based serial numbers, that should be changed after import is finished
*
* @var Array
*/
var $changedPrefixes = Array ();
public function __construct()
{
parent::__construct();
// "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 = microtime(true);
$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', Array ('l%s_Translation', 'l%s_HintTranslation', 'l%s_ColumnTranslation', 'PhraseType'));
$this->_performUpgrade($language_id, 'emailevents', 'EventId', Array ('l%s_Subject', 'Headers', 'MessageType', 'l%s_Body'));
$this->_performUpgrade($language_id, 'country-state', 'CountryStateId', Array ('l%s_Name'));
}
$this->_initImportTables(true);
$this->changedPrefixes = array_unique($this->changedPrefixes);
foreach ($this->changedPrefixes as $prefix) {
$this->Application->incrementCacheSerial($prefix);
}
if ($this->_debugMode) {
$this->Application->Debugger->appendHTML(__CLASS__ . '::' . __FUNCTION__ . '("' . $filename . '"): ' . (microtime(true) - $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) );
$ret = '<LANGUAGES Version="' . $this->_latestVersion . '">' . "\n";
$export_fields = $this->_getExportFields();
$email_message_helper = $this->Application->recallObject('EmailMessageHelper');
/* @var $email_message_helper EmailMessageHelper */
// get languages
$sql = 'SELECT *
FROM ' . $this->Application->getUnitOption('lang','TableName') . '
WHERE LanguageId IN (' . implode(',', $language_ids) . ')';
$languages = $this->Conn->Query($sql, 'LanguageId');
// get phrases
$phrase_modules = $module_ids;
array_push($phrase_modules, ''); // for old language packs without module
$phrase_modules = $this->Conn->qstrArray($phrase_modules);
// apply phrase selection limit
if ($this->_exportLimits['phrases']) {
$escaped_phrases = $this->Conn->qstrArray($this->_exportLimits['phrases']);
$limit_where = 'Phrase IN (' . implode(',', $escaped_phrases) . ')';
}
else {
$limit_where = 'TRUE';
}
$sql = 'SELECT *
FROM ' . $this->Application->getUnitOption('phrases','TableName') . '
WHERE PhraseType IN (' . implode(',', $phrase_types) . ') AND Module IN (' . implode(',', $phrase_modules) . ') AND ' . $limit_where . '
ORDER BY Phrase';
$phrases = $this->Conn->Query($sql, 'PhraseId');
// email events
$module_sql = preg_replace('/(.*),/U', 'INSTR(Module,\'\\1\') OR ', implode(',', $module_ids) . ',');
// apply event selection limit
if ($this->_exportLimits['emailevents']) {
$escaped_email_events = $this->Conn->qstrArray($this->_exportLimits['emailevents']);
$limit_where = '`Event` IN (' . implode(',', $escaped_email_events) . ')';
}
else {
$limit_where = 'TRUE';
}
$sql = 'SELECT *
FROM ' . $this->Application->getUnitOption('emailevents', 'TableName') . '
WHERE `Type` IN (' . implode(',', $phrase_types) . ') AND (' . substr($module_sql, 0, -4) . ') AND ' . $limit_where . '
ORDER BY `Event`, `Type`';
$events = $this->Conn->Query($sql, 'EventId');
if (in_array('Core', $module_ids)) {
// countries
$sql = 'SELECT *
FROM ' . $this->Application->getUnitOption('country-state', 'TableName') . '
WHERE Type = ' . DESTINATION_TYPE_COUNTRY . '
ORDER BY `IsoCode`';
$countries = $this->Conn->Query($sql, 'CountryStateId');
// states
$sql = 'SELECT *
FROM ' . $this->Application->getUnitOption('country-state', 'TableName') . '
WHERE Type = ' . DESTINATION_TYPE_STATE . '
ORDER BY `IsoCode`';
$states = $this->Conn->Query($sql, 'CountryStateId');
foreach ($states as $state_id => $state_data) {
$country_id = $state_data['StateCountryId'];
if (!array_key_exists('States', $countries[$country_id])) {
$countries[$country_id]['States'] = Array ();
}
$countries[$country_id]['States'][] = $state_id;
}
}
foreach ($languages as $language_id => $language_info) {
// language
$ret .= "\t" . '<LANGUAGE Encoding="' . $this->_exportEncoding . '"';
foreach ($export_fields as $export_field) {
$ret .= ' ' . $export_field . '="' . htmlspecialchars($language_info[$export_field]) . '"';
}
$ret .= '>' . "\n";
// filename replacements
$replacements = $language_info['FilenameReplacements'];
if ($replacements) {
$ret .= "\t\t" . '<REPLACEMENTS>';
$ret .= $this->_exportEncoding == 'base64' ? base64_encode($replacements) : '<![CDATA[' . $replacements . ']]>';
$ret .= '</REPLACEMENTS>' . "\n";
}
// phrases
if ($phrases) {
$ret .= "\t\t" . '<PHRASES>' . "\n";
foreach ($phrases as $phrase_id => $phrase) {
$translation = $phrase['l' . $language_id . '_Translation'];
$hint_translation = $phrase['l' . $language_id . '_HintTranslation'];
$column_translation = $phrase['l' . $language_id . '_ColumnTranslation'];
if (!$translation) {
// phrase is not translated on given language
continue;
}
if ( $this->_exportEncoding == 'base64' ) {
$data = base64_encode($translation);
$hint_translation = base64_encode($hint_translation);
$column_translation = base64_encode($column_translation);
}
else {
$data = '<![CDATA[' . $translation . ']]>';
$hint_translation = htmlspecialchars($hint_translation);
$column_translation = htmlspecialchars($column_translation);
}
$attributes = Array (
'Label="' . $phrase['Phrase'] . '"',
'Module="' . $phrase['Module'] . '"',
'Type="' . $phrase['PhraseType'] . '"'
);
if ( $phrase['l' . $language_id . '_HintTranslation'] ) {
$attributes[] = 'Hint="' . $hint_translation . '"';
}
if ( $phrase['l' . $language_id . '_ColumnTranslation'] ) {
$attributes[] = 'Column="' . $column_translation . '"';
}
$ret .= "\t\t\t" . '<PHRASE ' . implode(' ', $attributes) . '>' . $data . '</PHRASE>' . "\n";
}
$ret .= "\t\t" . '</PHRASES>' . "\n";
}
// email events
if ($events) {
$ret .= "\t\t" . '<EVENTS>' . "\n";
foreach ($events as $event_id => $event) {
$fields_hash = Array (
'Headers' => $event['Headers'],
'Subject' => $event['l' . $language_id . '_Subject'],
'Body' => $event['l' . $language_id . '_Body'],
);
$template = $email_message_helper->buildTemplate($fields_hash);
if (!$template) {
// email event is not translated on given language
continue;
}
$data = $this->_exportEncoding == 'base64' ? base64_encode($template) : '<![CDATA[' . $template . ']]>';
$ret .= "\t\t\t" . '<EVENT MessageType="' . $event['MessageType'] . '" Event="' . $event['Event'] . '" Type="' . $event['Type'] . '">' . $data . '</EVENT>'."\n";
}
$ret .= "\t\t" . '</EVENTS>' . "\n";
}
if (in_array('Core', $module_ids) && $countries) {
$ret .= "\t\t" . '<COUNTRIES>' . "\n";
foreach ($countries as $country_id => $country_data) {
$translation = $country_data['l' . $language_id . '_Name'];
if (!$translation) {
// country is not translated on given language
continue;
}
$data = $this->_exportEncoding == 'base64' ? base64_encode($translation) : $translation;
if (array_key_exists('States', $country_data)) {
$ret .= "\t\t\t" . '<COUNTRY Iso="' . $country_data['IsoCode'] . '" Translation="' . $data . '">' . "\n";
foreach ($country_data['States'] as $state_id) {
$translation = $states[$state_id]['l' . $language_id . '_Name'];
if (!$translation) {
// state is not translated on given language
continue;
}
$data = $this->_exportEncoding == 'base64' ? base64_encode($translation) : $translation;
$ret .= "\t\t\t\t" . '<STATE Iso="' . $states[$state_id]['IsoCode'] . '" Translation="' . $data . '"/>' . "\n";
}
$ret .= "\t\t\t" . '</COUNTRY>' . "\n";
}
else {
$ret .= "\t\t\t" . '<COUNTRY Iso="' . $country_data['IsoCode'] . '" Translation="' . $data . '"/>' . "\n";
}
}
$ret .= "\t\t" . '</COUNTRIES>' . "\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;
}
/**
* Sets language pack data limit for export
*
* @param string $prefix
* @param string $data
*/
function setExportLimit($prefix, $data = null)
{
if ( !isset($data) ) {
$key_field = $prefix == 'phrases' ? 'Phrase' : 'Event';
$ids = $this->getExportIDs($prefix);
$sql = 'SELECT ' . $key_field . '
FROM ' . $this->Application->getUnitOption($prefix, 'TableName') . '
WHERE ' . $this->Application->getUnitOption($prefix, 'IDField') . ' IN (' . $ids . ')';
$rs = $this->Conn->QueryRaw($sql);
if ( $this->Conn->RowCount($rs) ) {
$data = '';
while ( ($row = $this->Conn->GetNextRow($rs)) ) {
$data .= ',' . $row[$key_field];
}
$data = substr($data, 1);
}
$this->Conn->Destroy($rs);
}
if ( !is_array($data) ) {
$data = str_replace(',', "\n", $data);
$data = preg_replace("/\n+/", "\n", str_replace("\r", '', trim($data)));
$data = $data ? array_map('trim', explode("\n", $data)) : Array ();
}
$this->_exportLimits[$prefix] = $data;
}
/**
* Performs upgrade of given language pack part
*
* @param int $language_id
* @param string $prefix
* @param string $unique_field
* @param Array $data_fields
*/
function _performUpgrade($language_id, $prefix, $unique_field, $data_fields)
{
$live_records = $this->_getTableData($language_id, $prefix, $unique_field, $data_fields[0], false);
$temp_records = $this->_getTableData($language_id, $prefix, $unique_field, $data_fields[0], true);
if (!$temp_records) {
// no data for given language
return ;
}
// perform insert for records, that are missing in live table
$to_insert = array_diff($temp_records, $live_records);
if ($to_insert) {
$to_insert = $this->Conn->qstrArray($to_insert);
$sql = 'INSERT INTO ' . $this->Application->getUnitOption($prefix, 'TableName') . '
SELECT *
FROM ' . $this->_tables[$prefix] . '
WHERE ' . $unique_field . ' IN (' . implode(',', $to_insert) . ')';
$this->Conn->Query($sql);
// new records were added
$this->changedPrefixes[] = $prefix;
}
// perform update for records, that are present in live table
$to_update = array_diff($temp_records, $to_insert);
if ($to_update) {
$to_update = $this->Conn->qstrArray($to_update);
$sql = 'UPDATE ' . $this->Application->getUnitOption($prefix, 'TableName') . ' live
SET ';
foreach ($data_fields as $index => $data_field) {
$data_field = sprintf($data_field, $language_id);
$sql .= ' live.' . $data_field . ' = (
SELECT temp' . $index . '.' . $data_field . '
FROM ' . $this->_tables[$prefix] . ' temp' . $index . '
WHERE temp' . $index . '.' . $unique_field . ' = live.' . $unique_field . '
),';
}
$sql = substr($sql, 0, -1); // cut last comma
$where_clause = Array (
// this won't make any difference, but just in case
$unique_field . ' IN (' . implode(',', $to_update) . ')',
);
if ($this->import_mode == LANG_SKIP_EXISTING) {
// empty OR not set
$data_field = sprintf($data_fields[0], $language_id);
$where_clause[] = '(' . $data_field . ' = "") OR (' . $data_field . ' IS NULL)';
}
if ($where_clause) {
$sql .= "\n" . 'WHERE (' . implode(') AND (', $where_clause) . ')';
}
$this->Conn->Query($sql);
if ($this->Conn->getAffectedRows() > 0) {
// existing records were updated
$this->changedPrefixes[] = $prefix;
}
}
}
/**
* Returns data from given table used for language pack upgrade
*
* @param int $language_id
* @param string $prefix
* @param string $unique_field
* @param string $data_field
* @param bool $temp_mode
* @return Array
*/
function _getTableData($language_id, $prefix, $unique_field, $data_field, $temp_mode = false)
{
$data_field = sprintf($data_field, $language_id);
$table_name = $this->Application->getUnitOption($prefix, 'TableName');
if ($temp_mode) {
// for temp table get only records, that have contents on given language (not empty and isset)
$sql = 'SELECT ' . $unique_field . '
FROM ' . $this->Application->GetTempName($table_name, 'prefix:' . $prefix) . '
WHERE (' . $data_field . ' <> "") AND (' . $data_field . ' IS NOT NULL)';
}
else {
// for live table get all records, no matter on what language
$sql = 'SELECT ' . $unique_field . '
FROM ' . $table_name;
}
return $this->Conn->GetCol($sql);
}
function _parseXML($filename)
{
- if ($this->_debugMode) {
+ if ( $this->_debugMode ) {
$start_time = microtime(true);
$this->Application->Debugger->appendHTML(__CLASS__ . '::' . __FUNCTION__ . '("' . $filename . '")');
}
- $fdata = file_get_contents($filename);
-
- $xml_parser = $this->Application->recallObject('kXMLHelper');
- /* @var $xml_parser kXMLHelper */
+ $languages = simplexml_load_file($filename);
- $root_node =& $xml_parser->Parse($fdata);
- if (!is_object($root_node) || !is_a($root_node, 'kXMLNode')) {
+ if ( $languages === false) {
// invalid language pack contents
return false;
}
- if ($root_node->Children) {
- $this->_processLanguages($root_node->firstChild);
+ if ( $languages->count() ) {
+ $this->_processLanguages($languages);
}
- if ($this->_debugMode) {
+ if ( $this->_debugMode ) {
$this->Application->Debugger->appendHTML(__CLASS__ . '::' . __FUNCTION__ . '("' . $filename . '"): ' . (microtime(true) - $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['emailevents'] = $this->_prepareTempTable('emailevents', $drop_only);
$this->_tables['country-state'] = $this->_prepareTempTable('country-state', $drop_only);
}
/**
* Create temp table for prefix, if table already exists, then delete it and create again
*
* @param string $prefix
* @param bool $drop_only
* @return string Name of created temp table
* @access protected
*/
protected function _prepareTempTable($prefix, $drop_only = false)
{
$id_field = $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 ' . $temp_table . ' SELECT * FROM ' . $table . ' WHERE 0';
$this->Conn->Query($sql);
$sql = 'ALTER TABLE %1$s CHANGE %2$s %2$s INT(11) NOT NULL DEFAULT "0"';
$this->Conn->Query( sprintf($sql, $temp_table, $id_field) );
switch ($prefix) {
case 'phrases':
$unique_field = 'PhraseKey';
break;
case 'emailevents':
$unique_field = 'EventId';
break;
case 'country-state':
$unique_field = 'CountryStateId';
break;
default:
throw new Exception('Unknown prefix "<strong>' . $prefix . '</strong>" during language pack import');
break;
}
$sql = 'ALTER TABLE ' . $temp_table . ' ADD UNIQUE (' . $unique_field . ')';
$this->Conn->Query($sql);
}
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 . 'EmailEvents';
$this->events_hash = $this->Conn->GetCol($sql, 'EventMix');
}
/**
* Returns language fields to be exported
*
* @return Array
*/
function _getExportFields()
{
return Array (
'PackName', 'LocalName', 'DateFormat', 'TimeFormat', 'InputDateFormat', 'InputTimeFormat',
'DecimalPoint', 'ThousandSep', 'Charset', 'UnitSystem', 'Locale', 'UserDocsUrl'
);
}
/**
* Processes parsed XML
*
- * @param kXMLNode $language_node
+ * @param SimpleXMLElement $languages
*/
- function _processLanguages(&$language_node)
+ function _processLanguages($languages)
{
- if (array_key_exists('VERSION', $language_node->Parent->Attributes)) {
- // version present -> use it
- $version = $language_node->Parent->Attributes['VERSION'];
- }
- else {
+ $version = (int)$languages['Version'];
+
+ if ( !$version ) {
// version missing -> guess it
- if (is_object($language_node->FindChild('DATEFORMAT'))) {
+ if ( $languages->DATEFORMAT->getName() ) {
$version = 1;
}
- elseif (array_key_exists('CHARSET', $language_node->Attributes)) {
+ elseif ( (string)$languages->LANGUAGE['Charset'] != '' ) {
$version = 2;
}
}
- if ($version == 1) {
+ if ( $version == 1 ) {
$field_mapping = Array (
'DATEFORMAT' => 'DateFormat',
'TIMEFORMAT' => 'TimeFormat',
'INPUTDATEFORMAT' => 'InputDateFormat',
'INPUTTIMEFORMAT' => 'InputTimeFormat',
'DECIMAL' => 'DecimalPoint',
'THOUSANDS' => 'ThousandSep',
'CHARSET' => 'Charset',
'UNITSYSTEM' => 'UnitSystem',
'DOCS_URL' => 'UserDocsUrl',
);
}
else {
$export_fields = $this->_getExportFields();
}
- do {
+ foreach ($languages as $language_node) {
$language_id = false;
$fields_hash = Array (
- 'PackName' => $language_node->Attributes['PACKNAME'],
- 'LocalName' => $language_node->Attributes['PACKNAME'],
- 'Encoding' => $language_node->Attributes['ENCODING'],
+ 'PackName' => (string)$language_node['PackName'],
+ 'LocalName' => (string)$language_node['PackName'],
+ 'Encoding' => (string)$language_node['Encoding'],
'Charset' => 'utf-8',
'SynchronizationModes' => Language::SYNCHRONIZE_DEFAULT,
);
- if ($version > 1) {
+ if ( $version > 1 ) {
foreach ($export_fields as $export_field) {
- $attribute_name = strtoupper($export_field);
-
- if (array_key_exists($attribute_name, $language_node->Attributes)) {
- $fields_hash[$export_field] = $language_node->Attributes[$attribute_name];
+ if ( (string)$language_node[$export_field] ) {
+ $fields_hash[$export_field] = (string)$language_node[$export_field];
}
}
}
- $sub_node =& $language_node->firstChild;
- /* @var $sub_node kXMLNode */
+ $container_nodes = Array ('PHRASES', 'EVENTS', 'COUNTRIES');
- do {
- switch ($sub_node->Name) {
- case 'PHRASES':
- if ($sub_node->Children) {
- if (!$language_id) {
- $language_id = $this->_processLanguage($fields_hash);
- }
+ foreach ($language_node as $sub_node) {
+ /* @var $sub_node SimpleXMLElement */
- if ($this->_debugMode) {
- $start_time = microtime(true);
- }
+ if ( in_array($sub_node->getName(), $container_nodes) ) {
+ if ( !$sub_node->count() ) {
+ continue;
+ }
- $this->_processPhrases($sub_node->firstChild, $language_id, $fields_hash['Encoding']);
+ if ( !$language_id ) {
+ $language_id = $this->_processLanguage($fields_hash);
+ }
+ }
- if ($this->_debugMode) {
- $this->Application->Debugger->appendHTML(__CLASS__ . '::' . '_processPhrases: ' . (microtime(true) - $start_time));
- }
- }
+ switch ($sub_node->getName()) {
+ case 'PHRASES':
+ $this->_processPhrases($sub_node, $language_id, $fields_hash['Encoding']);
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']);
- }
+ $this->_processEvents($sub_node, $language_id, $fields_hash['Encoding']);
break;
case 'COUNTRIES':
- if ($sub_node->Children) {
- if (!$language_id) {
- $language_id = $this->_processLanguage($fields_hash);
- }
-
- $this->_processCountries($sub_node->firstChild, $language_id, $fields_hash['Encoding']);
- }
+ $this->_processCountries($sub_node, $language_id, $fields_hash['Encoding']);
break;
case 'REPLACEMENTS':
// added since v2
- $replacements = $sub_node->Data;
+ $replacements = (string)$sub_node;
- if ($fields_hash['Encoding'] != 'plain') {
+ if ( $fields_hash['Encoding'] != 'plain' ) {
$replacements = base64_decode($replacements);
}
$fields_hash['FilenameReplacements'] = $replacements;
break;
default:
- if ($version == 1) {
- $fields_hash[ $field_mapping[$sub_node->Name] ] = $sub_node->Data;
+ if ( $version == 1 ) {
+ $fields_hash[$field_mapping[$sub_node->Name]] = (string)$sub_node;
}
break;
}
- } while (($sub_node =& $sub_node->NextSibling()));
- } while (($language_node =& $language_node->NextSibling()));
+ }
+ }
}
/**
* Performs phases import
*
- * @param kXMLNode $phrase_node
+ * @param SimpleXMLElement $phrases
* @param int $language_id
* @param string $language_encoding
*/
- function _processPhrases(&$phrase_node, $language_id, $language_encoding)
+ function _processPhrases($phrases, $language_id, $language_encoding)
{
static $other_translations = Array ();
- if ($this->Application->isDebugMode()) {
+ if ( $this->Application->isDebugMode() ) {
$this->Application->Debugger->profileStart('L[' . $language_id . ']P', 'Language: ' . $language_id . '; Phrases Import');
}
- do {
- $phrase_key = mb_strtoupper($phrase_node->Attributes['LABEL']);
+ foreach ($phrases as $phrase_node) {
+ /* @var $phrase_node SimpleXMLElement */
+
+ $phrase_key = mb_strtoupper($phrase_node['Label']);
$fields_hash = Array (
- 'Phrase' => $phrase_node->Attributes['LABEL'],
+ 'Phrase' => (string)$phrase_node['Label'],
'PhraseKey' => $phrase_key,
- 'PhraseType' => $phrase_node->Attributes['TYPE'],
- 'Module' => array_key_exists('MODULE', $phrase_node->Attributes) ? $phrase_node->Attributes['MODULE'] : 'Core',
- 'LastChanged' => adodb_mktime(),
+ 'PhraseType' => (int)$phrase_node['Type'],
+ 'Module' => (string)$phrase_node['Module'] ? (string)$phrase_node['Module'] : 'Core',
+ 'LastChanged' => TIMENOW,
'LastChangeIP' => $this->ip_address,
);
- $translation = $phrase_node->Data;
- $hint_translation = isset($phrase_node->Attributes['HINT']) ? $phrase_node->Attributes['HINT'] : '';
- $column_translation = isset($phrase_node->Attributes['COLUMN']) ? $phrase_node->Attributes['COLUMN'] : '';
+ $translation = (string)$phrase_node;
+ $hint_translation = (string)$phrase_node['Hint'];
+ $column_translation = (string)$phrase_node['Column'];
- if (array_key_exists($fields_hash['PhraseType'], $this->phrase_types_allowed)) {
- if ($language_encoding != 'plain') {
+ if ( array_key_exists($fields_hash['PhraseType'], $this->phrase_types_allowed) ) {
+ if ( $language_encoding != 'plain' ) {
$translation = base64_decode($translation);
$hint_translation = base64_decode($hint_translation);
$column_translation = base64_decode($column_translation);
}
- if (array_key_exists($phrase_key, $other_translations)) {
+ if ( array_key_exists($phrase_key, $other_translations) ) {
$other_translations[$phrase_key]['l' . $language_id . '_Translation'] = $translation;
$other_translations[$phrase_key]['l' . $language_id . '_HintTranslation'] = $hint_translation;
$other_translations[$phrase_key]['l' . $language_id . '_ColumnTranslation'] = $column_translation;
}
else {
$other_translations[$phrase_key] = Array (
'l' . $language_id . '_Translation' => $translation,
'l' . $language_id . '_HintTranslation' => $hint_translation,
'l' . $language_id . '_ColumnTranslation' => $column_translation,
);
}
$fields_hash = array_merge($fields_hash, $other_translations[$phrase_key]);
$this->Conn->doInsert($fields_hash, $this->_tables['phrases'], 'REPLACE', false);
}
- } while (($phrase_node =& $phrase_node->NextSibling()));
+ }
- if ($this->Application->isDebugMode()) {
+ if ( $this->Application->isDebugMode() ) {
$this->Application->Debugger->profileFinish('L[' . $language_id . ']P', 'Language: ' . $language_id . '; Phrases Import');
}
$this->Conn->doInsert($fields_hash, $this->_tables['phrases'], 'REPLACE');
}
/**
* Performs email event import
*
- * @param kXMLNode $event_node
+ * @param SimpleXMLElement $events
* @param int $language_id
* @param string $language_encoding
*/
- function _processEvents(&$event_node, $language_id, $language_encoding)
+ function _processEvents($events, $language_id, $language_encoding)
{
static $other_translations = Array ();
- if ($this->Application->isDebugMode()) {
+ if ( $this->Application->isDebugMode() ) {
$this->Application->Debugger->profileStart('L[' . $language_id . ']E', 'Language: ' . $language_id . '; Events Import');
}
$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) {
- if ($language_encoding == 'plain') {
- $template = rtrim($event_node->Data);
- }
- else {
- $template = base64_decode($event_node->Data);
- }
+ foreach ($events as $event_node) {
+ /* @var $event_node SimpleXMLElement */
- $parsed = $email_message_helper->parseTemplate($template);
+ $event_id = $this->_getEventId((string)$event_node['Event'], (int)$event_node['Type']);
- $fields_hash = Array (
- 'EventId' => $event_id,
- 'Event' => $event_node->Attributes['EVENT'],
- 'Type' => $event_node->Attributes['TYPE'],
- 'MessageType' => $event_node->Attributes['MESSAGETYPE'],
- );
+ if ( !$event_id ) {
+ continue;
+ }
- if (array_key_exists($event_id, $other_translations)) {
- $other_translations[$event_id]['l' . $language_id . '_Subject'] = $parsed['Subject'];
- $other_translations[$event_id]['l' . $language_id . '_Body'] = $parsed['Body'];
- }
- else {
- $other_translations[$event_id] = Array (
- 'l' . $language_id . '_Subject' => $parsed['Subject'],
- 'l' . $language_id . '_Body' => $parsed['Body'],
- );
- }
+ if ( $language_encoding == 'plain' ) {
+ $template = rtrim($event_node);
+ }
+ else {
+ $template = base64_decode($event_node);
+ }
- if ($parsed['Headers']) {
- $other_translations[$event_id]['Headers'] = $parsed['Headers'];
- }
- elseif (!$parsed['Headers'] && !array_key_exists('Headers', $other_translations[$event_id])) {
- $other_translations[$event_id]['Headers'] = $parsed['Headers'];
- }
+ $parsed = $email_message_helper->parseTemplate($template);
+
+ $fields_hash = Array (
+ 'EventId' => $event_id,
+ 'Event' => (string)$event_node['Event'],
+ 'Type' => (int)$event_node['Type'],
+ 'MessageType' => (string)$event_node['MessageType'],
+ );
+
+ if ( array_key_exists($event_id, $other_translations) ) {
+ $other_translations[$event_id]['l' . $language_id . '_Subject'] = $parsed['Subject'];
+ $other_translations[$event_id]['l' . $language_id . '_Body'] = $parsed['Body'];
+ }
+ else {
+ $other_translations[$event_id] = Array (
+ 'l' . $language_id . '_Subject' => $parsed['Subject'],
+ 'l' . $language_id . '_Body' => $parsed['Body'],
+ );
+ }
- $fields_hash = array_merge($fields_hash, $other_translations[$event_id]);
- $this->Conn->doInsert($fields_hash, $this->_tables['emailevents'], 'REPLACE', false);
+ if ( $parsed['Headers'] ) {
+ $other_translations[$event_id]['Headers'] = $parsed['Headers'];
+ }
+ elseif ( !$parsed['Headers'] && !array_key_exists('Headers', $other_translations[$event_id]) ) {
+ $other_translations[$event_id]['Headers'] = $parsed['Headers'];
}
- } while (($event_node =& $event_node->NextSibling()));
- if ($this->Application->isDebugMode()) {
+ $fields_hash = array_merge($fields_hash, $other_translations[$event_id]);
+ $this->Conn->doInsert($fields_hash, $this->_tables['emailevents'], 'REPLACE', false);
+ }
+
+ if ( $this->Application->isDebugMode() ) {
$this->Application->Debugger->profileFinish('L[' . $language_id . ']E', 'Language: ' . $language_id . '; Events Import');
}
- if (isset($fields_hash)) {
+ if ( isset($fields_hash) ) {
// at least one email event in language pack was found in database
$this->Conn->doInsert($fields_hash, $this->_tables['emailevents'], 'REPLACE');
}
}
/**
* Performs country_state translation import
*
- * @param kXMLNode $country_state_node
+ * @param SimpleXMLElement $country_states
* @param int $language_id
* @param string $language_encoding
* @param bool $process_states
* @return void
*/
- function _processCountries(&$country_state_node, $language_id, $language_encoding, $process_states = false)
+ function _processCountries($country_states, $language_id, $language_encoding, $process_states = false)
{
static $other_translations = Array ();
- do {
- if ($process_states) {
- $country_state_id = $this->_getStateId($country_state_node->Parent->Attributes['ISO'], $country_state_node->Attributes['ISO']);
+ foreach ($country_states as $country_state_node) {
+ /* @var $country_state_node SimpleXMLElement */
+
+ if ( $process_states ) {
+ $country_state_id = $this->_getStateId((string)$country_states['Iso'], (string)$country_state_node['Iso']);
}
else {
- $country_state_id = $this->_getCountryId($country_state_node->Attributes['ISO']);
+ $country_state_id = $this->_getCountryId((string)$country_state_node['Iso']);
}
- if ($country_state_id) {
- if ($language_encoding == 'plain') {
- $translation = rtrim($country_state_node->Attributes['TRANSLATION']);
- }
- else {
- $translation = base64_decode($country_state_node->Attributes['TRANSLATION']);
- }
+ if ( !$country_state_id ) {
+ continue;
+ }
- $fields_hash = Array (
- 'CountryStateId' => $country_state_id,
- );
+ if ( $language_encoding == 'plain' ) {
+ $translation = rtrim($country_state_node['Translation']);
+ }
+ else {
+ $translation = base64_decode($country_state_node['Translation']);
+ }
- if (array_key_exists($country_state_id, $other_translations)) {
- $other_translations[$country_state_id]['l' . $language_id . '_Name'] = $translation;
- }
- else {
- $other_translations[$country_state_id] = Array (
- 'l' . $language_id . '_Name' => $translation,
- );
- }
+ $fields_hash = Array ('CountryStateId' => $country_state_id);
+
+ if ( array_key_exists($country_state_id, $other_translations) ) {
+ $other_translations[$country_state_id]['l' . $language_id . '_Name'] = $translation;
+ }
+ else {
+ $other_translations[$country_state_id] = Array ('l' . $language_id . '_Name' => $translation);
+ }
- $fields_hash = array_merge($fields_hash, $other_translations[$country_state_id]);
- $this->Conn->doInsert($fields_hash, $this->_tables['country-state'], 'REPLACE', false);
+ $fields_hash = array_merge($fields_hash, $other_translations[$country_state_id]);
+ $this->Conn->doInsert($fields_hash, $this->_tables['country-state'], 'REPLACE', false);
- if (!$process_states && $country_state_node->Children) {
- $this->_processCountries($country_state_node->firstChild, $language_id, $language_encoding, true);
- }
+ if ( !$process_states && $country_state_node->count() ) {
+ $this->_processCountries($country_state_node, $language_id, $language_encoding, true);
}
- } while (($country_state_node =& $country_state_node->NextSibling()));
+ }
$this->Conn->doInsert($fields_hash, $this->_tables['country-state'], 'REPLACE');
}
/**
* 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;
}
/**
* Returns country id based on it's 3letter ISO code
*
* @param string $iso
* @return int
*/
function _getCountryId($iso)
{
static $cache = null;
if (!isset($cache)) {
$sql = 'SELECT CountryStateId, IsoCode
FROM ' . TABLE_PREFIX . 'CountryStates
WHERE Type = ' . DESTINATION_TYPE_COUNTRY;
$cache = $this->Conn->GetCol($sql, 'IsoCode');
}
return array_key_exists($iso, $cache) ? $cache[$iso] : false;
}
/**
* Returns state id based on 3letter country ISO code and 2letter state ISO code
*
* @param string $country_iso
* @param string $state_iso
* @return int
*/
function _getStateId($country_iso, $state_iso)
{
static $cache = null;
if (!isset($cache)) {
$sql = 'SELECT CountryStateId, CONCAT(StateCountryId, "-", IsoCode) AS IsoCode
FROM ' . TABLE_PREFIX . 'CountryStates
WHERE Type = ' . DESTINATION_TYPE_STATE;
$cache = $this->Conn->GetCol($sql, 'IsoCode');
}
$country_id = $this->_getCountryId($country_iso);
return array_key_exists($country_id . '-' . $state_iso, $cache) ? $cache[$country_id . '-' . $state_iso] : false;
}
/**
* Returns comma-separated list of IDs, that will be exported
*
* @param string $prefix
* @return string
* @access public
*/
public function getExportIDs($prefix)
{
$ids = $this->Application->RecallVar($prefix . '_selected_ids');
if ( $ids ) {
// some records were selected in grid
return $ids;
}
$tag_params = Array (
'grid' => $prefix == 'phrases' ? 'Phrases' : 'Emails',
'skip_counting' => 1,
'per_page' => -1
);
$list = $this->Application->recallObject($prefix, $prefix . '_List', $tag_params);
/* @var $list kDBList */
$sql = $list->getCountSQL($list->GetSelectSQL());
$sql = str_replace('COUNT(*) AS count', $list->TableName . '.' . $list->IDField, $sql);
$ids = '';
$rs = $this->Conn->QueryRaw($sql);
if ( $this->Conn->RowCount($rs) ) {
while ( ($row = $this->Conn->GetNextRow($rs)) ) {
$ids .= ',' . $row[$list->IDField];
}
$ids = substr($ids, 1);
}
$this->Conn->Destroy($rs);
return $ids;
}
}
\ No newline at end of file
Index: branches/5.2.x/core/units/helpers/controls/minput_helper.php
===================================================================
--- branches/5.2.x/core/units/helpers/controls/minput_helper.php (revision 15157)
+++ branches/5.2.x/core/units/helpers/controls/minput_helper.php (revision 15158)
@@ -1,227 +1,218 @@
<?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!');
class MInputHelper extends kHelper {
/**
* Returns table for given prefix
*
* @param string $prefix
* @param bool $temp
* @return string
* @access protected
*/
protected function getTable($prefix, $temp = false)
{
$table_name = $this->Application->getUnitOption($prefix, 'TableName');
return $temp ? $this->Application->GetTempName($table_name, 'prefix:' . $prefix) : $table_name;
}
function prepareMInputXML($records, $use_fields)
{
$xml = '';
foreach ($records as $record) {
$xml .= '<record>';
foreach ($record as $field_name => $field_value) {
if (!in_array($field_name, $use_fields)) {
continue;
}
$xml .= '<field name="' . $field_name . '">' . htmlspecialchars($field_value) . '</field>';
}
$xml .= '</record>';
}
return $xml ? '<records>'.$xml.'</records>' : '';
}
/**
* Returns validation errors in XML format
*
* @param kDBItem $object
* @param Array $fields_hash
* @return string
*/
function prepareErrorsXML(&$object, $fields_hash)
{
$xml = '';
$errors = Array ();
foreach ($fields_hash as $field_name => $field_value) {
if (!$object->ValidateField($field_name)) {
$field_options = $object->GetFieldOptions($field_name);
$error_field = array_key_exists('error_field', $field_options) ? $field_options['error_field'] : $field_name;
$errors[$error_field] = '<field name="'.$error_field.'">'.$object->GetErrorMsg($error_field, false).'</field>';
}
}
return '<errors>'.implode('', $errors).'</errors>';
}
/**
* Validates MInput control fields
*
* @param kEvent $event
*/
function OnValidateMInputFields($event)
{
$object = $event->getObject();
/* @var $object kDBItem */
$items_info = $this->Application->GetVar($event->getPrefixSpecial(true));
if ($items_info) {
list ($id, $field_values) = each($items_info);
foreach ($field_values as $field_name => $field_value) {
$object->SetField($field_name, $field_value);
}
$event_mapping = Array (
'AddRecord' => 'OnBeforeItemCreate',
'SaveRecord' => 'OnBeforeItemUpdate',
);
$request_type = $this->Application->GetVar('request_type');
if (array_key_exists($request_type, $event_mapping)) {
$event->CallSubEvent($event_mapping[$request_type]);
}
echo $this->prepareErrorsXML($object, $field_values);
}
$event->status = kEvent::erSTOP;
}
function parseMInputXML($xml)
{
- $xml_helper = $this->Application->recallObject('kXMLHelper');
- /* @var $xml_helper kXMLHelper */
-
- $root_node =& $xml_helper->Parse($xml);
- $root_node =& $root_node->FindChild('records');
+ $records = Array ();
+ $records_node = simplexml_load_string($xml);
- if ( !$root_node || !$root_node->firstChild ) {
+ if ( $records_node === false ) {
return false;
}
- $records = Array ();
- $current_node = $root_node->firstChild;
- /* @var $current_node kXMLNode */
-
- do {
+ foreach ($records_node as $record_node) {
$record = Array ();
- $sub_node =& $current_node->firstChild;
- /* @var $current_node kXMLNode */
- do {
- $record[ $sub_node->Attributes['NAME'] ] = $sub_node->Data;
- } while ( ($sub_node =& $sub_node->NextSibling()) );
+ foreach ($record_node as $field_node) {
+ $record[(string)$field_node['name']] = (string)$field_node;
+ }
$records[] = $record;
- } while ( ($current_node =& $current_node->NextSibling()) );
+ }
return $records;
}
/**
* Loads selected values from sub_prefix to main item virtual field.
* Called from OnAfterItemLoad of main prefix.
*
* @param kEvent $event
* @param string $store_field main item's field name, to store values into
* @param string $sub_prefix prefix used to store info about selected items
* @param Array $use_fields fields, used in value string building
*/
function LoadValues($event, $store_field, $sub_prefix, $use_fields)
{
$object = $event->getObject();
/* @var $object kDBItem */
$sub_item = $this->Application->recallObject($sub_prefix, null, Array('skip_autoload' => true));
/* @var $sub_item kDBItem */
$foreign_key = $this->Application->getUnitOption($sub_prefix, 'ForeignKey');
$sql = 'SELECT *
FROM '.$this->getTable($sub_prefix, $object->IsTempTable()).'
WHERE '.$foreign_key.' = '.$object->GetID();
$selected_items = $this->Conn->Query($sql);
$field_names = array_keys( $sub_item->GetFieldValues() );
foreach ($selected_items as $key => $fields_hash) {
$sub_item->Clear();
$sub_item->SetDBFieldsFromHash($fields_hash);
// to fill *_date and *_time fields from main date fields
$sub_item->UpdateFormattersSubFields();
foreach ($field_names as $field) {
$field_options = $sub_item->GetFieldOptions($field);
$formatter = array_key_exists('formatter', $field_options) ? $field_options['formatter'] : false;
if ($formatter == 'kDateFormatter') {
$selected_items[$key][$field] = $sub_item->GetField($field, $field_options['input_format']);
}
else {
$selected_items[$key][$field] = $sub_item->GetDBField($field);
}
}
}
$object->SetDBField($store_field, $this->prepareMInputXML($selected_items, $use_fields));
}
/**
* Saves data from minput control to subitem table (used from subitem hook)
*
* @param kEvent $sub_event
* @param string $store_field
*/
function SaveValues(&$sub_event, $store_field)
{
$main_object =& $sub_event->MasterEvent->getObject();
/* @var $main_object kDBItem */
$affected_field = $main_object->GetDBField($store_field);
$object = $this->Application->recallObject($sub_event->getPrefixSpecial(), null, Array ('skip_autoload' => true));
/* @var $object kDBItem */
$sub_table = $object->TableName;
$foreign_key = $this->Application->getUnitOption($sub_event->Prefix, 'ForeignKey');
$sql = 'DELETE FROM '.$sub_table.'
WHERE '.$foreign_key.' = '.$main_object->GetID();
$this->Conn->Query($sql);
if ($affected_field) {
$records = $this->parseMInputXML($affected_field);
$main_id = $main_object->GetID();
foreach ($records as $fields_hash) {
$object->Clear();
$fields_hash[$foreign_key] = $main_id;
$object->SetDBFieldsFromHash($fields_hash);
$object->Create();
}
}
}
}
\ No newline at end of file
Index: branches/5.2.x/core/units/helpers/themes_helper.php
===================================================================
--- branches/5.2.x/core/units/helpers/themes_helper.php (revision 15157)
+++ branches/5.2.x/core/units/helpers/themes_helper.php (revision 15158)
@@ -1,629 +1,622 @@
<?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!');
class kThemesHelper extends kHelper {
/**
* Where all themes are located
*
* @var string
*/
var $themesFolder = '';
/**
* List of theme names, found on system
*
* @var Array
*/
var $_themeNames = Array ();
/**
* Temporary array when all theme files from db are stored
*
* @var Array
*/
var $themeFiles = Array ();
public function __construct()
{
parent::__construct();
$this->themesFolder = FULL_PATH.'/themes';
}
/**
* Updates file system changes to database for selected theme
*
* @param string $theme_name
*
* @return mixed returns ID of created/used theme or false, if none created
*/
function refreshTheme($theme_name)
{
if (!file_exists($this->themesFolder . '/' . $theme_name)) {
// requested theme was not found on hdd
return false;
}
$id_field = $this->Application->getUnitOption('theme', 'IDField');
$table_name = $this->Application->getUnitOption('theme', 'TableName');
$sql = 'SELECT *
FROM ' . $table_name . '
WHERE Name = ' . $this->Conn->qstr($theme_name);
$theme_info = $this->Conn->GetRow($sql);
if ($theme_info) {
$theme_id = $theme_info[$id_field];
$theme_enabled = $theme_info['Enabled'];
}
else {
$theme_id = $theme_enabled = false;
}
$this->themeFiles = Array ();
if ($theme_id) {
if (!$theme_enabled) {
// don't process existing theme files, that are disabled
return $theme_id;
}
// reset found mark for every themes file (if theme is not new)
$sql = 'UPDATE '.TABLE_PREFIX.'ThemeFiles
SET FileFound = 0
WHERE ThemeId = '.$theme_id;
$this->Conn->Query($sql);
// get all theme files from db
$sql = 'SELECT FileId, CONCAT(FilePath, "/", FileName) AS FullPath
FROM '.TABLE_PREFIX.'ThemeFiles
WHERE ThemeId = '.$theme_id;
$this->themeFiles = $this->Conn->GetCol($sql, 'FullPath');
}
else {
// theme was not found in db, but found on hdd -> create new
$theme_info = Array (
'Name' => $theme_name,
'Enabled' => 0,
'Description' => $theme_name,
'PrimaryTheme' => 0,
'CacheTimeout' => 3600, // not in use right now
'StylesheetId' => 0, // not in use right now
'LanguagePackInstalled' => 0
);
$this->Conn->doInsert($theme_info, $table_name);
$theme_id = $this->Conn->getInsertID();
if (!$theme_enabled) {
// don't process newly created theme files, because they are disabled
return $theme_id;
}
}
$this->_themeNames[$theme_id] = $theme_name;
$theme_path = $this->themesFolder.'/'.$theme_name;
$this->FindThemeFiles('', $theme_path, $theme_id); // search from base theme directory
// delete file records from db, that were not found on hdd
$sql = 'DELETE FROM '.TABLE_PREFIX.'ThemeFiles
WHERE ThemeId = '.$theme_id.' AND FileFound = 0';
$this->Conn->Query($sql);
// install language packs, associated with theme (if any found and wasn't aready installed)
if (!$theme_info['LanguagePackInstalled']) {
$this->installThemeLanguagePack($theme_path);
$fields_hash = Array (
'LanguagePackInstalled' => 1,
);
$this->Conn->doUpdate($fields_hash, $table_name, $id_field . ' = ' . $theme_id);
}
$fields_hash = Array (
'TemplateAliases' => serialize( $this->getTemplateAliases($theme_id, $theme_path) ),
);
$this->Conn->doUpdate($fields_hash, $table_name, $id_field . ' = ' . $theme_id);
return $theme_id;
}
/**
* Installs module(-s) language pack for given theme
*
* @param string $theme_path
* @param string|bool $module_name
* @return void
*/
function installThemeLanguagePack($theme_path, $module_name = false)
{
if ( $module_name === false ) {
$modules = $this->Application->ModuleInfo;
}
else {
$modules = Array ($module_name => $this->Application->ModuleInfo[$module_name]);
}
$language_import_helper = $this->Application->recallObject('LanguageImportHelper');
/* @var $language_import_helper LanguageImportHelper */
foreach ($modules as $module_name => $module_info) {
if ( $module_name == 'In-Portal' ) {
continue;
}
$lang_file = $theme_path . '/' . $module_info['TemplatePath'] . '_install/english.lang';
if ( file_exists($lang_file) ) {
$language_import_helper->performImport($lang_file, '|0|', '', LANG_SKIP_EXISTING);
}
}
}
/**
* Returns template aliases from "/_install/theme.xml" files in theme
*
* @param int $theme_id
* @param string $theme_path
* @return Array
* @access protected
*/
protected function getTemplateAliases($theme_id, $theme_path)
{
$template_aliases = Array ();
- $xml_parser = $this->Application->recallObject('kXMLHelper');
- /* @var $xml_parser kXMLHelper */
-
foreach ($this->Application->ModuleInfo as $module_name => $module_info) {
- if ( $module_name == 'In-Portal' ) {
+ $xml_file = $theme_path . '/' . $module_info['TemplatePath'] . '_install/theme.xml';
+
+ if ( $module_name == 'In-Portal' || !file_exists($xml_file) ) {
continue;
}
- $xml_file = $theme_path . '/' . $module_info['TemplatePath'] . '_install/theme.xml';
+ $theme = simplexml_load_file($xml_file);
- if ( file_exists($xml_file) ) {
- $xml_data = file_get_contents($xml_file);
- $root_node =& $xml_parser->Parse($xml_data);
-
- if ( !is_object($root_node) || !is_a($root_node, 'kXMLNode') || !$root_node->Children ) {
- // broken xml OR no aliases defined
- continue;
- }
+ if ( $theme === false ) {
+ // broken xml OR no aliases defined
+ continue;
+ }
- $current_node =& $root_node->firstChild;
- /* @var $current_node kXMLNode */
+ foreach ($theme as $design) {
+ /* @var $design SimpleXMLElement */
- do {
- $template_path = trim($current_node->Data);
- $module_override = $current_node->GetAttribute('module');
-
- if ( $module_override ) {
- // allow to put template mappings form all modules into single theme.xml file
- $module_folder = $this->Application->findModule('Name', $module_override, 'TemplatePath');
- }
- else {
- // no module specified -> use module based on theme.xml file location
- $module_folder = $module_info['TemplatePath'];
- }
+ $template_path = trim($design);
+ $module_override = (string)$design['module'];
+
+ if ( $module_override ) {
+ // allow to put template mappings form all modules into single theme.xml file
+ $module_folder = $this->Application->findModule('Name', $module_override, 'TemplatePath');
+ }
+ else {
+ // no module specified -> use module based on theme.xml file location
+ $module_folder = $module_info['TemplatePath'];
+ }
- // only store alias, when template exists on disk
- if ( $this->getTemplateId($template_path, $theme_id) ) {
- $alias = '#' . $module_folder . strtolower($current_node->Name) . '#';
+ // only store alias, when template exists on disk
+ if ( $this->getTemplateId($template_path, $theme_id) ) {
+ $alias = '#' . $module_folder . strtolower($design->getName()) . '#';
- // remember alias in global theme mapping
- $template_aliases[$alias] = $template_path;
+ // remember alias in global theme mapping
+ $template_aliases[$alias] = $template_path;
- // store alias in theme file record to use later in design dropdown
- $this->updateTemplate($template_path, $theme_id, Array ('TemplateAlias' => $alias));
- }
- } while ( ($current_node =& $current_node->NextSibling()) );
+ // store alias in theme file record to use later in design dropdown
+ $this->updateTemplate($template_path, $theme_id, Array ('TemplateAlias' => $alias));
+ }
}
}
return $template_aliases;
}
/**
* Returns ID of given physical template (relative to theme) given from ThemeFiles table
* @param string $template_path
* @param int $theme_id
* @return int
* @access public
*/
public function getTemplateId($template_path, $theme_id)
{
$physical_template = $this->Application->getPhysicalTemplate($template_path);
if ( ($physical_template !== false) && (substr($physical_template, 0, 3) != 'id:') ) {
// replace menu template name with it's actual template name on disk
list ($template_path) = explode(':', $physical_template, 2);
}
$sql = 'SELECT FileId
FROM ' . TABLE_PREFIX . 'ThemeFiles
WHERE ' . $this->getTemplateWhereClause($template_path, $theme_id);
return $this->Conn->GetOne($sql);
}
/**
* Updates template record with a given data
*
* @param string $template_path
* @param int $theme_id
* @param Array $fields_hash
* @return void
* @access public
*/
public function updateTemplate($template_path, $theme_id, $fields_hash)
{
$where_clause = $this->getTemplateWhereClause($template_path, $theme_id);
$this->Conn->doUpdate($fields_hash, TABLE_PREFIX . 'ThemeFiles', $where_clause);
}
/**
* Returns where clause to get associated record from ThemeFiles table for given template path
* @param string $template_path
* @param int $theme_id
* @return string
* @access protected
*/
protected function getTemplateWhereClause($template_path, $theme_id)
{
$folder = dirname($template_path);
$where_clause = Array (
'ThemeId = ' . $theme_id,
'FilePath = ' . $this->Conn->qstr($folder == '.' ? '' : '/' . $folder),
'FileName = ' . $this->Conn->qstr(basename($template_path) . '.tpl'),
);
return '(' . implode(') AND (', $where_clause) . ')';
}
/**
* Installs given module language pack and refreshed it from all themes
*
* @param string $module_name
*/
function synchronizeModule($module_name)
{
$sql = 'SELECT `Name`, ThemeId
FROM ' . TABLE_PREFIX . 'Themes';
$themes = $this->Conn->GetCol($sql, 'ThemeId');
if (!$themes) {
return ;
}
foreach ($themes as $theme_id => $theme_name) {
$theme_path = $this->themesFolder . '/' . $theme_name;
// install language pack
$this->installThemeLanguagePack($theme_path, $module_name);
// update TemplateAliases mapping
$fields_hash = Array (
'TemplateAliases' => serialize( $this->getTemplateAliases($theme_id, $theme_path) ),
);
$this->Conn->doUpdate($fields_hash, TABLE_PREFIX . 'Themes', 'ThemeId = ' . $theme_id);
}
}
/**
* Searches for new templates (missing in db) in specified folder
*
* @param string $folder_path subfolder of searchable theme
* @param string $theme_path theme path from web server root
* @param int $theme_id id of theme we are scanning
* @param int $auto_structure_mode
*/
function FindThemeFiles($folder_path, $theme_path, $theme_id, $auto_structure_mode = 1)
{
$ignore_regexp = $this->getIgnoreRegexp($theme_path . $folder_path);
$iterator = new DirectoryIterator($theme_path . $folder_path . '/');
/* @var $file_info DirectoryIterator */
foreach ($iterator as $file_info) {
$filename = $file_info->getFilename();
$auto_structure = preg_match($ignore_regexp, $filename) ? 2 : $auto_structure_mode;
$file_path = $folder_path . '/' . $filename; // don't pass path to theme top folder!
if ( $file_info->isDir() && !$file_info->isDot() && $filename != 'CVS' && $filename != '.svn' ) {
$this->FindThemeFiles($file_path, $theme_path, $theme_id, $auto_structure);
}
elseif ( pathinfo($filename, PATHINFO_EXTENSION) == 'tpl' ) {
$meta_info = $this->_getTemplateMetaInfo(trim($file_path, '/'), $theme_id);
$file_id = isset($this->themeFiles[$file_path]) ? $this->themeFiles[$file_path] : false;
$file_description = array_key_exists('desc', $meta_info) ? $meta_info['desc'] : '';
if ($file_id) {
// file was found in db & on hdd -> mark as existing
$fields_hash = Array (
'FileFound' => 1,
'Description' => $file_description,
'FileType' => $auto_structure,
'FileMetaInfo' => serialize($meta_info),
);
$this->Conn->doUpdate($fields_hash, TABLE_PREFIX . 'ThemeFiles', 'FileId = ' . $file_id);
}
else {
// file was found on hdd, but missing in db -> create new file record
$fields_hash = Array (
'ThemeId' => $theme_id,
'FileName' => $filename,
'FilePath' => $folder_path,
'Description' => $file_description,
'FileType' => $auto_structure, // 1 - built-in, 0 - custom (not in use right now), 2 - skipped in structure
'FileMetaInfo' => serialize($meta_info),
'FileFound' => 1,
);
$this->Conn->doInsert($fields_hash, TABLE_PREFIX.'ThemeFiles');
$this->themeFiles[$file_path] = $this->Conn->getInsertID();
}
// echo 'FilePath: [<strong>'.$folder_path.'</strong>]; FileName: [<strong>'.$filename.'</strong>]; IsNew: [<strong>'.($file_id > 0 ? 'NO' : 'YES').'</strong>]<br />';
}
}
}
/**
* Returns single regular expression to match all ignore patters, that are valid for given folder
*
* @param string $folder_path
* @return string
*/
protected function getIgnoreRegexp($folder_path)
{
// always ignore design and element templates
$ignore = '\.des\.tpl$|\.elm\.tpl$';
$sms_ignore_file = $folder_path . '/.smsignore';
if ( file_exists($sms_ignore_file) ) {
$manual_patterns = array_map('trim', file($sms_ignore_file));
foreach ($manual_patterns as $manual_pattern) {
$ignore .= '|' . str_replace('/', '\\/', $manual_pattern);
}
}
return '/' . $ignore . '/';
}
/**
* Returns template information (name, description, path) from it's header comment
*
* @param string $template
* @param int $theme_id
* @return Array
*/
function _getTemplateMetaInfo($template, $theme_id)
{
static $init_made = false;
if (!$init_made) {
$this->Application->InitParser(true);
$init_made = true;
}
$template = 'theme:' . $this->_themeNames[$theme_id] . '/' . $template;
$template_file = $this->Application->TemplatesCache->GetRealFilename($template); // ".tpl" was added before
return $this->parseTemplateMetaInfo($template_file);
}
function parseTemplateMetaInfo($template_file)
{
if (!file_exists($template_file)) {
// when template without info it's placed in top category
return Array ();
}
$template_data = file_get_contents($template_file);
if (substr($template_data, 0, 6) == '<!--##') {
// template starts with comment in such format
/*<!--##
<NAME></NAME>
<DESC></DESC>
<SECTION>||</SECTION>
##-->*/
$comment_end = strpos($template_data, '##-->');
if ($comment_end === false) {
// badly formatted comment
return Array ();
}
$comment = trim( substr($template_data, 6, $comment_end - 6) );
if (preg_match_all('/<(NAME|DESC|SECTION)>(.*?)<\/(NAME|DESC|SECTION)>/is', $comment, $regs)) {
$ret = Array ();
foreach ($regs[1] as $param_order => $param_name) {
$ret[ strtolower($param_name) ] = trim($regs[2][$param_order]);
}
if (array_key_exists('section', $ret) && $ret['section']) {
$category_path = explode('||', $ret['section']);
$category_path = array_map('trim', $category_path);
$ret['section'] = implode('||', $category_path);
}
return $ret;
}
}
return Array ();
}
/**
* Updates file system changes to database for all themes (including new ones)
*
*/
function refreshThemes()
{
$themes_found = Array ();
try {
$iterator = new DirectoryIterator($this->themesFolder . '/');
/* @var $file_info DirectoryIterator */
foreach ($iterator as $file_info) {
$filename = $file_info->getFilename();
if ( $file_info->isDir() && !$file_info->isDot() && $filename != '.svn' && $filename != 'CVS' ) {
$theme_id = $this->refreshTheme($filename);
if ( $theme_id ) {
$themes_found[] = $theme_id;
// increment serial of updated themes
$this->Application->incrementCacheSerial('theme', $theme_id);
}
}
}
}
catch ( UnexpectedValueException $e ) {
}
$id_field = $this->Application->getUnitOption('theme', 'IDField');
$table_name = $this->Application->getUnitOption('theme', 'TableName');
// 1. only one theme found -> enable it and make primary
/*if (count($themes_found) == 1) {
$sql = 'UPDATE ' . $table_name . '
SET Enabled = 1, PrimaryTheme = 1
WHERE ' . $id_field . ' = ' . current($themes_found);
$this->Conn->Query($sql);
}*/
// 2. if none themes found -> delete all from db OR delete all except of found themes
$sql = 'SELECT ' . $id_field . '
FROM ' . $table_name;
if ( $themes_found ) {
$sql .= ' WHERE ' . $id_field . ' NOT IN (' . implode(',', $themes_found) . ')';
}
$theme_ids = $this->Conn->GetCol($sql);
$this->deleteThemes($theme_ids);
foreach ($theme_ids as $theme_id) {
// increment serial of deleted themes
$this->Application->incrementCacheSerial('theme', $theme_id);
}
$this->Application->incrementCacheSerial('theme');
$this->Application->incrementCacheSerial('theme-file');
$minify_helper = $this->Application->recallObject('MinifyHelper');
/* @var $minify_helper MinifyHelper */
$minify_helper->delete();
}
/**
* Deletes themes with ids passed from db
*
* @param Array $theme_ids
*/
function deleteThemes($theme_ids)
{
if (!$theme_ids) {
return ;
}
$id_field = $this->Application->getUnitOption('theme', 'IDField');
$table_name = $this->Application->getUnitOption('theme', 'TableName');
$sql = 'DELETE FROM '.$table_name.'
WHERE '.$id_field.' IN ('.implode(',', $theme_ids).')';
$this->Conn->Query($sql);
$sql = 'DELETE FROM '.TABLE_PREFIX.'ThemeFiles
WHERE '.$id_field.' IN ('.implode(',', $theme_ids).')';
$this->Conn->Query($sql);
}
/**
* Returns current theme (also works in admin)
*
* @return int
*/
function getCurrentThemeId()
{
static $theme_id = null;
if (isset($theme_id)) {
return $theme_id;
}
if ($this->Application->isAdmin) {
// get theme, that user selected in catalog
$theme_id = $this->Application->RecallVar('theme_id');
if ($theme_id === false) {
// query, because "m_theme" is always empty in admin
$id_field = $this->Application->getUnitOption('theme', 'IDField');
$table_name = $this->Application->getUnitOption('theme', 'TableName');
$sql = 'SELECT ' . $id_field . '
FROM ' . $table_name . '
WHERE (PrimaryTheme = 1) AND (Enabled = 1)';
$theme_id = $this->Conn->GetOne($sql);
}
return $theme_id;
}
// use current theme, because it's available on Front-End
$theme_id = $this->Application->GetVar('m_theme');
if (!$theme_id) {
// happens in mod-rewrite mode, then requested template is not found
$theme_id = $this->Application->GetDefaultThemeId();
}
return $theme_id;
}
/**
* Returns page id based on given template
*
* @param string $template
* @param int $theme_id
* @return int
*/
function getPageByTemplate($template, $theme_id = null)
{
if (!isset($theme_id)) {
// during mod-rewrite url parsing current theme
// is not available to kHTTPQuery class, so don't use it
$theme_id = (int)$this->getCurrentThemeId();
}
$sql = 'SELECT ' . $this->Application->getUnitOption('c', 'IDField') . '
FROM ' . $this->Application->getUnitOption('c', 'TableName') . '
WHERE
(
(NamedParentPath = ' . $this->Conn->qstr('Content/' . $template) . ') OR
(`Type` = ' . PAGE_TYPE_TEMPLATE . ' AND CachedTemplate = ' . $this->Conn->qstr($template) . ')
)
AND (ThemeId = ' . $theme_id . ($theme_id > 0 ? ' OR ThemeId = 0' : '') . ')';
return $this->Conn->GetOne($sql);
}
}
\ No newline at end of file
Index: branches/5.2.x/core/install/install_toolkit.php
===================================================================
--- branches/5.2.x/core/install/install_toolkit.php (revision 15157)
+++ branches/5.2.x/core/install/install_toolkit.php (revision 15158)
@@ -1,1182 +1,1178 @@
<?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!');
/**
* Upgrade sqls are located using this mask
*
*/
define('UPGRADES_FILE', FULL_PATH.'/%sinstall/upgrades.%s');
/**
* Prerequisit check classes are located using this mask
*
*/
define('PREREQUISITE_FILE', FULL_PATH.'/%sinstall/prerequisites.php');
/**
* Format of version identificator in upgrade files (normal, beta, release candidate)
*
*/
define('VERSION_MARK', '# ===== v ([\d]+\.[\d]+\.[\d]+|[\d]+\.[\d]+\.[\d]+-B[\d]+|[\d]+\.[\d]+\.[\d]+-RC[\d]+) =====');
if (!defined('GET_LICENSE_URL')) {
/**
* Url used for retrieving user licenses from Intechnic licensing server
*
*/
define('GET_LICENSE_URL', 'http://www.in-portal.com/license.php');
}
/**
* Misc functions, that are required during installation, when
*
*/
class kInstallToolkit {
/**
* Reference to kApplication class object
*
* @var kApplication
*/
var $Application = null;
/**
* Connection to database
*
* @var kDBConnection
*/
var $Conn = null;
/**
* Path to config.php
*
* @var string
*/
var $INIFile = '';
/**
* Parsed data from config.php
*
* @var Array
*/
var $systemConfig = Array ();
/**
* Tells, that system config was changed
*
* @var bool
* @access public
*/
public $systemConfigChanged = false;
/**
* Path, used by system to store data on filesystem
*
* @var string
*/
var $defaultWritablePath = '';
/**
* Installator instance
*
* @var kInstallator
*/
var $_installator = null;
function kInstallToolkit()
{
$this->defaultWritablePath = DIRECTORY_SEPARATOR . 'system';
if ( class_exists('kApplication') ) {
// auto-setup in case of separate module install
$this->Application =& kApplication::Instance();
$this->Application->Init(); // needed for standalone module install
$this->Conn =& $this->Application->GetADODBConnection();
}
$this->INIFile = FULL_PATH . $this->defaultWritablePath . DIRECTORY_SEPARATOR . 'config.php';
$this->systemConfig = $this->ParseConfig(true);
}
/**
* Sets installator
*
* @param kInstallator $instance
*/
function setInstallator(&$instance)
{
$this->_installator =& $instance;
}
/**
* Checks prerequisities before module install or upgrade
*
* @param string $module_path
* @param string $versions
* @param string $mode upgrade mode = {install, standalone, upgrade}
* @return bool
*/
function CheckPrerequisites($module_path, $versions, $mode)
{
if ( !$versions ) {
return Array ();
}
$prerequisite_object =& $this->getPrerequisiteObject($module_path);
/* @var $prerequisite_object InPortalPrerequisites */
// some errors possible
return is_object($prerequisite_object) ? $prerequisite_object->CheckPrerequisites($versions, $mode) : Array ();
}
/**
* Call prerequisites method
*
* @param string $module_path
* @param string $method
* @return array
*/
function CallPrerequisitesMethod($module_path, $method)
{
$prerequisite_object =& $this->getPrerequisiteObject($module_path);
/* @var $prerequisite_object InPortalPrerequisites */
return is_object($prerequisite_object) ? $prerequisite_object->$method() : false;
}
/**
* Returns prerequisite object to be used for checks
*
* @param string $module_path
* @return kHelper
* @access protected
*/
protected function &getPrerequisiteObject($module_path)
{
static $prerequisite_classes = Array ();
$prerequisites_file = sprintf(PREREQUISITE_FILE, $module_path);
if ( !file_exists($prerequisites_file) ) {
$false = false;
return $false;
}
if ( !isset($prerequisite_classes[$module_path]) ) {
// save class name, because 2nd time
// (in after call $prerequisite_class variable will not be present)
include_once $prerequisites_file;
$prerequisite_classes[$module_path] = $prerequisite_class;
}
$prerequisite_object = new $prerequisite_classes[$module_path]();
/* @var $prerequisite_object InPortalPrerequisites */
if ( method_exists($prerequisite_object, 'setToolkit') ) {
$prerequisite_object->setToolkit($this);
}
return $prerequisite_object;
}
/**
* Processes one license, received from server
*
* @param string $file_data
*/
function processLicense($file_data)
{
$modules_helper = $this->Application->recallObject('ModulesHelper');
/* @var $modules_helper kModulesHelper */
$file_data = explode('Code==:', $file_data);
$file_data[0] = str_replace('In-Portal License File - do not edit!' . "\n", '', $file_data[0]);
$file_data = array_map('trim', $file_data);
if ($modules_helper->verifyLicense($file_data[0])) {
$this->setSystemConfig('Intechnic', 'License', $file_data[0]);
if (array_key_exists(1, $file_data)) {
$this->setSystemConfig('Intechnic', 'LicenseCode', $file_data[1]);
}
else {
$this->setSystemConfig('Intechnic', 'LicenseCode');
}
$this->SaveConfig();
}
else {
// invalid license received from licensing server
$this->_installator->errorMessage = 'Invalid License File';
}
}
/**
* Saves given configuration values to database
*
* @param Array $config
*/
function saveConfigValues($config)
{
foreach ($config as $config_var => $value) {
$sql = 'UPDATE ' . TABLE_PREFIX . 'SystemSettings
SET VariableValue = ' . $this->Conn->qstr($value) . '
WHERE VariableName = ' . $this->Conn->qstr($config_var);
$this->Conn->Query($sql);
}
}
/**
* Sets module version to passed
*
* @param string $module_name
* @param string|bool $module_path
* @param string|bool $version
*/
function SetModuleVersion($module_name, $module_path = false, $version = false)
{
if ($version === false) {
if (!$module_path) {
throw new Exception('Module path must be given to "SetModuleVersion" method to auto-detect version');
return ;
}
$version = $this->GetMaxModuleVersion($module_path);
}
// get table prefix from config, because application may not be available here
$table_prefix = $this->getSystemConfig('Database', 'TablePrefix');
if ($module_name == 'kernel') {
$module_name = 'in-portal';
}
// don't use "adodb_mktime" here, because it's not yet included
$sql = 'UPDATE ' . $table_prefix . 'Modules
SET Version = "' . $version . '", BuildDate = ' . time() . '
WHERE LOWER(Name) = "' . strtolower($module_name) . '"';
$this->Conn->Query($sql);
}
/**
* Sets module root category to passed
*
* @param string $module_name
* @param int $category_id
*/
function SetModuleRootCategory($module_name, $category_id = 0)
{
// get table prefix from config, because application may not be available here
$table_prefix = $this->getSystemConfig('Database', 'TablePrefix');
if ($module_name == 'kernel') {
$module_name = 'in-portal';
}
$sql = 'UPDATE ' . $table_prefix . 'Modules
SET RootCat = ' . $category_id . '
WHERE LOWER(Name) = "' . strtolower($module_name) . '"';
$this->Conn->Query($sql);
}
/**
* Returns maximal version of given module by scanning it's upgrade scripts
*
* @param string $module_path
* @return string
*/
function GetMaxModuleVersion($module_path)
{
$module_path = rtrim(mb_strtolower($module_path), '/');
$upgrades_file = sprintf(UPGRADES_FILE, $module_path . '/', 'sql');
if (!file_exists($upgrades_file)) {
// no upgrade file
return '5.0.0';
}
$sqls = file_get_contents($upgrades_file);
$versions_found = preg_match_all('/'.VERSION_MARK.'/s', $sqls, $regs);
if (!$versions_found) {
// upgrades file doesn't contain version definitions
return '5.0.0';
}
return end($regs[1]);
}
/**
* Runs SQLs from file
*
* @param string $filename
* @param mixed $replace_from
* @param mixed $replace_to
*/
function RunSQL($filename, $replace_from = null, $replace_to = null)
{
if (!file_exists(FULL_PATH.$filename)) {
return ;
}
$sqls = file_get_contents(FULL_PATH.$filename);
if (!$this->RunSQLText($sqls, $replace_from, $replace_to)) {
if (is_object($this->_installator)) {
$this->_installator->Done();
}
else {
if (isset($this->Application)) {
$this->Application->Done();
}
exit;
}
}
}
/**
* Runs SQLs from string
*
* @param string $sqls
* @param mixed $replace_from
* @param mixed $replace_to
* @param int $start_from
* @return bool
*/
function RunSQLText(&$sqls, $replace_from = null, $replace_to = null, $start_from = 0)
{
$table_prefix = $this->getSystemConfig('Database', 'TablePrefix');
// add prefix to all tables
if (strlen($table_prefix) > 0) {
$replacements = Array ('INSERT INTO ', 'UPDATE ', 'ALTER TABLE ', 'DELETE FROM ', 'REPLACE INTO ');
foreach ($replacements as $replacement) {
$sqls = str_replace($replacement, $replacement . $table_prefix, $sqls);
}
}
$sqls = str_replace('CREATE TABLE ', 'CREATE TABLE IF NOT EXISTS ' . $table_prefix, $sqls);
$sqls = str_replace('DROP TABLE ', 'DROP TABLE IF EXISTS ' . $table_prefix, $sqls);
$sqls = str_replace('<%TABLE_PREFIX%>', $table_prefix, $sqls);
$primary_language = is_object($this->Application) ? $this->Application->GetDefaultLanguageId() : 1;
$sqls = str_replace('<%PRIMARY_LANGUAGE%>', $primary_language, $sqls);
if (isset($replace_from) && isset($replace_to)) {
// replace something additionally, e.g. module root category
$sqls = str_replace($replace_from, $replace_to, $sqls);
}
$sqls = str_replace("\r\n", "\n", $sqls); // convert to linux line endings
$no_comment_sqls = preg_replace("/#\s([^;]*?)\n/is", '', $sqls); // remove all comments "#" on new lines
if ($no_comment_sqls === null) {
// "ini.pcre.backtrack-limit" reached and error happened
$sqls = explode(";\n", $sqls . "\n"); // ensures that last sql won't have ";" in it
$sqls = array_map('trim', $sqls);
// remove all comments "#" on new lines (takes about 2 seconds for 53000 sqls)
$sqls = preg_replace("/#\s([^;]*?)/", '', $sqls);
}
else {
$sqls = explode(";\n", $no_comment_sqls . "\n"); // ensures that last sql won't have ";" in it
$sqls = array_map('trim', $sqls);
}
$sql_count = count($sqls);
$db_collation = $this->getSystemConfig('Database', 'DBCollation');
for ($i = $start_from; $i < $sql_count; $i++) {
$sql = $sqls[$i];
if (!$sql || (substr($sql, 0, 1) == '#')) {
continue; // usually last line
}
if (substr($sql, 0, 13) == 'CREATE TABLE ' && $db_collation) {
// it is CREATE TABLE statement -> add collation
$sql .= ' COLLATE \'' . $db_collation . '\'';
}
$this->Conn->Query($sql);
if ($this->Conn->getErrorCode() != 0) {
if (is_object($this->_installator)) {
$this->_installator->errorMessage = 'Error: ('.$this->Conn->getErrorCode().') '.$this->Conn->getErrorMsg().'<br /><br />Last Database Query:<br /><textarea cols="70" rows="10" readonly>'.htmlspecialchars($sql).'</textarea>';
$this->_installator->LastQueryNum = $i + 1;
}
return false;
}
}
return true;
}
/**
* Performs clean language import from given xml file
*
* @param string $lang_file
* @param bool $upgrade
* @todo Import for "core/install/english.lang" (322KB) takes 18 seconds to work on Windows
*/
function ImportLanguage($lang_file, $upgrade = false)
{
$lang_file = FULL_PATH.$lang_file.'.lang';
if (!file_exists($lang_file)) {
return ;
}
$language_import_helper = $this->Application->recallObject('LanguageImportHelper');
/* @var $language_import_helper LanguageImportHelper */
$language_import_helper->performImport($lang_file, '|0|1|2|', '', $upgrade ? LANG_SKIP_EXISTING : LANG_OVERWRITE_EXISTING);
}
/**
* Converts module version in format X.Y.Z[-BN/-RCM] to signle integer
*
* @param string $version
* @return int
*/
function ConvertModuleVersion($version)
{
if (preg_match('/(.*)-(B|RC)([\d]+)/', $version, $regs)) {
// -B<M> or RC-<N>
$parts = explode('.', $regs[1]);
$parts[] = $regs[2] == 'B' ? 1 : 2; // B reliases goes before RC releases
$parts[] = $regs[3];
}
else {
// releases without B/RC marks go after any B/RC releases
$parts = explode('.', $version . '.3.100');
}
$bin = '';
foreach ($parts as $part_index => $part) {
if ($part_index == 3) {
// version type only can be 1/2/3 (11 in binary form), so don't use padding at all
$pad_count = 2;
}
else {
$pad_count = 8;
}
$bin .= str_pad(decbin($part), $pad_count, '0', STR_PAD_LEFT);
}
return bindec($bin);
}
/**
* Returns themes, found in system
*
* @param bool $rebuild
* @return int
*/
function getThemes($rebuild = false)
{
if ($rebuild) {
$this->rebuildThemes();
}
$id_field = $this->Application->getUnitOption('theme', 'IDField');
$table_name = $this->Application->getUnitOption('theme', 'TableName');
$sql = 'SELECT Name, ' . $id_field . '
FROM ' . $table_name . '
ORDER BY Name ASC';
return $this->Conn->GetCol($sql, $id_field);
}
function ParseConfig($parse_section = false)
{
if (!file_exists($this->INIFile)) {
return Array ();
}
if (file_exists($this->INIFile) && !is_readable($this->INIFile)) {
die('Could Not Open Ini File');
}
$contents = file($this->INIFile);
if ($contents && $contents[0] == '<' . '?' . 'php die() ?' . ">\n") {
// format of "config.php" file before 5.1.0 version
array_shift($contents);
return $this->parseIniString(implode('', $contents), $parse_section);
}
$_CONFIG = Array ();
require($this->INIFile);
if ($parse_section) {
return $_CONFIG;
}
$ret = Array ();
foreach ($_CONFIG as $section => $section_variables) {
$ret = array_merge($ret, $section_variables);
}
return $ret;
}
/**
* Equivalent for "parse_ini_string" function available since PHP 5.3.0
*
* @param string $ini
* @param bool $process_sections
* @param int $scanner_mode
* @return Array
*/
function parseIniString($ini, $process_sections = false, $scanner_mode = null)
{
# Generate a temporary file.
$tempname = tempnam('/tmp', 'ini');
$fp = fopen($tempname, 'w');
fwrite($fp, $ini);
$ini = parse_ini_file($tempname, !empty($process_sections));
fclose($fp);
@unlink($tempname);
return $ini;
}
function SaveConfig($silent = false)
{
if (!is_writable($this->INIFile) && !is_writable(dirname($this->INIFile))) {
$error_msg = 'Cannot write to "' . $this->INIFile . '" file';
if ($silent) {
trigger_error($error_msg, E_USER_WARNING);
}
else {
throw new Exception($error_msg);
}
return ;
}
$fp = fopen($this->INIFile, 'w');
fwrite($fp, '<' . '?' . 'php' . "\n\n");
foreach ($this->systemConfig as $section_name => $section_data) {
foreach ($section_data as $key => $value) {
fwrite($fp, '$_CONFIG[\'' . $section_name . '\'][\'' . $key . '\'] = \'' . addslashes($value) . '\';' . "\n");
}
fwrite($fp, "\n");
}
fclose($fp);
$this->systemConfigChanged = false;
}
/**
* Sets value to system config (yet SaveConfig must be called to write it to file)
*
* @param string $section
* @param string $key
* @param string $value
*/
function setSystemConfig($section, $key, $value = null)
{
$this->systemConfigChanged = true;
if (isset($value)) {
if (!array_key_exists($section, $this->systemConfig)) {
// create section, when missing
$this->systemConfig[$section] = Array ();
}
// create key in section
$this->systemConfig[$section][$key] = $value;
return ;
}
unset($this->systemConfig[$section][$key]);
}
/**
* Returns information from system config
*
* @param string $section
* @param string $key
* @param mixed $default
* @return string|bool
*/
function getSystemConfig($section, $key, $default = false)
{
if ( !array_key_exists($section, $this->systemConfig) ) {
return $default;
}
if ( !array_key_exists($key, $this->systemConfig[$section]) ) {
return $default;
}
return $this->systemConfig[$section][$key] ? $this->systemConfig[$section][$key] : $default;
}
/**
* Checks if system config is present and is not empty
*
* @return bool
*/
function systemConfigFound()
{
return file_exists($this->INIFile) && $this->systemConfig;
}
/**
* Checks if given section is present in config
*
* @param string $section
* @return bool
*/
function sectionFound($section)
{
return array_key_exists($section, $this->systemConfig);
}
/**
* Returns formatted module name based on it's root folder
*
* @param string $module_folder
* @return string
*/
function getModuleName($module_folder)
{
return implode('-', array_map('ucfirst', explode('-', $module_folder)));
}
/**
* Returns information about module (based on "install/module_info.xml" file)
*
* @param string $module_name
* @return Array
*/
function getModuleInfo($module_name)
{
- if ($module_name == 'core') {
+ if ( $module_name == 'core' ) {
$info_file = FULL_PATH . '/' . $module_name . '/install/module_info.xml';
}
else {
$info_file = MODULES_PATH . '/' . $module_name . '/install/module_info.xml';
}
- if (!file_exists($info_file)) {
+ if ( !file_exists($info_file) ) {
return Array ();
}
- $xml_helper = $this->Application->recallObject('kXMLHelper');
- /* @var $xml_helper kXMLHelper */
-
- $root_node =& $xml_helper->Parse( file_get_contents($info_file) );
+ $ret = Array ();
+ $module_info = simplexml_load_file($info_file);
- if (!is_object($root_node) || !preg_match('/^kxmlnode/i', get_class($root_node)) || ($root_node->Name == 'ERROR')) {
+ if ( $module_info === false ) {
// non-valid xml file
return Array ();
}
- $ret = Array ();
- $current_node =& $root_node->firstChild;
-
- do {
- $ret[ strtolower($current_node->Name) ] = trim($current_node->Data);
- } while (($current_node =& $current_node->NextSibling()));
+ foreach ($module_info as $node) {
+ /* @var $node SimpleXMLElement */
+ $ret[strtolower($node->getName())] = trim($node);
+ }
return $ret;
}
/**
* Returns nice module string to be used on install/upgrade screens
*
* @param string $module_name
* @param string $version_string
* @return string
*/
function getModuleString($module_name, $version_string)
{
// image (if exists) <description> (<name> <version>)
$ret = Array ();
$module_info = $this->getModuleInfo($module_name);
if (array_key_exists('name', $module_info) && $module_info['name']) {
$module_name = $module_info['name'];
}
else {
$module_name = $this->getModuleName($module_name);
}
if (array_key_exists('image', $module_info) && $module_info['image']) {
$image_src = $module_info['image'];
if (!preg_match('/^(http|https):\/\//', $image_src)) {
// local image -> make absolute url
$image_src = $this->Application->BaseURL() . $image_src;
}
$ret[] = '<img src="' . $image_src . '" alt="' . htmlspecialchars($module_name) . '" title="' . htmlspecialchars($module_name) . '" style="vertical-align:middle; margin: 3px 0 3px 5px"/>';
}
if (array_key_exists('description', $module_info) && $module_info['description']) {
$ret[] = $module_info['description'];
}
else {
$ret[] = $module_name;
}
$ret[] = '(' . $module_name . ' ' . $version_string . ')';
return implode(' ', $ret);
}
/**
* Creates module root category in "Home" category using given data and returns it
*
* @param string $name
* @param string $description
* @param string $category_template
* @param string $category_icon
* @return kDBItem
*/
function &createModuleCategory($name, $description, $category_template = null, $category_icon = null)
{
static $fields = null;
if ( !isset($fields) ) {
$ml_formatter = $this->Application->recallObject('kMultiLanguage');
/* @var $ml_formatter kMultiLanguage */
$fields['name'] = $ml_formatter->LangFieldName('Name');
$fields['description'] = $ml_formatter->LangFieldName('Description');
}
$category = $this->Application->recallObject('c', null, Array ('skip_autoload' => true));
/* @var $category kDBItem */
$category_fields = Array (
$fields['name'] => $name, 'Filename' => $name, 'AutomaticFilename' => 1,
$fields['description'] => $description, 'Status' => STATUS_ACTIVE, 'Priority' => -9999,
// prevents empty link to module category on spearate module install
'NamedParentPath' => 'Content/' . $name,
);
$category_fields['ParentId'] = $this->Application->getBaseCategory();
if ( isset($category_template) ) {
$category_fields['Template'] = $category_template;
$category_fields['CachedTemplate'] = $category_template;
}
if ( isset($category_icon) ) {
$category_fields['UseMenuIconUrl'] = 1;
$category_fields['MenuIconUrl'] = $category_icon;
}
$category->Clear();
$category->SetDBFieldsFromHash($category_fields);
$category->Create();
$priority_helper = $this->Application->recallObject('PriorityHelper');
/* @var $priority_helper kPriorityHelper */
$event = new kEvent('c:OnListBuild');
// ensure, that newly created category has proper value in Priority field
$priority_helper->recalculatePriorities($event, 'ParentId = ' . $category_fields['ParentId']);
// update Priority field in object, becase "CategoriesItem::Update" method will be called
// from "kInstallToolkit::setModuleItemTemplate" and otherwise will set 0 to Priority field
$sql = 'SELECT Priority
FROM ' . $category->TableName . '
WHERE ' . $category->IDField . ' = ' . $category->GetID();
$category->SetDBField('Priority', $this->Conn->GetOne($sql));
return $category;
}
/**
* Sets category item template into custom field for given prefix
*
* @param kDBItem $category
* @param string $prefix
* @param string $item_template
*/
function setModuleItemTemplate(&$category, $prefix, $item_template)
{
$this->Application->removeObject('c-cdata');
// recreate all fields, because custom fields are added during install script
$category->Configure();
$category->SetDBField('cust_' . $prefix .'_ItemTemplate', $item_template);
$category->Update();
}
/**
* Link custom field records with search config records + create custom field columns
*
* @param string $module_folder
* @param string $prefix
* @param int $item_type
*/
function linkCustomFields($module_folder, $prefix, $item_type)
{
$module_folder = strtolower($module_folder);
$module_name = $module_folder;
if ( $module_folder == 'kernel' ) {
$module_name = 'in-portal';
$module_folder = 'core';
}
$db =& $this->Application->GetADODBConnection();
$sql = 'SELECT FieldName, CustomFieldId
FROM ' . TABLE_PREFIX . 'CustomFields
WHERE Type = ' . $item_type . ' AND IsSystem = 0'; // config is not read here yet :( $this->Application->getUnitOption('p', 'ItemType');
$custom_fields = $db->GetCol($sql, 'CustomFieldId');
foreach ($custom_fields as $cf_id => $cf_name) {
$sql = 'UPDATE ' . TABLE_PREFIX . 'SearchConfig
SET CustomFieldId = ' . $cf_id . '
WHERE (TableName = "CustomFields") AND (LOWER(ModuleName) = "' . $module_name . '") AND (FieldName = ' . $db->qstr($cf_name) . ')';
$db->Query($sql);
}
$this->Application->refreshModuleInfo(); // this module configs are now processed
// because of configs was read only from installed before modules (in-portal), then reread configs
$this->Application->UnitConfigReader->scanModules(MODULES_PATH . DIRECTORY_SEPARATOR . $module_folder);
// create correct columns in CustomData table
$ml_helper = $this->Application->recallObject('kMultiLanguageHelper');
/* @var $ml_helper kMultiLanguageHelper */
$ml_helper->createFields($prefix . '-cdata', true);
}
/**
* Deletes cache, useful after separate module install and installator last step
*
* @param bool $refresh_permissions
* @return void
*/
function deleteCache($refresh_permissions = false)
{
$this->Application->HandleEvent(new kEvent('adm:OnResetConfigsCache'));
$this->Application->HandleEvent(new kEvent('adm:OnResetSections'));
$this->Application->HandleEvent(new kEvent('c:OnResetCMSMenuCache'));
$this->Conn->Query('DELETE FROM ' . TABLE_PREFIX . 'CachedUrls');
if ( $refresh_permissions ) {
if ( $this->Application->ConfigValue('QuickCategoryPermissionRebuild') ) {
// refresh permission without progress bar
$updater = $this->Application->makeClass('kPermCacheUpdater');
/* @var $updater kPermCacheUpdater */
$updater->OneStepRun();
}
else {
// refresh permissions with ajax progress bar (when available)
$this->Application->setDBCache('ForcePermCacheUpdate', 1);
}
}
}
/**
* Deletes all temp tables (from active sessions too)
*
*/
function deleteEditTables()
{
$table_prefix = $this->getSystemConfig('Database', 'TablePrefix');
$tables = $this->Conn->GetCol('SHOW TABLES');
$mask_edit_table = '/' . $table_prefix . 'ses_(.*)_edit_(.*)/';
$mask_search_table = '/' . $table_prefix . 'ses_(.*?)_(.*)/';
foreach ($tables as $table) {
if ( preg_match($mask_edit_table, $table, $rets) || preg_match($mask_search_table, $table, $rets) ) {
$this->Conn->Query('DROP TABLE IF EXISTS ' . $table);
}
}
}
/**
* Perform redirect after separate module install
*
* @param string $module_folder
* @param bool $refresh_permissions
*/
function finalizeModuleInstall($module_folder, $refresh_permissions = false)
{
$this->SetModuleVersion(basename($module_folder), $module_folder);
if (!$this->Application->GetVar('redirect')) {
return ;
}
$themes_helper = $this->Application->recallObject('ThemesHelper');
/* @var $themes_helper kThemesHelper */
// use direct query, since module isn't yet in kApplication::ModuleInfo array
$sql = 'SELECT Name
FROM ' . TABLE_PREFIX . 'Modules
WHERE Path = ' . $this->Conn->qstr(rtrim($module_folder, '/') . '/');
$module_name = $this->Conn->GetOne($sql);
$themes_helper->synchronizeModule($module_name);
$ml_helper = $this->Application->recallObject('kMultiLanguageHelper');
/* @var $ml_helper kMultiLanguageHelper */
$ml_helper->massCreateFields();
$this->deleteCache($refresh_permissions);
$url_params = Array (
'pass' => 'm', 'admin' => 1,
'RefreshTree' => 1, 'index_file' => 'index.php',
);
$this->Application->Redirect('modules/modules_list', $url_params);
}
/**
* Performs rebuild of themes
*
*/
function rebuildThemes()
{
$this->Application->HandleEvent(new kEvent('adm:OnRebuildThemes'));
}
/**
* Checks that file is writable by group or others
*
* @param string $file
* @return boolean
*/
function checkWritePermissions($file)
{
if (DIRECTORY_SEPARATOR == '\\') {
// windows doen't allow to check permissions (always returns null)
return null;
}
$permissions = fileperms($file);
return $permissions & 0x0010 || $permissions & 0x0002;
}
/**
* Upgrades primary skin to the latest version
*
* @param Array $module_info
* @return string|bool
*/
function upgradeSkin($module_info)
{
$upgrades_file = sprintf(UPGRADES_FILE, $module_info['Path'], 'css');
$data = file_get_contents($upgrades_file);
// get all versions with their positions in file
$versions = Array ();
preg_match_all('/(' . VERSION_MARK . ')/s', $data, $matches, PREG_SET_ORDER + PREG_OFFSET_CAPTURE);
$from_version_int = $this->ConvertModuleVersion($module_info['FromVersion']);
foreach ($matches as $index => $match) {
$version_int = $this->ConvertModuleVersion($match[2][0]);
if ( $version_int < $from_version_int ) {
// only process versions, that were released after currently used version
continue;
}
$start_pos = $match[0][1] + strlen($match[0][0]);
$end_pos = array_key_exists($index + 1, $matches) ? $matches[$index + 1][0][1] : mb_strlen($data);
$patch_data = str_replace("\r\n", "\n", substr($data, $start_pos, $end_pos - $start_pos));
$versions[] = Array (
'Version' => $match[2][0],
// fixes trimmed leading spaces by modern text editor
'Data' => ltrim( str_replace("\n\n", "\n \n", $patch_data) ),
);
}
if ( !$versions ) {
// not skin changes -> quit
return true;
}
$primary_skin = $this->Application->recallObject('skin.primary', null, Array ('skip_autoload' => true));
/* @var $primary_skin kDBItem */
$primary_skin->Load(1, 'IsPrimary');
if ( !$primary_skin->isLoaded() ) {
// we always got primary skin, but just in case
return false;
}
$temp_handler = $this->Application->recallObject('skin_TempHandler', 'kTempTablesHandler');
/* @var $temp_handler kTempTablesHandler */
// clone current skin
$cloned_ids = $temp_handler->CloneItems('skin', '', Array ($primary_skin->GetID()));
if ( !$cloned_ids ) {
// can't clone
return false;
}
$skin = $this->Application->recallObject('skin.tmp', null, Array ('skip_autoload' => true));
/* @var $skin kDBItem */
$skin->Load($cloned_ids[0]);
// save css to temp file (for patching)
$skin_file = tempnam('/tmp', 'skin_css_');
$fp = fopen($skin_file, 'w');
fwrite($fp, str_replace("\r\n", "\n", $skin->GetDBField('CSS')));
fclose($fp);
$output = Array ();
$patch_file = tempnam('/tmp', 'skin_patch_');
foreach ($versions as $version_info) {
// for each left version get it's patch and apply to temp file
$fp = fopen($patch_file, 'w');
fwrite($fp, $version_info['Data']);
fclose($fp);
$output[ $version_info['Version'] ] = shell_exec('patch ' . $skin_file . ' ' . $patch_file . ' 2>&1') . "\n";
}
// place temp file content into cloned skin
$skin->SetDBField('Name', 'Upgraded to ' . $module_info['ToVersion']);
$skin->SetDBField('CSS', file_get_contents($skin_file));
$skin->Update();
unlink($skin_file);
unlink($patch_file);
$has_errors = false;
foreach ($output as $version => $version_output) {
$version_errors = trim(preg_replace("/(^|\n)(patching file .*?|Hunk #.*?\.)(\n|$)/m", '', $version_output));
if ( $version_errors ) {
$has_errors = true;
$output[$version] = trim(preg_replace("/(^|\n)(patching file .*?)(\n|$)/m", '', $output[$version]));
}
else {
unset($output[$version]);
}
}
if ( !$has_errors ) {
// copy patched css back to primary skin
$primary_skin->SetDBField('CSS', $skin->GetDBField('CSS'));
$primary_skin->Update();
// delete temporary skin record
$temp_handler->DeleteItems('skin', '', Array ($skin->GetID()));
return true;
}
// put clean skin from new version
$skin->SetDBField('CSS', file_get_contents(FULL_PATH . '/core/admin_templates/incs/style_template.css'));
$skin->Update();
// return output in case of errors
return $output;
}
/**
* Returns cache handlers, that are working
*
* @param string $current
* @return Array
*/
public function getWorkingCacheHandlers($current = null)
{
if ( !isset($current) ) {
$current = $this->getSystemConfig('Misc', 'CacheHandler');
}
$cache_handlers = Array (
'Fake' => 'None', 'Memcache' => 'Memcached', 'XCache' => 'XCache', 'Apc' => 'Alternative PHP Cache'
);
foreach ($cache_handlers AS $class_prefix => $title) {
$handler_class = $class_prefix . 'CacheHandler';
if ( !class_exists($handler_class) ) {
unset($cache_handlers[$class_prefix]);
}
else {
$handler = new $handler_class('localhost:11211');
/* @var $handler FakeCacheHandler */
if ( !$handler->isWorking() ) {
if ( $current == $class_prefix ) {
$cache_handlers[$class_prefix] .= ' (offline)';
}
else {
unset($cache_handlers[$class_prefix]);
}
}
}
}
return $cache_handlers;
}
/**
* Returns compression engines, that are working
*
* @param string $current
* @return Array
*/
public function getWorkingCompressionEngines($current = null)
{
if ( !isset($current) ) {
$current = $this->getSystemConfig('Misc', 'CompressionEngine');
}
$output = shell_exec('java -version 2>&1');
$compression_engines = Array ('' => 'None', 'yui' => 'YUICompressor (Java)', 'php' => 'PHP-based');
if ( stripos($output, 'java version') === false ) {
if ( $current == 'yui' ) {
$compression_engines['yui'] .= ' (offline)';
}
else {
unset($compression_engines['yui']);
}
}
return $compression_engines;
}
}
\ No newline at end of file
Event Timeline
Log In to Comment