Page MenuHomeIn-Portal Phabricator

in-portal
No OneTemporary

File Metadata

Created
Thu, Jun 19, 3:15 PM

in-portal

Index: branches/5.2.x/core/kernel/db/db_load_balancer.php
===================================================================
--- branches/5.2.x/core/kernel/db/db_load_balancer.php (revision 14747)
+++ branches/5.2.x/core/kernel/db/db_load_balancer.php (revision 14748)
@@ -1,627 +1,641 @@
<?php
+/**
+* @version $Id$
+* @package In-Portal
+* @copyright Copyright (C) 1997 - 2011 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 kDBLoadBalancer extends kBase {
/**
* Current database type
*
* @var string
* @access protected
*/
protected $dbType = 'mysql';
/**
* Function to handle sql errors
*
* @var string
* @access public
*/
public $errorHandler = '';
/**
* Database connection settings
*
* @var Array
* @access protected
*/
protected $servers = Array ();
/**
* Load of each slave server, given
*
* @var Array
* @access protected
*/
protected $serverLoads = Array ();
/**
* Caches replication lag of servers
*
* @var Array
* @access protected
*/
protected $serverLagTimes = Array ();
/**
* Connection references to opened connections
*
* @var Array
* @access protected
*/
protected $connections = Array ();
/**
* Index of last user slave connection
*
* @var int
* @access protected
*/
protected $slaveIndex = false;
/**
* Index of the server, that was used last
*
* @var int
* @access protected
*/
protected $lastUsedIndex = 0;
/**
* Consider slave down if it isn't responding for N milliseconds
*
* @var int
* @access protected
*/
protected $DBClusterTimeout = 10;
/**
* Scale load balancer polling time so that under overload conditions, the database server
* receives a SHOW STATUS query at an average interval of this many microseconds
*
* @var int
* @access protected
*/
protected $DBAvgStatusPoll = 2000;
/**
* Indicates, that next database query could be cached, when memory caching is enabled
*
* @var bool
* @access public
*/
public $nextQueryCachable = false;
/**
* Indicates, that next query should be sent to maser database
*
* @var bool
*/
public $nextQueryFromMaster = false;
/**
* Creates new instance of load balancer class
*
* @param string $dbType
* @param Array|string $errorHandler
*/
function __construct($dbType, $errorHandler = '')
{
parent::__construct();
$this->dbType = $dbType;
$this->errorHandler = $errorHandler;
$this->DBClusterTimeout *= 1e6; // convert to milliseconds
}
/**
* Setups load balancer according given configuration
*
* @param Array $config
* @return void
* @access public
*/
public function setup($config)
{
$this->servers = Array ();
$this->servers[0] = Array (
'DBHost' => $config['Database']['DBHost'],
'DBUser' => $config['Database']['DBUser'],
'DBUserPassword' => $config['Database']['DBUserPassword'],
'DBName' => $config['Database']['DBName'],
'DBLoad' => 0,
);
if ( isset($config['Databases']) ) {
$this->servers = array_merge($this->servers, $config['Databases']);
}
foreach ($this->servers as $server_index => $server_setting) {
$this->serverLoads[$server_index] = $server_setting['DBLoad'];
}
}
/**
* Returns connection index to master database
*
* @return int
* @access protected
*/
protected function getMasterIndex()
{
return 0;
}
/**
* Returns connection index to slave database. This takes into account load ratios and lag times.
* Side effect: opens connections to databases
*
* @return int
* @access protected
*/
protected function getSlaveIndex()
{
if ( count($this->servers) == 1 || $this->Application->isAdmin ) {
// skip the load balancing if there's only one server OR in admin console
return 0;
}
elseif ( $this->slaveIndex !== false ) {
// shortcut if generic reader exists already
return $this->slaveIndex;
}
$total_elapsed = 0;
$non_error_loads = $this->serverLoads;
$i = $found = $lagged_slave_mode = false;
// first try quickly looking through the available servers for a server that meets our criteria
do {
$current_loads = $non_error_loads;
$overloaded_servers = $total_threads_connected = 0;
while ($current_loads) {
if ( $lagged_slave_mode ) {
// when all slave servers are too lagged, then ignore lag and pick random server
$i = $this->pickRandom($current_loads);
}
else {
$i = $this->getRandomNonLagged($current_loads);
if ( $i === false && $current_loads ) {
// all slaves lagged -> pick random lagged slave then
$lagged_slave_mode = true;
$i = $this->pickRandom( $current_loads );
}
}
if ( $i === false ) {
// all slaves are down -> use master as a slave
$this->slaveIndex = $this->getMasterIndex();
return $this->slaveIndex;
}
$conn =& $this->openConnection($i);
if ( !$conn ) {
unset($non_error_loads[$i], $current_loads[$i]);
continue;
}
// Perform post-connection backoff
$threshold = isset($this->servers[$i]['DBMaxThreads']) ? $this->servers[$i]['DBMaxThreads'] : false;
$backoff = $this->postConnectionBackoff($conn, $threshold);
if ( $backoff ) {
// post-connection overload, don't use this server for now
$total_threads_connected += $backoff;
$overloaded_servers++;
unset( $current_loads[$i] );
}
else {
// return this server
break 2;
}
}
// no server found yet
$i = false;
// if all servers were down, quit now
if ( !$non_error_loads ) {
break;
}
// back off for a while
// scale the sleep time by the number of connected threads, to produce a roughly constant global poll rate
$avg_threads = $total_threads_connected / $overloaded_servers;
usleep($this->DBAvgStatusPoll * $avg_threads);
$total_elapsed += $this->DBAvgStatusPoll * $avg_threads;
} while ( $total_elapsed < $this->DBClusterTimeout );
if ( $i !== false ) {
// slave connection successful
if ( $this->slaveIndex <= 0 && $this->serverLoads[$i] > 0 && $i !== false ) {
$this->slaveIndex = $i;
}
}
return $i;
}
/**
* Returns random non-lagged server
*
* @param Array $loads
* @return int
* @access protected
*/
protected function getRandomNonLagged($loads)
{
// unset excessively lagged servers
$lags = $this->getLagTimes();
foreach ($lags as $i => $lag) {
if ( $i != 0 && isset($this->servers[$i]['DBMaxLag']) ) {
if ( $lag === false ) {
unset( $loads[$i] ); // server is not replicating
}
elseif ( $lag > $this->servers[$i]['DBMaxLag'] ) {
unset( $loads[$i] ); // server is excessively lagged
}
}
}
// find out if all the slaves with non-zero load are lagged
if ( !$loads || array_sum($loads) == 0 ) {
return false;
}
// return a random representative of the remainder
return $this->pickRandom($loads);
}
/**
* Select an element from an array of non-normalised probabilities
*
* @param Array $weights
* @return int
* @access protected
*/
protected function pickRandom($weights)
{
if ( !is_array($weights) || !$weights ) {
return false;
}
$sum = array_sum($weights);
if ( $sum == 0 ) {
return false;
}
$max = mt_getrandmax();
$rand = mt_rand(0, $max) / $max * $sum;
$index = $sum = 0;
foreach ($weights as $index => $weight) {
$sum += $weight;
if ( $sum >= $rand ) {
break;
}
}
return $index;
}
/**
* Get lag time for each server
* Results are cached for a short time in memcached, and indefinitely in the process cache
*
* @return Array
* @access protected
*/
protected function getLagTimes()
{
if ( $this->serverLagTimes ) {
return $this->serverLagTimes;
}
$expiry = 5;
$request_rate = 10;
$cache_key = 'lag_times:' . $this->servers[0]['DBHost'];
$times = $this->Application->getCache($cache_key);
if ( $times ) {
// randomly recache with probability rising over $expiry
$elapsed = adodb_mktime() - $times['timestamp'];
$chance = max(0, ($expiry - $elapsed) * $request_rate);
if ( mt_rand(0, $chance) != 0 ) {
unset( $times['timestamp'] );
$this->serverLagTimes = $times;
return $times;
}
}
// cache key missing or expired
$times = Array();
foreach ($this->servers as $index => $server) {
if ($index == 0) {
$times[$index] = 0; // master
}
else {
$conn =& $this->openConnection($index);
if ($conn !== false) {
$times[$index] = $conn->getSlaveLag();
}
}
}
// add a timestamp key so we know when it was cached
$times['timestamp'] = adodb_mktime();
$this->Application->setCache($cache_key, $times, $expiry);
// but don't give the timestamp to the caller
unset($times['timestamp']);
$this->serverLagTimes = $times;
return $this->serverLagTimes;
}
/**
* Determines whatever server should not be used, even, when connection was made
*
* @param kDBConnection $conn
* @param int $threshold
* @return int
* @access protected
*/
protected function postConnectionBackoff(&$conn, $threshold)
{
if ( !$threshold ) {
return 0;
}
$status = $conn->getStatus('Thread%');
return $status['Threads_running'] > $threshold ? $status['Threads_connected'] : 0;
}
/**
* Open a connection to the server given by the specified index
* Index must be an actual index into the array.
* If the server is already open, returns it.
*
* On error, returns false.
*
* @param integer $i Server index
* @return kDBConnection|false
* @access protected
*/
protected function &openConnection($i)
{
if ( isset($this->connections[$i]) ) {
$conn =& $this->connections[$i];
}
else {
$server = $this->servers[$i];
$server['serverIndex'] = $i;
$conn =& $this->reallyOpenConnection($server);
if ( $conn->connectionOpened ) {
$this->connections[$i] =& $conn;
$this->lastUsedIndex = $i;
}
else {
$conn = false;
}
}
if ( $this->nextQueryCachable && is_object($conn) ) {
$conn->nextQueryCachable = true;
$this->nextQueryCachable = false;
}
return $conn;
}
/**
* Really opens a connection.
* Returns a database object whether or not the connection was successful.
*
* @param Array $server
* @return kDBConnection
*/
protected function &reallyOpenConnection($server)
{
$db =& $this->Application->makeClass( 'kDBConnection', Array ($this->dbType, $this->errorHandler, $server['serverIndex']) );
/* @var $db kDBConnection */
$db->debugMode = $this->Application->isDebugMode();
$db->Connect($server['DBHost'], $server['DBUser'], $server['DBUserPassword'], $this->servers[0]['DBName'], true, true);
return $db;
}
/**
* Returns first field of first line of recordset if query ok or false otherwise
*
* @param string $sql
* @param int $offset
* @return string
* @access public
*/
public function GetOne($sql, $offset = 0)
{
$conn =& $this->chooseConnection($sql);
return $conn->GetOne($sql, $offset);
}
/**
* Returns first row of recordset if query ok, false otherwise
*
* @param string $sql
* @param int $offset
* @return Array
* @access public
*/
public function GetRow($sql, $offset = 0)
{
$conn =& $this->chooseConnection($sql);
return $conn->GetRow($sql, $offset);
}
/**
* Returns 1st column of recordset as one-dimensional array or false otherwise
* Optional parameter $key_field can be used to set field name to be used as resulting array key
*
* @param string $sql
* @param string $key_field
* @return Array
* @access public
*/
public function GetCol($sql, $key_field = null)
{
$conn =& $this->chooseConnection($sql);
return $conn->GetCol($sql, $key_field);
}
/**
* Queries db with $sql query supplied and returns rows selected if any, false
* otherwise. Optional parameter $key_field allows to set one of the query fields
* value as key in string array.
*
* @param string $sql
* @param string $key_field
* @param bool $no_debug
* @return Array
* @access public
*/
public function Query($sql, $key_field = null, $no_debug = false)
{
$conn =& $this->chooseConnection($sql);
return $conn->Query($sql, $key_field, $no_debug);
}
/**
* Performs sql query, that will change database content
*
* @param string $sql
* @return bool
* @access public
*/
public function ChangeQuery($sql)
{
$conn =& $this->chooseConnection($sql);
return $conn->ChangeQuery($sql);
}
/**
* If it's a string, adds quotes and backslashes (only work since PHP 4.3.0)
* Otherwise returns as-is
*
* @param mixed $string
* @return string
* @access public
*/
public function qstr($string)
{
$conn =& $this->openConnection($this->lastUsedIndex);
return $conn->qstr($string);
}
/**
* Performs insert of given data (useful with small number of queries)
* or stores it to perform multiple insert later (useful with large number of queries)
*
* @param Array $fields_hash
* @param string $table
* @param string $type
* @param bool $insert_now
* @return bool
* @access public
*/
public function doInsert($fields_hash, $table, $type = 'INSERT', $insert_now = true)
{
$conn =& $this->openConnection( $this->getMasterIndex() );
return $conn->doInsert($fields_hash, $table, $type, $insert_now);
}
/**
* Update given field values to given record using $key_clause
*
* @param Array $fields_hash
* @param string $table
* @param string $key_clause
* @return bool
* @access public
*/
public function doUpdate($fields_hash, $table, $key_clause)
{
$conn =& $this->openConnection( $this->getMasterIndex() );
return $conn->doUpdate($fields_hash, $table, $key_clause);
}
/**
* When undefined method is called, then send it directly to last used slave server connection
*
* @param string $name
* @param Array $arguments
* @return mixed
* @access public
*/
public function __call($name, $arguments)
{
$conn =& $this->openConnection($this->lastUsedIndex);
return call_user_func_array( Array (&$conn, $name), $arguments );
}
/**
* Returns appropriate connection based on sql
*
* @param string $sql
* @return kDBConnection
* @access protected
*/
protected function &chooseConnection($sql)
{
if ( $this->nextQueryFromMaster ) {
$this->nextQueryFromMaster = false;
$index = $this->getMasterIndex();
}
else {
$sid = isset($this->Application->Session) ? $this->Application->GetSID() : '9999999999999999999999';
if ( preg_match('/(^[ \t\r\n]*(ALTER|CREATE|DROP|RENAME|DELETE|DO|INSERT|LOAD|REPLACE|TRUNCATE|UPDATE))|ses_' . $sid . '/', $sql) ) {
$index = $this->getMasterIndex();
}
else {
$index = $this->getSlaveIndex();
}
}
$this->lastUsedIndex = $index;
$conn =& $this->openConnection($index);
return $conn;
}
}
Index: branches/5.2.x/core/kernel/utility/formatters/filesize_formatter.php
===================================================================
--- branches/5.2.x/core/kernel/utility/formatters/filesize_formatter.php (revision 14747)
+++ branches/5.2.x/core/kernel/utility/formatters/filesize_formatter.php (revision 14748)
@@ -1,47 +1,49 @@
<?php
/**
* @version $Id$
* @package In-Portal
-* @copyright Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
+* @copyright Copyright (C) 1997 - 2011 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 kFilesizeFormatter extends kFormatter {
/**
* Formats value of a given field
*
* @param string $value
* @param string $field_name
* @param kDBItem|kDBList $object
* @param string $format
* @return string
*/
function Format($value, $field_name, &$object, $format=null)
{
if ($value >= 1099511627776) {
$return = round($value / 1024 / 1024 / 1024 / 1024, 2);
$suffix = "Tb";
} elseif ($value >= 1073741824) {
$return = round($value / 1024 / 1024 / 1024, 2);
$suffix = "Gb";
} elseif ($value >= 1048576) {
$return = round($value / 1024 / 1024, 2);
$suffix = "Mb";
} elseif ($value >= 1024) {
$return = round($value / 1024, 2);
$suffix = "Kb";
} else {
$return = $value;
$suffix = "B";
}
$return .= ' '.$suffix;
return $return;
}
}
\ No newline at end of file
Index: branches/5.2.x/core/kernel/utility/formatters/left_formatter.php
===================================================================
--- branches/5.2.x/core/kernel/utility/formatters/left_formatter.php (revision 14747)
+++ branches/5.2.x/core/kernel/utility/formatters/left_formatter.php (revision 14748)
@@ -1,100 +1,102 @@
<?php
/**
* @version $Id$
* @package In-Portal
-* @copyright Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
+* @copyright Copyright (C) 1997 - 2011 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!');
+
/**
* Replacement for kOptionsFormatter in case if options
* should be selected from database. Use this formatter
* only in case if formatter attached field is in edit form.
*
* For usage in grid just use LEFT JOIN clause to table
* where requested options are located.
*/
class kLEFTFormatter extends kFormatter {
/**
* Formats value of a given field
*
* @param string $value
* @param string $field_name
* @param kDBItem|kDBList $object
* @param string $format
* @return string
*/
function Format($value, $field_name, &$object, $format=null)
{
if ( is_null($value) ) {
return '';
}
$options = $object->GetFieldOptions($field_name);
if ( isset($format) ) {
$options['format'] = $format;
}
if ( !isset($options['options'][$value]) ) {
// required option is not defined in config => query for it
$sql = sprintf($options['left_sql'], $options['left_title_field'], $options['left_key_field'], $this->Conn->escape($value));
$options['options'][$value] = $this->Conn->GetOne($sql);
if ( $options['options'][$value] === false ) {
return $value;
}
}
return $options['options'][$value];
}
/**
* Performs basic type validation on form field value
*
* @param mixed $value
* @param string $field_name
* @param kDBItem $object
* @return mixed
* @access public
*/
public function Parse($value, $field_name, &$object)
{
if ( $value == '' ) {
return NULL;
}
$options = $object->GetFieldOptions($field_name);
$found = isset($options['options']) ? array_search($value, $options['options']) : false;
if ( $found !== false ) {
// requested option found among field options
return $found;
}
// requested option is not found in field options -> query for it
$sql = sprintf($options['left_sql'], $options['left_key_field'], $options['left_title_field'], $this->Conn->escape($value));
$found = $this->Conn->GetOne($sql);
if ( $found !== false ) {
// option successfully retrieved from db -> cache it
$options['options'][$found] = $value;
}
$skip_errors = array_key_exists('skip_errors', $options) && $options['skip_errors'];
if ( $found === false && !$skip_errors ) {
// option not found at all -> return not formatted value & set error
$object->SetError($field_name, 'invalid_option', 'la_error_InvalidOption');
return $value;
}
return $found;
}
}
\ No newline at end of file
Index: branches/5.2.x/core/kernel/utility/formatters/options_formatter.php
===================================================================
--- branches/5.2.x/core/kernel/utility/formatters/options_formatter.php (revision 14747)
+++ branches/5.2.x/core/kernel/utility/formatters/options_formatter.php (revision 14748)
@@ -1,114 +1,116 @@
<?php
/**
* @version $Id$
* @package In-Portal
-* @copyright Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
+* @copyright Copyright (C) 1997 - 2011 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 kOptionsFormatter extends kFormatter {
/**
* Formats value of a given field
*
* @param string $value
* @param string $field_name
* @param kDBItem|kDBList $object
* @param string $format
* @return string
*/
function Format($value, $field_name, &$object, $format=null)
{
if ( is_null($value) ) {
return '';
}
$field_options = $object->GetFieldOptions($field_name);
if (!array_key_exists('options', $field_options) || !is_array($field_options['options'])) {
trigger_error('Options not defined for <strong>'.$object->Prefix.'</strong> field <strong>'.$field_name.'</strong>', E_USER_WARNING);
return $value;
}
$options = $field_options['options'];
$use_phrases = array_key_exists('use_phrases', $field_options) ? $field_options['use_phrases'] : false;
if (strpos($value, '|') !== false) {
// multiple checkboxes OR multiselect
$values = Array ();
$values_unsorted = explode('|', substr($value, 1, -1) );
// 1. sort values using options order from unit config
$key_indexes = array_keys($options);
foreach ($values_unsorted as $value) {
$values[ array_search($value, $key_indexes) ] = $value;
}
ksort($values);
// 2. convert values to titles
$labels = Array ();
foreach ($values as $value) {
$label = $this->formatOption($value, $options, $use_phrases);
if ($label) {
$labels[] = $label;
}
}
return implode($format, $labels);
}
else {
return $this->formatOption($value, $options, $use_phrases);
}
}
function formatOption($value, $options, $use_phrases = true)
{
$label = getArrayValue($options, $value);
if ($label !== false) {
// option_id found in options array
return $use_phrases ? $this->Application->Phrase($label) : $label;
}
else {
// option_id not found
return "$value" == "0" ? '' : $value;
}
}
/**
* Performs basic type validation on form field value
*
* @param mixed $value
* @param string $field_name
* @param kDBItem $object
* @return mixed
* @access public
*/
public function Parse($value, $field_name, &$object)
{
if ( $value == '' ) {
return NULL;
}
$found = $option_key = false;
$options = $object->GetFieldOptions($field_name);
$use_phrases = getArrayValue($options, 'use_phrases');
foreach ($options['options'] as $option_key => $option_value) {
if ( $use_phrases ) {
$option_value = $this->Application->Phrase($option_value);
}
if ( $option_value == $value ) {
$found = true;
break;
}
}
return $found ? $option_key : $value;
}
}
\ No newline at end of file
Index: branches/5.2.x/core/kernel/utility/formatters/serialized_formatter.php
===================================================================
--- branches/5.2.x/core/kernel/utility/formatters/serialized_formatter.php (revision 14747)
+++ branches/5.2.x/core/kernel/utility/formatters/serialized_formatter.php (revision 14748)
@@ -1,51 +1,53 @@
<?php
/**
* @version $Id$
* @package In-Portal
-* @copyright Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
+* @copyright Copyright (C) 1997 - 2011 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 kSerializedFormatter extends kFormatter {
/**
* Performs basic type validation on form field value
*
* @param mixed $value
* @param string $field_name
* @param kDBItem $object
* @return mixed
* @access public
*/
public function Parse($value, $field_name, &$object)
{
$options = $object->GetFieldOptions($field_name);
$value = kUtil::array_merge_recursive(unserialize($options['default']), $value);
return serialize($value);
}
/**
* Formats value of a given field
*
* @param string $value
* @param string $field_name
* @param kDBItem|kDBList $object
* @param string $format
* @return string
*/
function Format($value, $field_name, &$object, $format = null)
{
$data = unserialize($value);
$format = explode('.', $format);
$format = '\''.implode('\', \'', $format).'\'';
return eval('return getArrayValue($data, '.$format.');');
}
}
Index: branches/5.2.x/core/kernel/utility/formatters/multilang_formatter.php
===================================================================
--- branches/5.2.x/core/kernel/utility/formatters/multilang_formatter.php (revision 14747)
+++ branches/5.2.x/core/kernel/utility/formatters/multilang_formatter.php (revision 14748)
@@ -1,320 +1,322 @@
<?php
/**
* @version $Id$
* @package In-Portal
-* @copyright Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
+* @copyright Copyright (C) 1997 - 2011 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 kMultiLanguage extends kFormatter
{
/**
* Multilanguage helper
*
* @var kMultiLanguageHelper
*/
var $helper = null;
public function __construct()
{
parent::__construct();
$this->helper =& $this->Application->recallObject('kMultiLanguageHelper');
}
/**
* Returns ML field equivalent to field name specifed
*
* @param string $field_name
* @param bool $from_primary use primary/current language for name custruction
* @return string
*/
function LangFieldName($field_name, $from_primary = false)
{
static $primary_language = null;
if (preg_match('/^l[0-9]+_/', $field_name)) {
return $field_name;
}
if (!isset($primary_language)) {
$primary_language = $this->Application->GetDefaultLanguageId();
}
$lang = $from_primary ? $primary_language : $this->Application->GetVar('m_lang');
if (!$lang || ($lang == 'default')) {
$lang = $primary_language;
}
return 'l' . $lang . '_' . $field_name;
}
/**
* The method is supposed to alter config options or cofigure object in some way based on its usage of formatters
* The methods is called for every field with formatter defined when configuring item.
* Could be used for adding additional VirtualFields to an object required by some special Formatter
*
* @param string $field_name
* @param array $field_options
* @param kDBBase $object
*/
function PrepareOptions($field_name, &$field_options, &$object)
{
if (getArrayValue($field_options, 'master_field') || getArrayValue($field_options, 'options_processed')) {
return ;
}
$lang_field_name = $this->LangFieldName($field_name);
//substitute title field
$title_field = $this->Application->getUnitOption($object->Prefix, 'TitleField');
if ($title_field == $field_name) {
$this->Application->setUnitOption($object->Prefix, 'TitleField', $lang_field_name);
}
$languages = $this->helper->getLanguages();
$primary_language_id = $this->Application->GetDefaultLanguageId();
$fields = $this->Application->getUnitOption($object->Prefix, 'Fields', Array ());
$virtual_fields = $this->Application->getUnitOption($object->Prefix, 'VirtualFields', Array ());
// substitute real field
if (array_key_exists($field_name, $fields)) {
$tmp_field_options = $fields[$field_name];
$tmp_field_options['master_field'] = $field_name;
$tmp_field_options['error_field'] = $field_name;
$field_required = array_key_exists('required', $tmp_field_options) && $tmp_field_options['required'];
foreach ($languages as $language_id) {
// make all non-primary language fields not required
if ($language_id != $primary_language_id) {
unset($tmp_field_options['required']);
}
elseif ($field_required) {
$tmp_field_options['required'] = $field_required;
}
$translated_field = 'l' . $language_id . '_' . $field_name;
$fields[$translated_field] = $tmp_field_options;
$object->SetFieldOptions($translated_field, $tmp_field_options);
}
// makes original field non-required
$object_fields = $object->getFields(); // use kDBBase::getFields, since there are no kDBList::setRequired
unset($fields[$field_name]['required'], $object_fields[$field_name]['required']);
$object->setFields($object_fields);
// prevents real field with formatter set to be saved in db
$virtual_fields[$field_name] = $object_fields[$field_name];
$object->SetFieldOptions($field_name, $object_fields[$field_name], true);
}
elseif (array_key_exists($field_name, $virtual_fields)) {
// substitute virtual field
$calculated_fields = $this->Application->getUnitOption($object->Prefix, 'CalculatedFields', Array ());
$calculated_field_special = array_key_exists($object->Special, $calculated_fields) ? $object->Special : (array_key_exists('', $calculated_fields) ? '' : false);
/* @var $calculated_fields Array */
$tmp_field_options = $virtual_fields[$field_name];
$tmp_field_options['master_field'] = $field_name;
$tmp_field_options['error_field'] = $field_name;
$field_required = array_key_exists('required', $tmp_field_options) && $tmp_field_options['required'];
foreach ($languages as $language_id) {
// make all non-primary language fields not required
if ($language_id != $primary_language_id) {
unset($tmp_field_options['required']);
}
elseif ($field_required) {
$tmp_field_options['required'] = $field_required;
}
$translated_field = 'l' . $language_id . '_' . $field_name;
$virtual_fields[$translated_field] = $tmp_field_options;
$object->SetFieldOptions($translated_field, $tmp_field_options, true);
// substitute calculated fields associated with given virtual field
foreach ($calculated_fields as $special => $special_fields) {
if (!array_key_exists($field_name, $special_fields)) {
continue;
}
$calculated_fields[$special][$translated_field] = str_replace('%2$s', $language_id, $special_fields[$field_name]);
if ($special === $calculated_field_special) {
$object->addCalculatedField($translated_field, $calculated_fields[$special][$translated_field]);
}
}
// manually copy virtual field back to fields (see kDBBase::setVirtualFields about that)
$fields[$translated_field] = $tmp_field_options;
$object->SetFieldOptions($translated_field, $tmp_field_options);
}
// remove original calculated field
foreach ($calculated_fields as $special => $special_fields) {
unset($calculated_fields[$special][$field_name]);
}
$object_calculated_fields = $object->getCalculatedFields();
unset($object_calculated_fields[$field_name]);
$object->setCalculatedFields($object_calculated_fields);
// save back calculated fields
$this->Application->setUnitOption($object->Prefix, 'CalculatedFields', $calculated_fields);
// makes original field non-required
$object_fields = $object->getFields(); // use kDBBase::getFields, since there are no kDBList::setRequired
unset($fields[$field_name]['required'], $object_fields[$field_name]['required']);
$object->setFields($object_fields);
$virtual_field_options = $object->GetFieldOptions($field_name, true);
unset($virtual_fields[$field_name]['required'], $virtual_field_options['required']);
$object->SetFieldOptions($field_name, $virtual_field_options, true);
}
// substitute grid fields
$grids = $this->Application->getUnitOption($object->Prefix, 'Grids', Array ());
/* @var $grids Array */
foreach ($grids as $name => $grid) {
if ( getArrayValue($grid, 'Fields', $field_name) ) {
// used by column picker to track column position
$grids[$name]['Fields'][$field_name]['formatter_renamed'] = true;
if (!array_key_exists('format', $grids[$name]['Fields'][$field_name])) {
// prevent displaying value from primary language
// instead of missing value in current language
$grids[$name]['Fields'][$field_name]['format'] = 'no_default';
}
if ( !isset($grid['Fields'][$field_name]['title']) ) {
$grids[$name]['Fields'][$field_name]['title'] = 'column:la_fld_' . $field_name;
}
kUtil::array_rename_key($grids[$name]['Fields'], $field_name, $lang_field_name);
}
// update sort fields - used for sorting and filtering in SQLs
foreach ($grid['Fields'] as $grid_fld_name => $fld_options) {
if (isset($fld_options['sort_field']) && $fld_options['sort_field'] == $field_name) {
$grids[$name]['Fields'][$grid_fld_name]['sort_field'] = $lang_field_name;
}
}
}
$this->Application->setUnitOption($object->Prefix, 'Grids', $grids);
// substitute default sortings
$sortings = $this->Application->getUnitOption($object->Prefix, 'ListSortings', Array ());
/* @var $sortings Array */
foreach ($sortings as $special => $the_sortings) {
if (isset($the_sortings['ForcedSorting'])) {
kUtil::array_rename_key($sortings[$special]['ForcedSorting'], $field_name, $lang_field_name);
}
if (isset($the_sortings['Sorting'])) {
kUtil::array_rename_key($sortings[$special]['Sorting'], $field_name, $lang_field_name);
}
}
$this->Application->setUnitOption($object->Prefix, 'ListSortings', $sortings);
// TODO: substitute possible language-fields sortings after changing language
$fields[$field_name]['options_processed'] = $field_options['options_processed'] = true;
$this->Application->setUnitOption($object->Prefix, 'Fields', $fields);
$this->Application->setUnitOption($object->Prefix, 'VirtualFields', $virtual_fields);
}
/*function UpdateSubFields($field, $value, &$options, &$object)
{
}
*/
/**
* Checks, that field value on primary language is set
*
* @param string $field
* @param mixed $value
* @param Array $options
* @param kDBItem $object
*/
function UpdateMasterFields($field, $value, &$options, &$object)
{
$master_field = array_key_exists('master_field', $options) ? $options['master_field'] : false;
if (!$master_field) {
return ;
}
// moved here from Parse, because at Parse time not all of the fields may be set - this is extremly actual, when working with PopulateMlFields mode
$lang = $this->Application->GetVar('m_lang');
$def_lang = $this->Application->GetDefaultLanguageId();
if ( !$this->Application->GetVar('allow_translation') && ($lang != $def_lang) && $object->isRequired($field) ) {
$def_lang_field = 'l' . $def_lang . '_' . $master_field;
if ( !$object->ValidateRequired($def_lang_field, $options) ) {
$object->SetError($master_field, 'primary_lang_required');
if ( $object->isField($def_lang_field) ) {
$object->SetError($def_lang_field, 'primary_lang_required');
}
}
}
}
/**
* Formats value of a given field
*
* @param string $value
* @param string $field_name
* @param kDBItem|kDBList $object
* @param string $format
* @return string
*/
function Format($value, $field_name, &$object, $format=null)
{
$master_field = $object->GetFieldOption($field_name, 'master_field');
if (!$master_field) { // if THIS field is master it does NOT have reference to it's master_field
$lang = $this->Application->GetVar('m_lang');
$value = $object->GetDBField('l'.$lang.'_'.$field_name); //getting value of current language
$master_field = $field_name; // THIS is master_field
}
$options = $object->GetFieldOptions($field_name);
$format = isset($format) ? $format : ( isset($options['format']) ? $options['format'] : null);
// use strpos, becase 2 comma-separated formats could be specified
if ($value == '' && strpos($format, 'no_default') === false) { // try to get default language value
$def_lang_value = $object->GetDBField('l'.$this->Application->GetDefaultLanguageId().'_'.$master_field);
if ($def_lang_value == '') {
return NULL;
}
return $this->_replaceFCKLinks($def_lang_value, $options, $format); //return value from default language
}
return $this->_replaceFCKLinks($value, $options, $format);
}
/**
* Performs required field check on primary language
*
* @param mixed $value
* @param string $field_name
* @param kDBItem $object
* @return mixed
* @access public
*/
public function Parse($value, $field_name, &$object)
{
if ($value == '') return NULL;
return $value;
}
}
\ No newline at end of file
Index: branches/5.2.x/core/kernel/utility/formatters/date_formatter.php
===================================================================
--- branches/5.2.x/core/kernel/utility/formatters/date_formatter.php (revision 14747)
+++ branches/5.2.x/core/kernel/utility/formatters/date_formatter.php (revision 14748)
@@ -1,507 +1,509 @@
<?php
/**
* @version $Id$
* @package In-Portal
-* @copyright Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
+* @copyright Copyright (C) 1997 - 2011 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 kDateFormatter extends kFormatter {
/**
* Current Language
*
* @var LanguagesItem
*/
var $language = null;
/**
* Create date formatter
*
* @access public
*/
public function __construct()
{
parent::__construct();
$this->language =& $this->Application->recallObject('lang.current');
}
/**
* Sets mixed format (date + time) for field if not set directly
*
* @param Array $field_options options of field
* @param Array $format separate formats for date & time
* @param string $type destination key in field_options to store mixed format
*/
function SetMixedFormat(&$field_options, &$format, $type)
{
if (!isset($field_options[$type])) {
// default value is date+separator+time
$field_options[$type] = '_regional_DateTimeFormat';
}
if ($field_options[$type] == '_regional_DateTimeFormat') {
$field_options[$type] = $format['date'].$field_options['date_time_separator'].$format['time'];
}
else if(preg_match('/_regional_(.*)/', $field_options[$type], $regs)) {
$field_options[$type] = $this->language->GetDBField($regs[1]);
}
$format['mixed'] = $field_options[$type];
}
/**
* Returns separate formats for date,time,combined for input & display formats
*
* @param Array $field_options options of field
* @param string $type type of requested information = {mixed,date,time}
* @return Array display & input formats
*/
function GetSeparateFormats(&$field_options, $type)
{
if ($type == 'mixed') {
if (!isset($field_options['date_time_separator'])) $field_options['date_time_separator'] = ' ';
$display_format = Array ();
$input_format = Array ();
list ($display_format['date'], $input_format['date']) = $this->GetSeparateFormats($field_options, 'date');
list ($display_format['time'], $input_format['time']) = $this->GetSeparateFormats($field_options, 'time');
$this->SetMixedFormat($field_options, $display_format, 'format');
$this->SetMixedFormat($field_options, $input_format, 'input_format');
return Array ($display_format, $input_format);
}
else {
// 1. set display format
if (isset($field_options[$type.'_format'])) {
$format = $field_options[$type.'_format'];
}
else {
$format = $this->language->GetDBField(ucfirst($type).'Format');
}
// 2. set input format
if (isset($field_options['input_'.$type.'_format'])) {
$input_format = $field_options['input_'.$type.'_format'];
}
else {
$input_format = $this->language->GetDBField('Input'.ucfirst($type).'Format');
}
return Array ($format, $input_format);
}
}
/**
* The method is supposed to alter config options or configure object in some way based on its usage of formatters
* The methods is called for every field with formatter defined when configuring item.
* Could be used for adding additional VirtualFields to an object required by some special Formatter
*
* @param string $field_name
* @param array $field_options
* @param kDBBase $object
*/
function PrepareOptions($field_name, &$field_options, &$object)
{
list ($display_format, $input_format) = $this->GetSeparateFormats($field_options, 'mixed');
$field_options['sub_fields'] = Array('date' => $field_name.'_date', 'time' => $field_name.'_time');
if (!isset($field_options['use_timezone'])) {
// apply timezone from server
$field_options['use_timezone'] = true;
}
// 1. add field to indicate, that date is already combined into one field
$add_fields = Array (
$field_name . '_combined' => Array ('type' => 'int', 'default' => 0),
);
// 2. add DATE virtual field
$opts = Array('master_field' => $field_name, 'formatter' => 'kDateFormatter', 'format' => $display_format['date'], 'input_format' => $input_format['date']);
$copy_options = Array ('type', 'default', 'required', 'use_timezone', 'error_msgs');
foreach ($copy_options as $copy_option) {
if ( array_key_exists($copy_option, $field_options) ) {
$opts[$copy_option] = $field_options[$copy_option];
}
}
$add_fields[$field_name . '_date'] = $opts;
// 3. add TIME virtual field
$opts['format'] = $display_format['time'];
$opts['input_format'] = $input_format['time'];
$add_fields[$field_name . '_time'] = $opts;
$filter_type = getArrayValue($field_options, 'filter_type');
if ( $filter_type == 'range' ) {
$opts['format'] = $field_options['format'];
$add_fields[$field_name . '_rangefrom'] = $opts;
$add_fields[$field_name . '_rangeto'] = $opts;
}
if ( !$object->isVirtualField($field_name) ) {
// adding calculated field to format date directly in the query
$object->addCalculatedField($field_name . '_date', '%1$s.' . $field_name);
$object->addCalculatedField($field_name . '_time', '%1$s.' . $field_name);
}
$virtual_fields = $object->getVirtualFields();
$add_fields = kUtil::array_merge_recursive($add_fields, $virtual_fields);
$object->setVirtualFields($add_fields);
}
/**
* Used for split fields like timestamp -> date, time
* Called from DBItem to update sub fields values after loading item
*
* @param string $field
* @param string $value
* @param Array $options
* @param kDBItem $object
* @return void
* @access public
*/
public function UpdateSubFields($field, $value, &$options, &$object)
{
$sub_fields = getArrayValue($options, 'sub_fields');
if ( !$sub_fields || !isset($value) || !$value ) {
return ;
}
$object->SetDBField($sub_fields['date'], $value);
$object->SetDBField($sub_fields['time'], $value);
}
/**
* Used for split fields like timestamp -> date, time
* Called from DBItem Validate (before validation) to get back master field value from its sub_fields
*
* @param string $field
* @param mixed $value
* @param Array $options
* @param kDBItem $object
*/
function UpdateMasterFields($field, $value, &$options, &$object)
{
$sub_fields = getArrayValue($options, 'sub_fields');
$master_field = getArrayValue($options, 'master_field');
if ( $master_field ) {
// when in one of sub_fields - call update for master_field to update its value from sub_fields [are you following ? :) ]
$opt = $object->GetFieldOptions($master_field);
$this->UpdateMasterFields($master_field, null, $opt, $object);
}
elseif ( $sub_fields && !$object->GetDBField($field . '_combined') ) {
// when in master field - set own value from sub_fields
if ( $object->GetDBField($sub_fields['date']) != '' && $object->GetDBField($sub_fields['time']) == '' ) {
// when time is not supplied, then use "midnight" (or unit config override)
$empty_time = getArrayValue($options, 'empty_time');
if ( $empty_time === false ) {
$empty_time = adodb_mktime(0, 0, 0);
}
$object->SetDBField($sub_fields['time'], $empty_time);
}
elseif ( $object->GetDBField($sub_fields['time']) != '' && $object->GetDBField($sub_fields['date']) == '' ) {
// when date is not supplied, then use "1970-01-01 00:00:00" instead (or unit config override)
$empty_date = getArrayValue($options, 'empty_date');
if ( $empty_date === false ) {
$empty_date = adodb_mktime(0, 0, 0, 1, 1, 1970);
}
$object->SetDBField($sub_fields['date'], $empty_date);
}
$input_format['date'] = $object->GetFieldOption($sub_fields['date'], 'input_format');
$input_format['time'] = $object->GetFieldOption($sub_fields['time'], 'input_format');
$object->SetField($field, $object->GetField($sub_fields['date'], $input_format['date']) . $options['date_time_separator'] . $object->GetField($sub_fields['time'], $input_format['time']));
}
}
/**
* Formats value of a given field
*
* @param string $value
* @param string $field_name
* @param kDBItem|kDBList $object
* @param string $format
* @return string
*/
function Format($value, $field_name, &$object, $format=null)
{
if ( is_null($value) ) return '';
if ( !is_numeric($value) ) {
return $value; // for leaving badly formatted date on the form
}
settype($value, 'int');
if ( !is_int($value) ) {
return $value;
}
$options = $object->GetFieldOptions($field_name);
if ( isset($format) ) {
$options['format'] = $format;
}
if (preg_match('/_regional_(.*)/', $options['format'], $regs)) {
// when such type of format is given directly to kDBBase::GetField
$options['format'] = $this->language->GetDBField($regs[1]);
}
if ($options['format'] == '_input_') {
// use input format instead of output format
$options['format'] = $options['input_format'];
}
if (!$options['use_timezone']) {
return adodb_gmdate($options['format'], $value);
}
$format = defined($options['format']) ? constant($options['format']) : $options['format'];
$dt_separator = getArrayValue($options, 'date_time_separator');
if ($dt_separator) {
$format = trim($format, $dt_separator);
}
return adodb_date($format, $value);
}
function HumanFormat($format)
{
$patterns = Array('/m/',
'/n/',
'/d/',
'/j/',
'/y/',
'/Y/',
'/h|H/',
'/g|G/',
'/i/',
'/s/',
'/a|A/');
$replace = Array( 'mm',
'm',
'dd',
'd',
'yy',
'yyyy',
'hh',
'h',
'mm',
'ss',
'AM');
$res = preg_replace($patterns, $replace, $format);
return $res;
}
function SQLFormat($format)
{
$mapping = Array(
'/%/' => '%%',
'/(?<!%)a/' => '%p', // Lowercase Ante meridiem and Post meridiem => MySQL provides only uppercase
'/(?<!%)A/' => '%p', // Uppercase Ante meridiem and Post meridiem
'/(?<!%)d/' => '%d', // Day of the month, 2 digits with leading zeros
'/(?<!%)D/' => '%a', // A textual representation of a day, three letters
'/(?<!%)F/' => '%M', // A full textual representation of a month, such as January or March
'/(?<!%)g/' => '%l', // 12-hour format of an hour without leading zeros
'/(?<!%)G/' => '%k', // 24-hour format of an hour without leading zeros
'/(?<!%)h/' => '%h', // 12-hour format of an hour with leading zeros
'/(?<!%)H/' => '%H', // 24-hour format of an hour with leading zeros
'/(?<!%)i/' => '%i', // Minutes with leading zeros
'/(?<!%)I/' => 'N/A', // Whether or not the date is in daylights savings time
'/(?<!%)S/' => 'N/A', // English ordinal suffix for the day of the month, 2 characters, see below
'/jS/' => '%D', // MySQL can't return separate suffix, but could return date with suffix
'/(?<!%)j/' => '%e', // Day of the month without leading zeros
'/(?<!%)l/' => '%W', // A full textual representation of the day of the week
'/(?<!%)L/' => 'N/A', // Whether it's a leap year
'/(?<!%)m/' => '%m', // Numeric representation of a month, with leading zeros
'/(?<!%)M/' => '%b', // A short textual representation of a month, three letters
'/(?<!%)n/' => '%c', // Numeric representation of a month, without leading zeros
'/(?<!%)O/' => 'N/A', // Difference to Greenwich time (GMT) in hours
'/(?<!%)r/' => 'N/A', // RFC 2822 formatted date
'/(?<!%)s/' => '%s', // Seconds, with leading zeros
// S and jS moved before j - see above
'/(?<!%)t/' => 'N/A', // Number of days in the given month
'/(?<!%)T/' => 'N/A', // Timezone setting of this machine
'/(?<!%)U/' => 'N/A', // Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT)
'/(?<!%)w/' => '%w', // Numeric representation of the day of the week
'/(?<!%)W/' => '%v', // ISO-8601 week number of year, weeks starting on Monday (added in PHP 4.1.0)
'/(?<!%)Y/' => '%Y', // A full numeric representation of a year, 4 digits
'/(?<!%)y/' => '%y', // A two digit representation of a year
'/(?<!%)z/' => 'N/A', // The day of the year (starting from 0) => MySQL starts from 1
'/(?<!%)Z/' => 'N/A', // Timezone offset in seconds. The offset for timezones west of UTC is always negative, and for those east of UTC is always positive.
);
$patterns = array_keys($mapping);
$replacements = array_values($mapping);
$res = preg_replace($patterns, $replacements, $format);
return $res;
}
/**
* Converts formatted date+time to timestamp and validates format
*
* @param mixed $value
* @param string $field_name
* @param kDBItem $object
* @return mixed
* @access public
*/
public function Parse($value, $field_name, &$object)
{
$options = $object->GetFieldOptions($field_name);
$dt_separator = getArrayValue($options,'date_time_separator');
if($dt_separator) $value = trim($value, $dt_separator);
if($value == '') return NULL;
//return strtotime($value);
$format = $options['input_format'];
if ($dt_separator) $format = trim($format, $dt_separator);
$error_params = Array( $this->HumanFormat($format), adodb_date($format), 'value' => $value );
$hour = 0;
$minute = 0;
$second = 0;
$month = 1;
$day = 1;
$year = 1970;
$patterns['n'] = '([0-9]{1,2})';
$patterns['m'] = '([0-9]{1,2})';
$patterns['d'] = '([0-9]{1,2})';
$patterns['j'] = '([0-9]{1,2})';
$patterns['Y'] = '([0-9]{4})';
$patterns['y'] = '([0-9]{2})';
$patterns['G'] = '([0-9]{1,2})';
$patterns['g'] = '([0-9]{1,2})';
$patterns['H'] = '([0-9]{2})';
$patterns['h'] = '([0-9]{2})';
$patterns['i'] = '([0-9]{2})';
$patterns['s'] = '([0-9]{2})';
$patterns['a'] = '(am|pm)';
$patterns['A'] = '(AM|PM)';
$holders_mask = '/' . preg_replace('/[a-zA-Z]{1}/i', '([a-zA-Z]{1})', preg_quote($format, '/')) . '/';
if (!preg_match($holders_mask, $format, $holders)) {
$object->SetError($field_name, 'bad_date_format', null, $error_params);
return $value;
}
$values_mask = '/^' . preg_quote($format, '/') . '$/';
foreach ($patterns as $key => $val) {
$values_mask = str_replace($key, $val, $values_mask);
}
if (!preg_match($values_mask, $value, $values)) {
$object->SetError($field_name, 'bad_date_format', null, $error_params);
return $value;
}
for ($i = 1; $i < count($holders); $i++) {
switch ($holders[$i]) {
case 'n':
case 'm':
$month = $values[$i];
$month = preg_replace('/^0{1}/', '', $month);
break;
case 'd':
$day = $values[$i];
$day = preg_replace('/^0{1}/', '', $day);
break;
case 'Y':
$year = $values[$i];
break;
case 'y':
$year = $values[$i] >= 70 ? 1900 + $values[$i] : 2000 + $values[$i];
break;
case 'H':
case 'h':
case 'G':
case 'g':
$hour = $values[$i];
$hour = preg_replace('/^0{1}/', '', $hour);
break;
case 'i':
$minute = $values[$i];
$minute = preg_replace('/^0{1}/', '', $minute);
break;
case 's':
$second = $values[$i];
$second = preg_replace('/^0{1}/', '', $second);
break;
case 'a':
case 'A':
if ($hour <= 12) { // if AM/PM used with 24-hour - could happen :)
if ($values[$i] == 'pm' || $values[$i] == 'PM') {
$hour += 12;
if ($hour == 24) $hour = 12;
}
elseif ($values[$i] == 'am' || $values[$i] == 'AM') {
if ($hour == 12) $hour = 0;
}
}
break;
}
}
//echo "day: $day, month: $month, year: $year, hour: $hour, minute: $minute<br>";
/*if (!($year >= 1970 && $year <= 2037)) {
$object->SetError($field_name, 'bad_date_format', null, $error_params);
return $value;
}*/
if (!($month >= 1 && $month <= 12)) {
$object->SetError($field_name, 'bad_date_format', null, $error_params);
return $value;
}
$months_days = Array ( 1 => 31,2 => 28, 3 => 31, 4 => 30,5 => 31,6 => 30, 7 => 31, 8 => 31,9 => 30,10 => 31,11 => 30,12 => 31);
if ($year % 4 == 0) $months_days[2] = 29;
if (!($day >=1 && $day <= $months_days[$month])) {
$object->SetError($field_name, 'bad_date_format', null, $error_params);
return $value;
}
if (!($hour >=0 && $hour <= 23)) {
$object->SetError($field_name, 'bad_date_format', null, $error_params);
return $value;
}
if (!($minute >=0 && $minute <= 59)) {
$object->SetError($field_name, 'bad_date_format', null, $error_params);
return $value;
}
if (!($second >=0 && $second <= 59)) {
$object->SetError($field_name, 'bad_date_format', null, $error_params);
return $value;
}
if (!$options['use_timezone']) {
return adodb_gmmktime($hour, $minute, $second, $month, $day, $year);
}
return adodb_mktime($hour, $minute, $second, $month, $day, $year);
}
function GetSample($field, &$options, &$object)
{
return $this->Format( adodb_mktime(), $field, $object, $options['input_format']);
}
}
\ No newline at end of file
Index: branches/5.2.x/core/kernel/utility/formatters/customfield_formatter.php
===================================================================
--- branches/5.2.x/core/kernel/utility/formatters/customfield_formatter.php (revision 14747)
+++ branches/5.2.x/core/kernel/utility/formatters/customfield_formatter.php (revision 14748)
@@ -1,51 +1,53 @@
<?php
/**
* @version $Id$
* @package In-Portal
-* @copyright Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
+* @copyright Copyright (C) 1997 - 2011 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!');
+
+/**
+ * Like kMultiLanguage formatter for LEFT JOINed custom fields
+ *
+ */
+class kCustomFieldFormatter extends kFormatter
+{
+
/**
- * Like kMultiLanguage formatter for LEFT JOINed custom fields
+ * Formats value of a given field
*
+ * @param string $value
+ * @param string $field_name
+ * @param kDBItem|kDBList $object
+ * @param string $format
+ * @return string
*/
- class kCustomFieldFormatter extends kFormatter
+ function Format($value, $field_name, &$object, $format=null)
{
+ $options = $object->GetFieldOptions($field_name);
- /**
- * Formats value of a given field
- *
- * @param string $value
- * @param string $field_name
- * @param kDBItem|kDBList $object
- * @param string $format
- * @return string
- */
- function Format($value, $field_name, &$object, $format=null)
- {
- $options = $object->GetFieldOptions($field_name);
-
- $master_field = isset($options['master_field']) ? $options['master_field'] : false;
- if (!$master_field) {
- return $value;
- }
-
- $format = isset($format) ? $format : ( isset($options['format']) ? $options['format'] : null);
-
- if ($value == '' && $format != 'no_default') { // try to get default language value
- $def_lang_value = $object->GetDBField($master_field);
- if ($def_lang_value == '') return NULL;
- return $def_lang_value; //return value from default language
- }
-
+ $master_field = isset($options['master_field']) ? $options['master_field'] : false;
+ if (!$master_field) {
return $value;
}
- }
\ No newline at end of file
+ $format = isset($format) ? $format : ( isset($options['format']) ? $options['format'] : null);
+
+ if ($value == '' && $format != 'no_default') { // try to get default language value
+ $def_lang_value = $object->GetDBField($master_field);
+ if ($def_lang_value == '') return NULL;
+ return $def_lang_value; //return value from default language
+ }
+
+ return $value;
+ }
+
+}
\ No newline at end of file
Index: branches/5.2.x/core/kernel/utility/formatters/unit_formatter.php
===================================================================
--- branches/5.2.x/core/kernel/utility/formatters/unit_formatter.php (revision 14747)
+++ branches/5.2.x/core/kernel/utility/formatters/unit_formatter.php (revision 14748)
@@ -1,129 +1,131 @@
<?php
/**
* @version $Id$
* @package In-Portal
-* @copyright Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
+* @copyright Copyright (C) 1997 - 2011 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 kUnitFormatter extends kFormatter {
/**
* The method is supposed to alter config options or cofigure object in some way based on its usage of formatters
* The methods is called for every field with formatter defined when configuring item.
* Could be used for adding additional VirtualFields to an object required by some special Formatter
*
* @param string $field_name
* @param array $field_options
* @param kDBBase $object
*/
function PrepareOptions($field_name, &$field_options, &$object)
{
if( !isset($field_options['master_field']) )
{
$regional =& $this->Application->recallObject('lang.current');
/* @var $regional LanguagesItem */
$add_fields = Array();
$options_a = Array('type' => 'int','error_field' => $field_name,'master_field' => $field_name,'format' => '%d' );
$options_b = Array('type' => 'double','error_field' => $field_name,'master_field' => $field_name,'format' => '%0.2f' );
switch( $regional->GetDBField('UnitSystem') )
{
case 2: // US/UK
$field_options_copy = $field_options;
unset($field_options_copy['min_value_exc']);
$add_fields[$field_name.'_a'] = kUtil::array_merge_recursive($field_options_copy, $options_a);
$add_fields[$field_name.'_b'] = kUtil::array_merge_recursive($field_options_copy, $options_b);
break;
default:
}
$add_fields = kUtil::array_merge_recursive($add_fields, $object->getVirtualFields());
$object->setVirtualFields($add_fields);
}
}
/**
* Used for split fields like timestamp -> date, time
* Called from DBItem Validate (before validation) to get back master field value from its sub_fields
*
* @param string $field
* @param mixed $value
* @param Array $options
* @param kDBItem $object
*/
function UpdateMasterFields($field, $value, &$options, &$object)
{
if ( isset($options['master_field']) || ($value == -1) ) {
// for infinity setting, otherwise infinity is incorrectly converted back to Kg
return ;
}
$regional =& $this->Application->recallObject('lang.current');
/* @var $regional LanguagesItem */
if ( $regional->GetDBField('UnitSystem') == 2 ) {
// US/UK
$major = $this->TypeCast($object->GetDBField($field . '_a'), $options);
$minor = $this->TypeCast($object->GetDBField($field . '_b'), $options);
if ( $major === '' && $minor === '' ) {
$value = null;
}
elseif ( $major === null && $minor === null ) {
$fields = $object->getFields();
unset($fields[$field]);
$object->setFields($fields);
return;
}
else {
$value = kUtil::Pounds2Kg($major, $minor);
}
}
$object->SetDBField($field, $value);
}
/**
* Used for split fields like timestamp -> date, time
* Called from DBItem to update sub fields values after loading item
*
* @param string $field
* @param string $value
* @param Array $options
* @param kDBItem $object
* @return void
* @access public
*/
public function UpdateSubFields($field, $value, &$options, &$object)
{
if ( !isset($options['master_field']) ) {
$regional =& $this->Application->recallObject('lang.current');
/* @var $regional LanguagesItem */
if ( $regional->GetDBField('UnitSystem') == 2 ) {
// US/UK
if ( $value === null ) {
$major = null;
$minor = null;
}
else {
list($major, $minor) = kUtil::Kg2Pounds($value);
// $major = floor( $value / 0.5 );
// $minor = ($value - $major * 0.5) * 32;
}
$object->SetDBField($field . '_a', $major);
$object->SetDBField($field . '_b', $minor);
}
}
}
}
\ No newline at end of file
Index: branches/5.2.x/core/kernel/utility/formatters/formatter.php
===================================================================
--- branches/5.2.x/core/kernel/utility/formatters/formatter.php (revision 14747)
+++ branches/5.2.x/core/kernel/utility/formatters/formatter.php (revision 14748)
@@ -1,301 +1,303 @@
<?php
/**
* @version $Id$
* @package In-Portal
-* @copyright Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
+* @copyright Copyright (C) 1997 - 2011 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 kFormatter extends kBase {
/**
* Reference to category helper
*
* @var CategoryHelper
*/
var $_categoryHelper = null;
/**
* Creates formatter instance
*
* @access public
*/
public function __construct()
{
parent::__construct();
$this->_categoryHelper =& $this->Application->recallObject('CategoryHelper');
}
/**
* Replace FCK links like "@@ID@@" to real page urls, when "using_fck" option is set.
*
* @param string $value
* @param Array $options
* @param string $format
* @return string
*/
function _replaceFCKLinks(&$value, $options, $format = null)
{
if ((isset($format) && strpos($format, 'fck_ready') !== false) || (!array_key_exists('using_fck', $options) || !$options['using_fck'])) {
// in textarea, where fck will be used OR not using fck
return $value;
}
return $this->_categoryHelper->replacePageIds($value);
}
/**
* Convert's value to match type from config
*
* @param mixed $value
* @param Array $options
* @return mixed
* @access protected
*/
function TypeCast($value, $options)
{
$ret = true;
if ( isset($options['type']) ) {
$field_type = $options['type'];
if ($field_type == 'numeric') {
trigger_error('Invalid field type <strong>' . $field_type . '</strong> (in TypeCast method), please use <strong>float</strong> instead', E_USER_NOTICE);
$field_type = 'float';
}
elseif ( $field_type == 'string' ) {
if ( !$this->Application->isAdmin && isset($options['allow_html']) && $options['allow_html'] ) {
// this allows to revert htmlspecialchars call for each field submitted on front-end
$value = kUtil::unhtmlentities($value);
}
return $value;
}
$value = $this->formatNumber($value);
$type_ok = preg_match('#int|integer|double|float|real|numeric|string#', $field_type);
if ( $value != '' && $type_ok ) {
$ret = is_numeric($value);
if ($ret) {
$f = 'is_' . $field_type;
settype($value, $field_type);
$ret = $f($value);
}
}
}
return $ret ? $value : false;
}
/**
* Formats number, according to regional settings
*
* @param string $number
* @return float
*/
function formatNumber($number)
{
static $comma = null, $thousands = null;
if ( !isset($comma) || !isset($thousands) ) {
$lang =& $this->Application->recallObject('lang.current');
/* @var $lang LanguagesItem */
$comma = $lang->GetDBField('DecimalPoint');
$thousands = $lang->GetDBField('ThousandSep');
}
$number = str_replace($thousands, '', $number);
$number = str_replace($comma, '.', $number);
return $number;
}
/**
* Applies type casting on each array element
* @param Array $src
* @param kDBItem|kDBList|kDBBase $object
* @return Array
* @access public
*/
public function TypeCastArray($src, &$object)
{
$dst = array ();
foreach ($src as $id => $row) {
$tmp_row = array ();
foreach ($row as $fld => $value) {
$field_options = $object->GetFieldOptions($fld);
$tmp_row[$fld] = $this->TypeCast($value, $field_options);
}
$dst[$id] = $tmp_row;
}
return $dst;
}
/**
* Formats value of a given field
*
* @param string $value
* @param string $field_name
* @param kDBItem|kDBList|kDBBase $object
* @param string $format
* @return string
*/
function Format($value, $field_name, &$object, $format = null)
{
if ( is_null($value) ) {
return '';
}
$options = $object->GetFieldOptions($field_name);
if (!isset($format) && array_key_exists('format', $options)) {
$format = $options['format'];
}
if ($value === false) {
// used ?
return $value; // for leaving badly formatted date on the form
}
$original_format = $format;
if (isset($format)) {
if (strpos($format, 'fck_ready') !== false) {
$format = trim(str_replace('fck_ready', '', $format), ';');
}
}
if (isset($format) && $format) {
$value = sprintf($format, $value);
if ( isset($options['cut_zeros']) && $options['cut_zeros'] ) {
// converts 5.00 to 5, but doesn't change 5.340 or 5.34
$value = preg_replace('/\.[0]+$/', '', $value);
}
}
if (preg_match('#int|integer|double|float|real|numeric#', $options['type'])) {
$lang =& $this->Application->recallObject('lang.current');
/* @var $lang LanguagesItem */
return $lang->formatNumber($value);
}
elseif ($options['type'] == 'string') {
$value = $this->_replaceFCKLinks($value, $options, $original_format);
}
return $value;
}
/**
* Performs basic type validation on form field value
*
* @param mixed $value
* @param string $field_name
* @param kDBItem|kDBList|kDBBase $object
* @return mixed
* @access public
*/
public function Parse($value, $field_name, &$object)
{
if ($value == '') {
return NULL;
}
$options = $object->GetFieldOptions($field_name);
$tc_value = $this->TypeCast($value, $options);
if ($tc_value === false) {
return $value; // for leaving badly formatted date on the form
}
if(isset($options['type'])) {
if (preg_match('#double|float|real|numeric#', $options['type'])) {
$tc_value = str_replace(',', '.', $tc_value);
}
}
if (isset($options['regexp'])) {
if (!preg_match($options['regexp'], $value)) {
$object->SetError($field_name, 'invalid_format');
}
}
return $tc_value;
}
function HumanFormat($format)
{
return $format;
}
/**
* The method is supposed to alter config options or cofigure object in some way based on its usage of formatters
* The methods is called for every field with formatter defined when configuring item.
* Could be used for adding additional VirtualFields to an object required by some special Formatter
*
* @param string $field_name
* @param array $field_options
* @param kDBBase $object
*/
function PrepareOptions($field_name, &$field_options, &$object)
{
}
/**
* Used for split fields like timestamp -> date, time
* Called from DBItem to update sub fields values after loading item
*
* @param string $field
* @param string $value
* @param Array $options
* @param kDBItem|kDBList|kDBBase $object
* @return void
* @access public
*/
public function UpdateSubFields($field, $value, &$options, &$object)
{
}
/**
* Used for split fields like timestamp -> date, time
* Called from DBItem Validate (before validation) to get back master field value from its sub_fields
*
* @param string $field
* @param mixed $value
* @param Array $options
* @param kDBItem|kDBList|kDBBase $object
*/
function UpdateMasterFields($field, $value, &$options, &$object)
{
}
/**
* Return sample value, that can be entered in this field
*
* @param string $field
* @param Array $options
* @param kDBItem|kDBList|kDBBase $object
* @return string
* @access public
*/
public function GetSample($field, &$options, &$object)
{
return isset($options['sample_value']) ? $options['sample_value'] : '';
}
}
\ No newline at end of file
Index: branches/5.2.x/core/kernel/utility/formatters/password_formatter.php
===================================================================
--- branches/5.2.x/core/kernel/utility/formatters/password_formatter.php (revision 14747)
+++ branches/5.2.x/core/kernel/utility/formatters/password_formatter.php (revision 14748)
@@ -1,156 +1,158 @@
<?php
/**
* @version $Id$
* @package In-Portal
-* @copyright Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
+* @copyright Copyright (C) 1997 - 2011 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 kPasswordFormatter extends kFormatter
{
/**
* The method is supposed to alter config options or cofigure object in some way based on its usage of formatters
* The methods is called for every field with formatter defined when configuring item.
* Could be used for adding additional VirtualFields to an object required by some special Formatter
*
* @param string $field_name
* @param array $field_options
* @param kDBBase $object
*/
function PrepareOptions($field_name, &$field_options, &$object)
{
if ( isset( $field_options['verify_field'] ) ) {
$add_fields = Array ();
$options = Array ('master_field' => $field_name, 'formatter' => 'kPasswordFormatter');
$copy_options = Array ('encryption_method', 'salt', 'required', 'skip_empty');
foreach ($copy_options as $copy_option) {
if (array_key_exists($copy_option, $field_options)) {
$options[$copy_option] = $field_options[$copy_option];
}
}
$add_fields[ $field_options['verify_field'] ] = $options;
$add_fields[$field_name.'_plain'] = Array('type'=>'string', 'error_field'=>$field_name);
$add_fields[ $field_options['verify_field'].'_plain' ] = Array('type'=>'string', 'error_field'=>$field_options['verify_field'] );
$virtual_fields = $object->getVirtualFields();
$add_fields = kUtil::array_merge_recursive($add_fields, $virtual_fields);
$object->setVirtualFields($add_fields);
}
}
/**
* Formats value of a given field
*
* @param string $value
* @param string $field_name
* @param kDBItem|kDBList $object
* @param string $format
* @return string
*/
function Format($value, $field_name, &$object, $format=null)
{
return $value;
}
/**
* Performs password & verify password field validation
*
* @param mixed $value
* @param string $field_name
* @param kDBItem $object
* @return mixed
* @access public
*/
public function Parse($value, $field_name, &$object)
{
$options = $object->GetFieldOptions($field_name);
$flip_count = 0;
$fields_set = true;
$password_field = $verify_field = '';
$fields = Array ('master_field', 'verify_field');
// 1. collect values from both Password and VerifyPassword fields
while ($flip_count < 2) {
if ( getArrayValue($options, $fields[0]) ) {
$tmp_field = $options[ $fields[0] ];
$object->SetDBField($field_name.'_plain', $value);
if ( !$object->GetFieldOption($tmp_field, $fields[1].'_set') ) {
$object->SetFieldOption($tmp_field, $fields[1].'_set', true);
}
$password_field = $options[ $fields[0] ];
$verify_field = $field_name;
}
$fields = array_reverse($fields);
$flip_count++;
}
$salt = $object->GetFieldOption($password_field, 'salt', false, '');
if ($object->GetFieldOption($password_field, 'verify_field_set') && $object->GetFieldOption($verify_field, 'master_field_set')) {
$new_password = $object->GetDBField($password_field . '_plain');
$verify_password = $object->GetDBField($verify_field . '_plain');
if ($new_password == '' && $verify_password == '') {
// both passwords are empty -> keep old password
if ($object->GetDBField($password_field) != $this->EncryptPassword('', $salt)) {
if ($options['encryption_method'] == 'plain') {
return $value;
}
return $this->EncryptPassword($value);
}
else {
return $value;
}
}
// determine admin or front
$phrase_error_prefix = $this->Application->isAdmin ? 'la' : 'lu';
if ($new_password != $verify_password) {
// passwords don't match (no matter what is their length)
$object->SetError($verify_field, 'passwords_do_not_match', $phrase_error_prefix.'_passwords_do_not_match');
}
$min_length = $this->Application->ConfigValue('Min_Password'); // for error message too
$min_length = $object->GetFieldOption($password_field, 'min_length', false, $min_length);
if (mb_strlen($new_password) < $min_length) {
$error_msg = '+' . sprintf($this->Application->Phrase($phrase_error_prefix.'_passwords_too_short'), $min_length); // + -> not phrase
$object->SetError($password_field, 'passwords_min_length', $error_msg);
}
}
if ($value == '') {
return $object->GetDBField($field_name);
}
if ($options['encryption_method'] == 'plain') {
return $value;
}
return $this->EncryptPassword($value, $salt);
}
function EncryptPassword($value, $salt=null)
{
if (!isset($salt) || !$salt) {
// if empty salt, assume, that it's not passed at all
return md5($value);
}
return md5(md5($value).$salt);
}
}
\ No newline at end of file
Index: branches/5.2.x/core/kernel/utility/formatters/ccdate_formatter.php
===================================================================
--- branches/5.2.x/core/kernel/utility/formatters/ccdate_formatter.php (revision 14747)
+++ branches/5.2.x/core/kernel/utility/formatters/ccdate_formatter.php (revision 14748)
@@ -1,100 +1,102 @@
<?php
/**
* @version $Id$
* @package In-Portal
-* @copyright Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
+* @copyright Copyright (C) 1997 - 2011 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!');
+
/**
* Credit card expiration date formatter
*
*/
class kCCDateFormatter extends kFormatter
{
/**
* The method is supposed to alter config options or cofigure object in some way based on its usage of formatters
* The methods is called for every field with formatter defined when configuring item.
* Could be used for adding additional VirtualFields to an object required by some special Formatter
*
* @param string $field_name
* @param array $field_options
* @param kDBBase $object
*/
function PrepareOptions($field_name, &$field_options, &$object)
{
$add_fields = Array();
$i = 1;
$options = Array('00' => '');
while($i <= 12)
{
$options[ sprintf('%02d',$i) ] = sprintf('%02d',$i);
$i++;
}
$add_fields[ $field_options['month_field'] ] = Array('formatter'=>'kOptionsFormatter', 'options' => $options, 'not_null' => true, 'default' => '00');
$add_fields[ $field_options['year_field'] ] = Array('type' => 'string', 'default' => '');
$virtual_fields = $object->getVirtualFields();
$add_fields = kUtil::array_merge_recursive($add_fields, $virtual_fields);
$object->setVirtualFields($add_fields);
}
/**
* Used for split fields like timestamp -> date, time
* Called from DBItem to update sub fields values after loading item
*
* @param string $field
* @param string $value
* @param Array $options
* @param kDBItem $object
* @return void
* @access public
*/
public function UpdateSubFields($field, $value, &$options, &$object)
{
if ( !$value ) {
return ;
}
$date = explode('/', $value);
$object->SetDBField($options['month_field'], $date[0]);
$object->SetDBField($options['year_field'], $date[1]);
}
/**
* Will work in future if we could attach 2 formatters to one field
*
* @param mixed $value
* @param string $field_name
* @param kDBItem $object
* @return mixed
* @access public
*/
public function Parse($value, $field_name, &$object)
{
$options = $object->GetFieldOptions($field_name);
$month = $object->GetDirtyField($options['month_field']);
$year = $object->GetDirtyField($options['year_field']);
if ( !(int)$month && !(int)$year ) {
return NULL;
}
$is_valid = ($month >= 1 && $month <= 12) && ($year >= 0 && $year <= 99);
if ( !$is_valid ) {
$object->SetError($field_name, 'bad_type');
}
return $month . '/' . $year;
}
}
\ No newline at end of file
Index: branches/5.2.x/core/kernel/utility/formatters/upload_formatter.php
===================================================================
--- branches/5.2.x/core/kernel/utility/formatters/upload_formatter.php (revision 14747)
+++ branches/5.2.x/core/kernel/utility/formatters/upload_formatter.php (revision 14748)
@@ -1,373 +1,375 @@
<?php
/**
* @version $Id$
* @package In-Portal
-* @copyright Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
+* @copyright Copyright (C) 1997 - 2011 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 kUploadFormatter extends kFormatter
{
var $DestinationPath;
var $FullPath;
/**
* File helper reference
*
* @var FileHelper
*/
var $fileHelper = null;
public function __construct()
{
parent::__construct();
$this->fileHelper =& $this->Application->recallObject('FileHelper');
if ($this->DestinationPath) {
$this->FullPath = FULL_PATH.$this->DestinationPath;
}
}
/**
* Processes file uploads from form
*
* @param mixed $value
* @param string $field_name
* @param kDBItem $object
* @return mixed
* @access public
*/
public function Parse($value, $field_name, &$object)
{
$ret = !is_array($value) ? $value : '';
$options = $object->GetFieldOptions($field_name);
if (getArrayValue($options, 'upload_dir')) {
$this->DestinationPath = $options['upload_dir'];
$this->FullPath = FULL_PATH.$this->DestinationPath;
}
$this->fileHelper->CheckFolder($this->FullPath);
// SWF Uploader
if (is_array($value) && isset($value['tmp_ids'])) {
if ($value['tmp_deleted']) {
$deleted = explode('|', $value['tmp_deleted']);
$upload = explode('|', $value['upload']);
$n_upload = array();
// $n_ids = array();
foreach ($upload as $name) {
if (in_array($name, $deleted)) continue;
$n_upload[] = $name;
// $n_ids[] = $name;
}
$value['upload'] = implode('|', $n_upload);
// $value['tmp_ids'] = implode('|', $n_ids);
}
if (!$value['tmp_ids']) {
// no pending files -> return already uploded files
return getArrayValue($value, 'upload');
}
$swf_uploaded_ids = explode('|', $value['tmp_ids']);
$swf_uploaded_names = explode('|', $value['tmp_names']);
$existing = $value['upload'] ? explode('|', $value['upload']) : array();
if (isset($options['multiple'])) {
$max_files = $options['multiple'] == false ? 1 : $options['multiple'];
}
else {
$max_files = 1;
}
$fret = array();
// don't delete uploaded file, when it's name matches delete file name
$var_name = $object->getPrefixSpecial().'_file_pending_actions'.$this->Application->GetVar('m_wid');
$schedule = $this->Application->RecallVar($var_name);
$schedule = $schedule ? unserialize($schedule) : Array();
$files2delete = Array();
foreach ($schedule as $data) {
if ($data['action'] == 'delete') {
$files2delete[] = $data['file'];
}
}
for ($i=0; $i<min($max_files, count($swf_uploaded_ids)); $i++) {
$real_name = $swf_uploaded_names[$i];
$real_name = $this->fileHelper->ensureUniqueFilename($this->FullPath, $real_name, $files2delete);
$file_name = $this->FullPath.$real_name;
$tmp_file = WRITEABLE . '/tmp/' . $swf_uploaded_ids[$i].'_'.$swf_uploaded_names[$i];
rename($tmp_file, $file_name);
@chmod($file_name, 0666);
$fret[] = getArrayValue($options, 'upload_dir') ? $real_name : $this->DestinationPath.$real_name;
}
$fret = array_merge($existing, $fret);
return implode('|', $fret);
}
// SWF Uploader END
if (getArrayValue($value, 'upload') && getArrayValue($value, 'error') == UPLOAD_ERR_NO_FILE) {
// file was not uploaded this time, but was uploaded before, then use previously uploaded file (from db)
return getArrayValue($value, 'upload');
}
if (is_array($value) && count($value) > 1 && $value['size']) {
if (is_array($value) && $value['error'] === UPLOAD_ERR_OK) {
$max_filesize = isset($options['max_size']) ? $options['max_size'] : MAX_UPLOAD_SIZE;
// we can get mime type based on file content and no use one, provided by the client
// $value['type'] = kUtil::mimeContentType($value['tmp_name']);
if ( getArrayValue($options, 'file_types') && !$this->extensionMatch($value['name'], $options['file_types']) ) {
// match by file extensions
$error_params = Array (
'file_name' => $value['name'],
'file_types' => $options['file_types'],
);
$object->SetError($field_name, 'bad_file_format', 'la_error_InvalidFileFormat', $error_params);
}
elseif ( getArrayValue($options, 'allowed_types') && !in_array($value['type'], $options['allowed_types']) ) {
// match by mime type provided by web-browser
$error_params = Array (
'file_type' => $value['type'],
'allowed_types' => $options['allowed_types'],
);
$object->SetError($field_name, 'bad_file_format', 'la_error_InvalidFileFormat', $error_params);
}
elseif ( $value['size'] > $max_filesize ) {
$object->SetError($field_name, 'bad_file_size', 'la_error_FileTooLarge');
}
elseif ( !is_writable($this->FullPath) ) {
$object->SetError($field_name, 'cant_save_file', 'la_error_cant_save_file');
}
else {
$real_name = $this->fileHelper->ensureUniqueFilename($this->FullPath, $value['name']);
$file_name = $this->FullPath . $real_name;
if ( !move_uploaded_file($value['tmp_name'], $file_name) ) {
$object->SetError($field_name, 'cant_save_file', 'la_error_cant_save_file');
}
else {
@chmod($file_name, 0666);
if ( getArrayValue($options, 'size_field') ) {
$object->SetDBField($options['size_field'], $value['size']);
}
if ( getArrayValue($options, 'orig_name_field') ) {
$object->SetDBField($options['orig_name_field'], $value['name']);
}
if ( getArrayValue($options, 'content_type_field') ) {
$object->SetDBField($options['content_type_field'], $value['type']);
}
$ret = getArrayValue($options, 'upload_dir') ? $real_name : $this->DestinationPath . $real_name;
// delete previous file, when new file is uploaded under same field
/*$previous_file = isset($value['upload']) ? $value['upload'] : false;
if ($previous_file && file_exists($this->FullPath.$previous_file)) {
unlink($this->FullPath.$previous_file);
}*/
}
}
}
else {
$object->SetError($field_name, 'cant_save_file', 'la_error_cant_save_file');
}
}
if ( (count($value) > 1) && $value['error'] && ($value['error'] != UPLOAD_ERR_NO_FILE) ) {
$object->SetError($field_name, 'cant_save_file', 'la_error_cant_save_file', $value);
}
return $ret;
}
/**
* Checks, that given file name has on of provided file extensions
*
* @param string $filename
* @param string $file_types
* @return bool
* @access protected
*/
protected function extensionMatch($filename, $file_types)
{
if ( preg_match_all('/\*\.(.*?)(;|$)/', $file_types, $regs) ) {
$file_extension = mb_strtolower( pathinfo($filename, PATHINFO_EXTENSION) );
$file_extensions = array_map('mb_strtolower', $regs[1]);
return in_array($file_extension, $file_extensions);
}
return true;
}
function getSingleFormat($format)
{
$single_mapping = Array (
'file_urls' => 'full_url',
'file_paths' => 'full_path',
'file_sizes' => 'file_size',
'files_resized' => 'resize',
'img_sizes' => 'img_size',
'wms' => 'wm',
);
return $single_mapping[$format];
}
/**
* Return formatted file url,path or size (or same for multiple files)
*
* @param string $value
* @param string $field_name
* @param kDBItem|kDBList $object
* @param string $format
* @return string
*/
function Format($value, $field_name, &$object, $format = null)
{
if (is_null($value)) {
return '';
}
$options = $object->GetFieldOptions($field_name);
if (!isset($format)) {
$format = isset($options['format']) ? $options['format'] : false;
}
if ($format && preg_match('/(file_urls|file_paths|file_names|file_sizes|img_sizes|files_resized|wms)(.*)/', $format, $regs)) {
if (!$value || $format == 'file_names') {
// storage format matches display format OR no value
return $value;
}
$ret = Array ();
$files = explode('|', $value);
$format = $this->getSingleFormat($regs[1]).$regs[2];
foreach ($files as $a_file) {
$ret[] = $this->GetFormatted($a_file, $field_name, $object, $format);
}
return implode('|', $ret);
}
$tc_value = $this->TypeCast($value, $options);
if( ($tc_value === false) || ($tc_value != $value) ) return $value; // for leaving badly formatted date on the form
// force direct links for case, when non-swf uploader is used
return $this->GetFormatted($tc_value, $field_name, $object, $format, true);
}
/**
* Return formatted file url,path or size
*
* @param string $value
* @param string $field_name
* @param kDBItem $object
* @param string $format
* @param bool $force_direct_links
* @return string
*/
function GetFormatted($value, $field_name, &$object, $format = null, $force_direct_links = null)
{
if (!$format) {
return $value;
}
$options = $object->GetFieldOptions($field_name);
$upload_dir = isset($options['upload_dir']) ? $options['upload_dir'] : $this->DestinationPath;
if (preg_match('/resize:([\d]*)x([\d]*)/', $format, $regs)) {
$image_helper =& $this->Application->recallObject('ImageHelper');
/* @var $image_helper ImageHelper */
if (array_key_exists('include_path', $options) && $options['include_path']) {
// relative path is already included in field
$upload_dir = '';
}
return $image_helper->ResizeImage($value ? FULL_PATH . str_replace('/', DIRECTORY_SEPARATOR, $upload_dir) . $value : '', $format);
}
switch ($format) {
case 'full_url':
if ( isset($force_direct_links) ) {
$direct_links = $force_direct_links;
}
else {
$direct_links = isset($options['direct_links']) ? $options['direct_links'] : false;
}
if ( $direct_links ) {
return $this->fileHelper->pathToUrl(FULL_PATH . $upload_dir . $value);
}
else {
$url_params = Array (
'no_amp' => 1, 'pass' => 'm,'.$object->Prefix,
$object->Prefix . '_event' => 'OnViewFile',
'file' => rawurlencode($value), 'field' => $field_name
);
return $this->Application->HREF('', '', $url_params);
}
break;
case 'full_path':
return FULL_PATH . str_replace('/', DIRECTORY_SEPARATOR, $upload_dir) . $value;
break;
case 'file_size':
return filesize(FULL_PATH . str_replace('/', DIRECTORY_SEPARATOR, $upload_dir) . $value);
break;
case 'img_size':
$image_helper =& $this->Application->recallObject('ImageHelper');
/* @var $image_helper ImageHelper */
$image_info = $image_helper->getImageInfo(FULL_PATH . str_replace('/', DIRECTORY_SEPARATOR, $upload_dir) . $value);
return $image_info ? $image_info[3] : '';
break;
}
return sprintf($format, $value);
}
}
class kPictureFormatter extends kUploadFormatter
{
public function __construct()
{
$this->NakeLookupPath = IMAGES_PATH; // used ?
$this->DestinationPath = kUtil::constOn('ADMIN') ? IMAGES_PENDING_PATH : IMAGES_PATH;
parent::__construct();
}
function GetFormatted($value, $field_name, &$object, $format = null, $force_direct_links = null)
{
if ($format == 'img_size') {
$upload_dir = isset($options['upload_dir']) ? $options['upload_dir'] : $this->DestinationPath;
$img_path = FULL_PATH.'/'.$upload_dir.$value;
$image_info = @getimagesize($img_path);
return ' width="'.$image_info[0].'" height="'.$image_info[1].'"';
}
return parent::GetFormatted($value, $field_name, $object, $format, $force_direct_links);
}
}
\ No newline at end of file
Index: branches/5.2.x/core/units/priorites/priority_eh.php
===================================================================
--- branches/5.2.x/core/units/priorites/priority_eh.php (revision 14747)
+++ branches/5.2.x/core/units/priorites/priority_eh.php (revision 14748)
@@ -1,370 +1,384 @@
<?php
+/**
+* @version $Id$
+* @package In-Portal
+* @copyright Copyright (C) 1997 - 2011 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 PriorityEventHandler extends kDBEventHandler {
/**
* Allows to override standard permission mapping
*
*/
function mapPermissions()
{
parent::mapPermissions();
$permissions = Array (
'OnRecalculatePriorities' => Array ('self' => true),
);
$this->permMapping = array_merge($this->permMapping, $permissions);
}
function mapEvents()
{
parent::mapEvents();
$events_map = Array (
'OnMassMoveUp' => 'OnChangePriority',
'OnMassMoveDown' => 'OnChangePriority',
);
$this->eventMethods = array_merge($this->eventMethods, $events_map);
}
/**
* Enter description here...
*
* @param kEvent $event
*/
function OnAfterConfigRead(&$event)
{
$hooks = Array(
Array(
'Mode' => hAFTER,
'Conditional' => false,
'HookToPrefix' => '',
'HookToSpecial' => '*',
'HookToEvent' => Array('OnAfterItemLoad', 'OnPreCreate', 'OnListBuild'),
'DoPrefix' => 'priority',
'DoSpecial' => '*',
'DoEvent' => 'OnPreparePriorities',
'Conditional' => false,
),
Array(
'Mode' => hBEFORE,
'Conditional' => false,
'HookToPrefix' => '',
'HookToSpecial' => '*',
'HookToEvent' => Array('OnPreSaveCreated'),
'DoPrefix' => 'priority',
'DoSpecial' => '*',
'DoEvent' => 'OnPreparePriorities',
'Conditional' => false,
),
Array(
'Mode' => hAFTER,
'Conditional' => false,
'HookToPrefix' => '',
'HookToSpecial' => '*',
'HookToEvent' => Array('OnPreSave', 'OnPreSaveCreated', 'OnSave', 'OnUpdate'),
'DoPrefix' => 'priority',
'DoSpecial' => '*',
'DoEvent' => 'OnSavePriorityChanges',
'Conditional' => false,
),
Array(
'Mode' => hAFTER,
'Conditional' => false,
'HookToPrefix' => '',
'HookToSpecial' => '*',
'HookToEvent' => Array('OnSave'),
'DoPrefix' => 'priority',
'DoSpecial' => '*',
'DoEvent' => 'OnSaveItems',
'Conditional' => false,
),
Array(
'Mode' => hBEFORE,
'Conditional' => false,
'HookToPrefix' => '',
'HookToSpecial' => '*',
'HookToEvent' => Array('OnBeforeItemCreate'),
'DoPrefix' => 'priority',
'DoSpecial' => '*',
'DoEvent' => 'OnItemCreate',
'Conditional' => false,
),
Array(
'Mode' => hBEFORE,
'Conditional' => false,
'HookToPrefix' => '',
'HookToSpecial' => '*',
'HookToEvent' => Array('OnAfterItemDelete'),
'DoPrefix' => 'priority',
'DoSpecial' => '*',
'DoEvent' => 'OnItemDelete',
'Conditional' => false,
)
);
$prefixes = $this->Application->getUnitOption($event->Prefix, 'ProcessPrefixes', Array ());
/* @var $prefixes Array */
foreach ($prefixes as $prefix) {
foreach ($hooks as $hook) {
if ( !is_array($hook['HookToEvent']) ) {
$hook['HookToEvent'] = Array($hook['HookToEvent']);
}
foreach ($hook['HookToEvent'] as $hook_event) {
$this->Application->registerHook(
$prefix . '.' . $hook['HookToSpecial'] . ':' . $hook_event,
$event->Prefix . '.' . $hook['DoSpecial'] . ':' . $hook['DoEvent'],
$hook['Mode'],
$hook['Conditional']
);
}
}
}
}
/**
* Should be hooked to OnAfterItemLoad, OnPreSaveCreated (why latter?)
*
* @param kEvent $event
*/
function OnPreparePriorities(&$event)
{
if ( !$this->Application->isAdminUser ) {
return ;
}
$priority_helper =& $this->Application->recallObject('PriorityHelper');
/* @var $priority_helper kPriorityHelper */
list ($constrain, $joins) = $this->getConstrainInfo($event);
$is_new = $event->MasterEvent->Name == 'OnPreCreate' || $event->MasterEvent->Name == 'OnPreSaveCreated';
$priority_helper->preparePriorities($event->MasterEvent, $is_new, $constrain, $joins);
}
/**
* Enter description here...
*
* @param kEvent $event
*/
function OnSavePriorityChanges(&$event)
{
if ($event->MasterEvent->status != kEvent::erSUCCESS) {
// don't update priorities, when OnSave validation failed
return ;
}
$object =& $event->MasterEvent->getObject();
$tmp = $this->Application->RecallVar('priority_changes'.$this->Application->GetVar('m_wid'));
$changes = $tmp ? unserialize($tmp) : array();
if (!isset($changes[$object->GetID()])) {
$changes[$object->GetId()]['old'] = $object->GetID() == 0 ? 'new' : $object->GetDBField('OldPriority');
}
if ($changes[$object->GetId()]['old'] == $object->GetDBField('Priority')) return ;
$changes[$object->GetId()]['new'] = $object->GetDBField('Priority');
list ($constrain, $joins) = $this->getConstrainInfo($event);
if ($constrain) {
$changes[$object->GetId()]['constrain'] = $constrain;
}
$this->Application->StoreVar('priority_changes'.$this->Application->GetVar('m_wid'), serialize($changes));
}
/**
* Enter description here...
*
* @param kEvent $event
*/
function OnItemDelete(&$event)
{
// just store the prefix in which the items were deleted
$del = $this->Application->RecallVar('priority_deleted' . $this->Application->GetVar('m_wid'));
$del = $del ? unserialize($del) : array();
list ($constrain, $joins) = $this->getConstrainInfo($event);
$cache_key = crc32($event->MasterEvent->Prefix . ':' . $constrain . ':' . $joins);
if ( !isset($del[$cache_key]) ) {
$del[$cache_key] = Array (
'prefix' => $event->MasterEvent->Prefix,
'constrain' => $constrain,
'joins' => $joins,
);
$this->Application->StoreVar('priority_deleted' . $this->Application->GetVar('m_wid'), serialize($del));
}
}
/**
* Called before script shut-down and recalculate all deleted prefixes, to avoid recalculation on each deleted item
*
* @param kEvent $event
*/
function OnBeforeShutDown(&$event)
{
$del = $this->Application->RecallVar('priority_deleted'.$this->Application->GetVar('m_wid'));
$del = $del ? unserialize($del) : array();
$priority_helper =& $this->Application->recallObject('PriorityHelper');
/* @var $priority_helper kPriorityHelper */
foreach ($del as $del_info) {
$dummy_event = new kEvent( array('prefix'=>$del_info['prefix'], 'name'=>'Dummy' ) );
$ids = $priority_helper->recalculatePriorities($dummy_event, $del_info['constrain'], $del_info['joins']);
if ($ids) {
$priority_helper->massUpdateChanged($del_info['prefix'], $ids);
}
}
$this->Application->RemoveVar('priority_deleted'.$this->Application->GetVar('m_wid'));
}
/**
* Enter description here...
*
* @param kEvent $event
*/
function OnSaveItems(&$event)
{
$tmp = $this->Application->RecallVar('priority_changes'.$this->Application->GetVar('m_wid'));
$changes = $tmp ? unserialize($tmp) : array();
$priority_helper =& $this->Application->recallObject('PriorityHelper');
/* @var $priority_helper kPriorityHelper */
list ($constrain, $joins) = $this->getConstrainInfo($event);
$ids = $priority_helper->updatePriorities($event->MasterEvent, $changes, Array (0 => $event->MasterEvent->getEventParam('ids')), $constrain, $joins);
if ($ids) {
$priority_helper->massUpdateChanged($event->MasterEvent->Prefix, $ids);
}
}
function OnItemCreate(&$event)
{
$obj =& $event->MasterEvent->getObject();
if ($obj->GetDBField('Priority') == 0) {
$priority_helper =& $this->Application->recallObject('PriorityHelper');
/* @var $priority_helper kPriorityHelper */
list ($constrain, $joins) = $this->getConstrainInfo($event);
$priority_helper->preparePriorities($event->MasterEvent, true, $constrain, $joins);
}
}
/**
* Processes OnMassMoveUp, OnMassMoveDown events
*
* @param kEvent $event
*/
function OnChangePriority(&$event)
{
$prefix = $this->Application->GetVar('priority_prefix');
$dummy_event = new kEvent( array('prefix'=>$prefix, 'name'=>'Dummy' ) );
$ids = $this->StoreSelectedIDs($dummy_event);
if ($ids) {
$id_field = $this->Application->getUnitOption($prefix, 'IDField');
$table_name = $this->Application->getUnitOption($prefix, 'TableName');
if ( $this->Application->IsTempMode($prefix) ) {
$table_name = $this->Application->GetTempName($table_name, 'prefix:' . $prefix);
}
$sql = 'SELECT Priority, '.$id_field.'
FROM '.$table_name.'
WHERE '.$id_field.' IN ('.implode(',', $ids).') ORDER BY Priority DESC';
$priorities = $this->Conn->GetCol($sql, $id_field);
$priority_helper =& $this->Application->recallObject('PriorityHelper');
/* @var $priority_helper kPriorityHelper */
list ($constrain, $joins) = $this->getConstrainInfo($event);
$sql = 'SELECT IFNULL(MIN(item_table.Priority), -1)
FROM '.$table_name . ' item_table
' . $joins;
if ( $constrain ) {
$sql .= ' WHERE ' . $priority_helper->normalizeConstrain($constrain);
}
$min_priority = $this->Conn->GetOne($sql);
foreach ($ids as $id) {
$new_priority = $priorities[$id] + ($event->Name == 'OnMassMoveUp' ? +1 : -1);
if ($new_priority > -1 || $new_priority < $min_priority) {
continue;
}
$changes = Array (
$id => Array ('old' => $priorities[$id], 'new' => $new_priority),
);
if ($constrain) {
$changes[$id]['constrain'] = $constrain;
}
$sql = 'UPDATE '.$table_name.'
SET Priority = '.$new_priority.'
WHERE '.$id_field.' = '.$id;
$this->Conn->Query($sql);
$ids = $priority_helper->updatePriorities($dummy_event, $changes, Array ($id => $id), $constrain, $joins);
if ($ids) {
$priority_helper->massUpdateChanged($prefix, $ids);
}
}
}
$this->clearSelectedIDs($dummy_event);
}
/**
* Completely recalculates priorities in current category
*
* @param kEvent $event
*/
function OnRecalculatePriorities(&$event)
{
$priority_helper =& $this->Application->recallObject('PriorityHelper');
/* @var $priority_helper kPriorityHelper */
$prefix = $this->Application->GetVar('priority_prefix');
$dummy_event = new kEvent( array('prefix'=>$prefix, 'name'=>'Dummy' ) );
list ($constrain, $joins) = $this->getConstrainInfo($event);
$ids = $priority_helper->recalculatePriorities($dummy_event, $constrain, $joins);
if ($ids) {
$priority_helper->massUpdateChanged($prefix, $ids);
}
}
/**
* Returns constrain for current priority calculations
*
* @param kEvent $event
* @return Array
*/
function getConstrainInfo(&$event)
{
$constrain_event = new kEvent($event->MasterEvent->getPrefixSpecial() . ':OnGetConstrainInfo');
$constrain_event->setEventParam('actual_event', $event->Name);
$constrain_event->setEventParam('original_event', $event->MasterEvent->Name);
$this->Application->HandleEvent($constrain_event);
return $constrain_event->getEventParam('constrain_info');
}
}
Index: branches/5.2.x/core/units/priorites/priorites_config.php
===================================================================
--- branches/5.2.x/core/units/priorites/priorites_config.php (revision 14747)
+++ branches/5.2.x/core/units/priorites/priorites_config.php (revision 14748)
@@ -1,31 +1,45 @@
<?php
+/**
+* @version $Id$
+* @package In-Bulletin
+* @copyright Copyright (C) 1997 - 2011 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!');
+
$config = Array (
'Prefix' => 'priority',
'EventHandlerClass' => Array ('class' => 'PriorityEventHandler', 'file' => 'priority_eh.php', 'build_event' => 'OnBuild'),
'QueryString' => Array (
1 => 'prefix',
2 => 'event',
),
'Hooks' => Array (
Array (
'Mode' => hAFTER,
'Conditional' => false,
'HookToPrefix' => 'adm',
'HookToSpecial' => '*',
'HookToEvent' => Array ('OnBeforeShutdown'),
'DoPrefix' => 'priority',
'DoSpecial' => '*',
'DoEvent' => 'OnBeforeShutdown',
'Conditional' => false,
),
),
'PermSection' => Array ('main' => 'custom'),
'ProcessPrefixes' => Array(
'c', 'st'
),
);
Index: branches/5.2.x/core/units/categories/categories_tag_processor.php
===================================================================
--- branches/5.2.x/core/units/categories/categories_tag_processor.php (revision 14747)
+++ branches/5.2.x/core/units/categories/categories_tag_processor.php (revision 14748)
@@ -1,2021 +1,2023 @@
<?php
/**
* @version $Id$
* @package In-Portal
-* @copyright Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
+* @copyright Copyright (C) 1997 - 2011 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 CategoriesTagProcessor extends kDBTagProcessor {
function SubCatCount($params)
{
$object =& $this->getObject($params);
/* @var $object kDBItem */
if ( isset($params['today']) && $params['today'] ) {
$sql = 'SELECT COUNT(*)
FROM ' . $object->TableName . '
WHERE (ParentPath LIKE "' . $object->GetDBField('ParentPath') . '%") AND (CreatedOn > ' . (adodb_mktime() - 86400) . ')';
return $this->Conn->GetOne($sql) - 1;
}
return $object->GetDBField('CachedDescendantCatsQty');
}
/**
* Returns category count in system
*
* @param Array $params
* @return int
*/
function CategoryCount($params)
{
$count_helper =& $this->Application->recallObject('CountHelper');
/* @var $count_helper kCountHelper */
$today_only = isset($params['today']) && $params['today'];
return $count_helper->CategoryCount($today_only);
}
function IsNew($params)
{
$object =& $this->getObject($params);
/* @var $object kDBItem */
return $object->GetDBField('IsNew') ? 1 : 0;
}
function IsPick($params)
{
return $this->IsEditorsPick($params);
}
/**
* Returns item's editors pick status (using not formatted value)
*
* @param Array $params
* @return bool
*/
function IsEditorsPick($params)
{
$object =& $this->getObject($params);
/* @var $object kDBItem */
return $object->GetDBField('EditorsPick') == 1;
}
function ItemIcon($params)
{
$grids = $this->Application->getUnitOption($this->Prefix, 'Grids');
$grid = $grids[ $params['grid'] ];
if (!array_key_exists('Icons', $grid)) {
return '';
}
$icons = $grid['Icons'];
$icon_prefix = array_key_exists('icon_prefix', $params)? $params['icon_prefix'] : 'icon16_';
if (array_key_exists('name', $params)) {
$icon_name = $params['name'];
return array_key_exists($icon_name, $icons) ? $icons[$icon_name] : '';
}
$object =& $this->getObject($params);
/* @var $object kDBList */
if ($object->GetDBField('ThemeId') > 0) {
if (!$object->GetDBField('IsMenu')) {
return $icon_prefix . 'section_menuhidden_system.png';
}
return $icon_prefix . 'section_system.png';
}
$status = $object->GetDBField('Status');
if ($status == STATUS_DISABLED) {
return $icon_prefix . 'section_disabled.png';
}
if (!$object->GetDBField('IsMenu')) {
return $icon_prefix . 'section_menuhidden.png';
}
if ($status == STATUS_PENDING) {
return $icon_prefix . 'section_pending.png';
}
if ($object->GetDBField('IsNew') && ($icon_prefix == 'icon16_')) {
return $icon_prefix . 'section_new.png'; // show gris icon only in grids
}
return $icon_prefix . 'section.png';
}
function ItemCount($params)
{
$object =& $this->getObject($params);
/* @var $object kDBItem */
$ci_table = $this->Application->getUnitOption('ci', 'TableName');
$sql = 'SELECT COUNT(*)
FROM ' . $object->TableName . ' c
LEFT JOIN ' . $ci_table . ' ci ON c.CategoryId = ci.CategoryId
WHERE (c.TreeLeft BETWEEN ' . $object->GetDBField('TreeLeft') . ' AND ' . $object->GetDBField('TreeRight') . ') AND NOT (ci.CategoryId IS NULL)';
return $this->Conn->GetOne($sql);
}
function ListCategories($params)
{
return $this->PrintList2($params);
}
function RootCategoryName($params)
{
return $this->Application->ProcessParsedTag('m', 'RootCategoryName', $params);
}
function CheckModuleRoot($params)
{
$module_name = getArrayValue($params, 'module') ? $params['module'] : 'In-Commerce';
$module_root_cat = $this->Application->findModule('Name', $module_name, 'RootCat');
$additional_cats = $this->SelectParam($params, 'add_cats');
if ($additional_cats) {
$additional_cats = explode(',', $additional_cats);
}
else {
$additional_cats = array();
}
if ($this->Application->GetVar('m_cat_id') == $module_root_cat || in_array($this->Application->GetVar('m_cat_id'), $additional_cats)) {
$home_template = getArrayValue($params, 'home_template');
if (!$home_template) return;
$this->Application->Redirect($home_template, Array('pass'=>'all'));
};
}
function CategoryPath($params)
{
$category_helper =& $this->Application->recallObject('CategoryHelper');
/* @var $category_helper CategoryHelper */
return $category_helper->NavigationBar($params);
}
/**
* Shows category path to specified category
*
* @param Array $params
* @return string
*/
function FieldCategoryPath($params)
{
$object =& $this->getObject();
/* @var $object kDBItem */
$field = $this->SelectParam($params, 'name,field');
$category_id = $object->GetDBField($field);
if ($category_id) {
$params['cat_id'] = $category_id;
return $this->CategoryPath($params);
}
return '';
}
function CurrentCategoryName($params)
{
$cat_object =& $this->Application->recallObject($this->getPrefixSpecial(), $this->Prefix.'_List');
/* @var $cat_object kDBList */
$sql = 'SELECT '.$this->getTitleField().'
FROM '.$cat_object->TableName.'
WHERE CategoryId = '.(int)$this->Application->GetVar('m_cat_id');
return $this->Conn->GetOne($sql);
}
/**
* Returns current category name
*
* @param Array $params
* @return string
* @todo Find where it's used
*/
function CurrentCategory($params)
{
return $this->CurrentCategoryName($params);
}
function getTitleField()
{
$ml_formatter =& $this->Application->recallObject('kMultiLanguage');
/* @var $ml_formatter kMultiLanguage */
return $ml_formatter->LangFieldName('Name');
}
/**
* Returns symlinked category for given category
*
* @param int $category_id
* @return int
*/
function getCategorySymLink($category_id)
{
if (!$category_id) {
// don't bother to get symlink for "Home" category
return $category_id;
}
$cache_key = 'category_symlinks[%CSerial%]';
$cache = $this->Application->getCache($cache_key);
if ($cache === false) {
$id_field = $this->Application->getUnitOption($this->Prefix, 'IDField');
$table_name = $this->Application->getUnitOption($this->Prefix, 'TableName');
// get symlinked categories, that are not yet deleted
$this->Conn->nextQueryCachable = true;
$sql = 'SELECT c1.SymLinkCategoryId, c1.' . $id_field . '
FROM ' . $table_name . ' c1
JOIN ' . $table_name . ' c2 ON c1.SymLinkCategoryId = c2.' . $id_field;
$cache = $this->Conn->GetCol($sql, $id_field);
$this->Application->setCache($cache_key, $cache);
}
return array_key_exists($category_id, $cache) ? $cache[$category_id] : $category_id;
}
function CategoryLink($params)
{
$category_id = getArrayValue($params, 'cat_id');
if ( $category_id === false ) {
$category_id = $this->Application->GetVar($this->getPrefixSpecial() . '_id');
}
if ( "$category_id" == 'Root' ) {
$category_id = $this->Application->findModule('Name', $params['module'], 'RootCat');
}
elseif ( "$category_id" == 'current' ) {
$category_id = $this->Application->GetVar('m_cat_id');
}
if ( !array_key_exists('direct_link', $params) || !$params['direct_link'] ) {
$category_id = $this->getCategorySymLink((int)$category_id);
}
else {
unset($params['direct_link']);
}
$virtual_template = $this->Application->getVirtualPageTemplate($category_id);
if ( ($virtual_template !== false) && preg_match('/external:(.*)/', $virtual_template, $rets) ) {
// external url (return here, instead of always replacing $params['t'] for kApplication::HREF to find it)
return $rets[1];
}
unset($params['cat_id'], $params['module']);
$new_params = Array ('pass' => 'm', 'm_cat_id' => $category_id, 'pass_category' => 1);
$params = array_merge($params, $new_params);
return $this->Application->ProcessParsedTag('m', 't', $params);
}
function CategoryList($params)
{
//$object =& $this->Application->recallObject( $this->getPrefixSpecial() , $this->Prefix.'_List', $params );
$object =& $this->GetList($params);
if ($object->GetRecordsCount() == 0)
{
if (isset($params['block_no_cats'])) {
$params['name'] = $params['block_no_cats'];
return $this->Application->ParseBlock($params);
}
else {
return '';
}
}
if (isset($params['block'])) {
return $this->PrintList($params);
}
else {
$params['block'] = $params['block_main'];
if (isset($params['block_row_start'])) {
$params['row_start_block'] = $params['block_row_start'];
}
if (isset($params['block_row_end'])) {
$params['row_end_block'] = $params['block_row_end'];
}
return $this->PrintList2($params);
}
}
function Meta($params)
{
$object =& $this->Application->recallObject($this->Prefix); // .'.-item'
/* @var $object CategoriesItem */
$meta_type = $params['name'];
if ($object->isLoaded()) {
// 1. get module prefix by current category
$category_helper =& $this->Application->recallObject('CategoryHelper');
/* @var $category_helper CategoryHelper */
$category_path = explode('|', substr($object->GetDBField('ParentPath'), 1, -1));
$module_info = $category_helper->getCategoryModule($params, $category_path);
// In-Edit & Proj-CMS module prefixes doesn't have custom field with item template
if ($module_info && $module_info['Var'] != 'adm' && $module_info['Var'] != 'st') {
// 2. get item template by current category & module prefix
$rewrite_processor = $this->Application->recallObject('kRewriteUrlProcessor');
/* @var $rewrite_processor kRewriteUrlProcessor */
$category_params = Array (
'CategoryId' => $object->GetID(),
'ParentPath' => $object->GetDBField('ParentPath'),
);
$item_template = $rewrite_processor->GetItemTemplate($category_params, $module_info['Var']);
if ($this->Application->GetVar('t') == $item_template) {
// we are located on item's details page
$item =& $this->Application->recallObject($module_info['Var']);
/* @var $item kCatDBItem */
// 3. get item's meta data
$value = $item->GetField('Meta'.$meta_type);
if ($value) {
return $value;
}
}
// 4. get category meta data
$value = $object->GetField('Meta'.$meta_type);
if ($value) {
return $value;
}
}
}
// 5. get default meta data
switch ($meta_type) {
case 'Description':
$config_name = 'Category_MetaDesc';
break;
case 'Keywords':
$config_name = 'Category_MetaKey';
break;
}
return $this->Application->ConfigValue($config_name);
}
function BuildListSpecial($params)
{
if (($this->Special != '') && !is_numeric($this->Special)) {
// When recursive category list is printed (like in sitemap), then special
// should be generated even if it's already present. Without it list on this
// level will erase list on previous level, because it will be stored in same object.
return $this->Special;
}
if ( isset($params['parent_cat_id']) ) {
$parent_cat_id = $params['parent_cat_id'];
}
else {
$parent_cat_id = $this->Application->GetVar($this->Prefix.'_id');
if (!$parent_cat_id) {
$parent_cat_id = $this->Application->GetVar('m_cat_id');
}
if (!$parent_cat_id) {
$parent_cat_id = 0;
}
}
$list_unique_key = $this->getUniqueListKey($params);
// check for "admin" variable, because we are parsing front-end template from admin when using template editor feature
if ($this->Application->GetVar('admin') || !$this->Application->isAdmin) {
// add parent category to special, when on Front-End,
// because there can be many category lists on same page
$list_unique_key .= $parent_cat_id;
}
if ($list_unique_key == '') {
return parent::BuildListSpecial($params);
}
return crc32($list_unique_key);
}
function IsCurrent($params)
{
$object =& $this->getObject($params);
if ($object->GetID() == $this->Application->GetVar('m_cat_id')) {
return true;
}
else {
return false;
}
}
/**
* Substitutes category in last template base on current category
* This is required becasue when you navigate catalog using AJAX, last_template is not updated
* but when you open item edit from catalog last_template is used to build opener_stack
* So, if we don't substitute m_cat_id in last_template, after saving item we'll get redirected
* to the first category we've opened, not the one we navigated to using AJAX
*
* @param Array $params
*/
function UpdateLastTemplate($params)
{
$category_id = $this->Application->GetVar('m_cat_id');
$wid = $this->Application->GetVar('m_wid');
list($index_file, $env) = explode('|', $this->Application->RecallVar(rtrim('last_template_'.$wid, '_')), 2);
$vars_backup = Array ();
$vars = $this->Application->processQueryString( str_replace('%5C', '\\', $env) );
foreach ($vars as $var_name => $var_value) {
$vars_backup[$var_name] = $this->Application->GetVar($var_name);
$this->Application->SetVar($var_name, $var_value);
}
// update required fields
$this->Application->SetVar('m_cat_id', $category_id);
$this->Application->Session->SaveLastTemplate($params['template']);
foreach ($vars_backup as $var_name => $var_value) {
$this->Application->SetVar($var_name, $var_value);
}
}
function GetParentCategory($params)
{
$parent_id = $this->Application->getBaseCategory();
$category_id = $this->Application->GetVar('m_cat_id');
if ($category_id != $parent_id) {
$sql = 'SELECT ParentId
FROM ' . $this->Application->getUnitOption($this->Prefix, 'TableName') . '
WHERE ' . $this->Application->getUnitOption($this->Prefix, 'IDField') . ' = ' . $category_id;
$parent_id = $this->Conn->GetOne($sql);
}
return $parent_id;
}
function InitCacheUpdater($params)
{
kUtil::safeDefine('CACHE_PERM_CHUNK_SIZE', 30);
$continue = $this->Application->GetVar('continue');
$total_cats = (int) $this->Conn->GetOne('SELECT COUNT(*) FROM '.TABLE_PREFIX.'Category');
if ($continue === false && $total_cats > CACHE_PERM_CHUNK_SIZE) {
// first step, if category count > CACHE_PERM_CHUNK_SIZE, then ask for cache update
return true;
}
if ($continue === false) {
// if we don't have to ask, then assume user selected "Yes" in permcache update dialog
$continue = 1;
}
$updater =& $this->Application->makeClass('kPermCacheUpdater', Array($continue));
/* @var $updater kPermCacheUpdater */
if ($continue === '0') { // No in dialog
$updater->clearData();
$this->Application->Redirect($params['destination_template']);
}
$ret = false; // don't ask for update
if ($continue == 1) { // Initial run
$updater->setData();
}
if ($continue == 2) { // Continuing
// called from AJAX request => returns percent
$needs_more = true;
while ($needs_more && $updater->iteration <= CACHE_PERM_CHUNK_SIZE) {
// until proceeeded in this step category count exceeds category per step limit
$needs_more = $updater->DoTheJob();
}
if ($needs_more) {
// still some categories are left for next step
$updater->setData();
}
else {
// all done, update left tree and redirect
$updater->SaveData();
$this->Application->HandleEvent($event, 'c:OnResetCMSMenuCache');
$this->Application->RemoveVar('PermCache_UpdateRequired');
$this->Application->StoreVar('RefreshStructureTree', 1);
$this->Application->Redirect($params['destination_template']);
}
$ret = $updater->getDonePercent();
}
return $ret;
}
/**
* Parses warning block, but with style="display: none;". Used during permissions saving from AJAX
*
* @param Array $params
* @return string
* @access protected
*/
protected function SaveWarning($params)
{
if ( $this->Prefix == 'st' ) {
// don't use this method for other prefixes then Category, that use this tag processor
return parent::SaveWarning($params);
}
$main_prefix = getArrayValue($params, 'main_prefix');
if ( $main_prefix && $main_prefix != '$main_prefix' ) {
$top_prefix = $main_prefix;
}
else {
$top_prefix = $this->Application->GetTopmostPrefix($this->Prefix);
}
$temp_tables = substr($this->Application->GetVar($top_prefix . '_mode'), 0, 1) == 't';
$modified = $this->Application->RecallVar($top_prefix . '_modified');
if ( !$temp_tables ) {
$this->Application->RemoveVar($top_prefix . '_modified');
return '';
}
$block_name = $this->SelectParam($params, 'render_as,name');
if ( $block_name ) {
$block_params = $this->prepareTagParams($params);
$block_params['name'] = $block_name;
$block_params['edit_mode'] = $temp_tables ? 1 : 0;
$block_params['display'] = $temp_tables && $modified ? 1 : 0;
return $this->Application->ParseBlock($block_params);
}
return $temp_tables && $modified ? 1 : 0;
}
/**
* Allows to detect if this prefix has something in clipboard
*
* @param Array $params
* @return bool
*/
function HasClipboard($params)
{
$clipboard = $this->Application->RecallVar('clipboard');
if ($clipboard) {
$clipboard = unserialize($clipboard);
foreach ($clipboard as $prefix => $clipboard_data) {
foreach ($clipboard_data as $mode => $ids) {
if (count($ids)) return 1;
}
}
}
return 0;
}
/**
* Allows to detect if root category being edited
*
* @param Array $params
*/
function IsRootCategory($params)
{
$object =& $this->getObject($params);
/* @var $object CategoriesItem */
return $object->IsRoot();
}
/**
* Returns home category id
*
* @param Array $params
* @return int
*/
function HomeCategory($params)
{
return $this->Application->getBaseCategory();
}
/**
* Used for disabling "Home" and "Up" buttons in category list
*
* @param Array $params
* @return bool
*/
function ModuleRootCategory($params)
{
return $this->Application->GetVar('m_cat_id') == $this->Application->getBaseCategory();
}
function CatalogItemCount($params)
{
$params['skip_quering'] = true;
$object =& $this->GetList($params);
return $object->GetRecordsCount(false) != $object->GetRecordsCount() ? $object->GetRecordsCount().' / '.$object->GetRecordsCount(false) : $object->GetRecordsCount();
}
function InitCatalog($params)
{
$tab_prefixes = $this->Application->GetVar('tp'); // {all, <prefixes_list>, none}
if ($tab_prefixes === false) $tab_prefixes = 'all';
$skip_prefixes = isset($params['skip_prefixes']) && $params['skip_prefixes'] ? explode(',', $params['skip_prefixes']) : Array();
$replace_main = isset($params['replace_m']) && $params['replace_m'];
// get all prefixes available
$prefixes = Array();
foreach ($this->Application->ModuleInfo as $module_name => $module_data) {
$prefix = $module_data['Var'];
if ($prefix == 'adm'/* || $prefix == 'm'*/) continue;
if ($prefix == 'm' && $replace_main) {
$prefix = 'c';
}
$prefixes[] = $prefix;
}
if ($tab_prefixes == 'none') {
$skip_prefixes = array_unique(array_merge($skip_prefixes, $prefixes));
unset($skip_prefixes[ array_search($replace_main ? 'c' : 'm', $skip_prefixes) ]);
}
elseif ($tab_prefixes != 'all') {
// prefix list here
$tab_prefixes = explode(',', $tab_prefixes); // list of prefixes that should stay
$skip_prefixes = array_unique(array_merge($skip_prefixes, array_diff($prefixes, $tab_prefixes)));
}
$params['name'] = $params['render_as'];
$params['skip_prefixes'] = implode(',', $skip_prefixes);
return $this->Application->ParseBlock($params);
}
/**
* Determines, that printed category/menu item is currently active (will also match parent category)
*
* @param Array $params
* @return bool
*/
function IsActive($params)
{
static $current_path = null;
if ( !isset($current_path) ) {
$sql = 'SELECT ParentPath
FROM ' . TABLE_PREFIX . 'Category
WHERE CategoryId = ' . (int)$this->Application->GetVar('m_cat_id');
$current_path = $this->Conn->GetOne($sql);
}
if ( array_key_exists('parent_path', $params) ) {
$test_path = $params['parent_path'];
}
else {
$template = $params['template'];
if ( $template ) {
// when using from "c:CachedMenu" tag
$sql = 'SELECT ParentPath
FROM ' . TABLE_PREFIX . 'Category
WHERE NamedParentPath = ' . $this->Conn->qstr('Content/' . $template);
$test_path = $this->Conn->GetOne($sql);
}
else {
// when using from "c:PrintList" tag
$cat_id = array_key_exists('cat_id', $params) && $params['cat_id'] ? $params['cat_id'] : false;
if ( $cat_id === false ) {
// category not supplied -> get current from PrintList
$category =& $this->getObject($params);
}
else {
if ( "$cat_id" == 'Root' ) {
$cat_id = $this->Application->findModule('Name', $params['module'], 'RootCat');
}
$category =& $this->Application->recallObject($this->Prefix . '.-c' . $cat_id, $this->Prefix, Array ('skip_autoload' => true));
/* @var $category CategoriesItem */
$category->Load($cat_id);
}
$test_path = $category->GetDBField('ParentPath');
}
}
return strpos($current_path, $test_path) !== false;
}
/**
* Checks if user have one of required permissions
*
* @param Array $params
* @return bool
*/
function HasPermission($params)
{
$perm_helper =& $this->Application->recallObject('PermissionsHelper');
/* @var $perm_helper kPermissionsHelper */
$params['raise_warnings'] = 0;
$object =& $this->getObject($params);
/* @var $object kDBItem */
$params['cat_id'] = $object->isLoaded() ? $object->GetDBField('ParentPath') : $this->Application->GetVar('m_cat_id');
return $perm_helper->TagPermissionCheck($params);
}
/**
* Prepares name for field with event in it (used only on front-end)
*
* @param Array $params
* @return string
*/
function SubmitName($params)
{
return 'events[' . $this->Prefix . '][' . $params['event'] . ']';
}
/**
* Returns last modification date of items in category / system
*
* @param Array $params
* @return string
*/
function LastUpdated($params)
{
$category_id = (int)$this->Application->GetVar('m_cat_id');
$local = array_key_exists('local', $params) && ($category_id > 0) ? $params['local'] : false;
$serial_name = $this->Application->incrementCacheSerial('c', $local ? $category_id : null, false);
$cache_key = 'category_last_updated[%' . $serial_name . '%]';
$row_data = $this->Application->getCache($cache_key);
if ( $row_data === false ) {
if ( $local && ($category_id > 0) ) {
// scan only current category & it's children
list ($tree_left, $tree_right) = $this->Application->getTreeIndex($category_id);
$sql = 'SELECT MAX(Modified) AS ModDate, MAX(CreatedOn) AS NewDate
FROM ' . TABLE_PREFIX . 'Category
WHERE TreeLeft BETWEEN ' . $tree_left . ' AND ' . $tree_right;
}
else {
// scan all categories in system
$sql = 'SELECT MAX(Modified) AS ModDate, MAX(CreatedOn) AS NewDate
FROM ' . TABLE_PREFIX . 'Category';
}
$this->Conn->nextQueryCachable = true;
$row_data = $this->Conn->GetRow($sql);
$this->Application->setCache($cache_key, $row_data);
}
if ( !$row_data ) {
return '';
}
$date = $row_data[$row_data['NewDate'] > $row_data['ModDate'] ? 'NewDate' : 'ModDate'];
// format date
$format = isset($params['format']) ? $params['format'] : '_regional_DateTimeFormat';
if ( preg_match("/_regional_(.*)/", $format, $regs) ) {
$lang =& $this->Application->recallObject('lang.current');
/* @var $lang LanguagesItem */
if ( $regs[1] == 'DateTimeFormat' ) {
// combined format
$format = $lang->GetDBField('DateFormat') . ' ' . $lang->GetDBField('TimeFormat');
}
else {
// simple format
$format = $lang->GetDBField($regs[1]);
}
}
return adodb_date($format, $date);
}
function CategoryItemCount($params)
{
$object =& $this->getObject($params);
/* @var $object kDBList */
$params['cat_id'] = $object->GetID();
$count_helper =& $this->Application->recallObject('CountHelper');
/* @var $count_helper kCountHelper */
return $count_helper->CategoryItemCount($params['prefix'], $params);
}
/**
* Returns prefix + any word (used for shared between categories per page settings)
*
* @param Array $params
* @return string
*/
function VarName($params)
{
return $this->Prefix.'_'.$params['type'];
}
/**
* Checks if current category is valid symbolic link to another category
*
* @param Array $params
* @return string
*/
function IsCategorySymLink($params)
{
$object =& $this->getObject($params);
/* @var $object kDBList */
$sym_category_id = $object->GetDBField('SymLinkCategoryId');
if (is_null($sym_category_id))
{
return false;
}
$id_field = $this->Application->getUnitOption($this->Prefix, 'IDField');
$table_name = $this->Application->getUnitOption($this->Prefix, 'TableName');
$sql = 'SELECT '.$id_field.'
FROM '.$table_name.'
WHERE '.$id_field.' = '.$sym_category_id;
return $this->Conn->GetOne($sql)? true : false;
}
/**
* Returns module prefix based on root category for given
*
* @param Array $params
* @return string
*/
function GetModulePrefix($params)
{
$object =& $this->getObject($params);
/* @var $object kDBItem */
$parent_path = explode('|', substr($object->GetDBField('ParentPath'), 1, -1));
$category_helper =& $this->Application->recallObject('CategoryHelper');
/* @var $category_helper CategoryHelper */
$module_info = $category_helper->getCategoryModule($params, $parent_path);
return $module_info['Var'];
}
function ImageSrc($params)
{
list ($ret, $tag_processed) = $this->processAggregatedTag('ImageSrc', $params, $this->getPrefixSpecial());
return $tag_processed ? $ret : false;
}
function PageLink($params)
{
$params['m_cat_page'] = $this->Application->GetVar($this->getPrefixSpecial() . '_Page');
return parent::PageLink($params);
}
/**
* Returns spelling suggestions against search keyword
*
* @param Array $params
* @return string
* @access protected
*/
protected function SpellingSuggestions($params)
{
$keywords = kUtil::unhtmlentities( trim($this->Application->GetVar('keywords')) );
if ( !$keywords ) {
return '';
}
// 1. try to get already cached suggestion
$cache_key = 'search.suggestion[%SpellingDictionary%]:' . $keywords;
$suggestion = $this->Application->getCache($cache_key);
if ( $suggestion !== false ) {
return $suggestion;
}
$table_name = $this->Application->getUnitOption('spelling-dictionary', 'TableName');
// 2. search suggestion in database
$this->Conn->nextQueryCachable = true;
$sql = 'SELECT SuggestedCorrection
FROM ' . $table_name . '
WHERE MisspelledWord = ' . $this->Conn->qstr($keywords);
$suggestion = $this->Conn->GetOne($sql);
if ( $suggestion !== false ) {
$this->Application->setCache($cache_key, $suggestion);
return $suggestion;
}
// 3. suggestion not found in database, ask webservice
$app_id = $this->Application->ConfigValue('YahooApplicationId');
$url = 'http://search.yahooapis.com/WebSearchService/V1/spellingSuggestion?appid=' . $app_id . '&query=';
$curl_helper =& $this->Application->recallObject('CurlHelper');
/* @var $curl_helper kCurlHelper */
$xml_data = $curl_helper->Send( $url . urlencode($keywords) );
$xml_helper =& $this->Application->recallObject('kXMLHelper');
/* @var $xml_helper kXMLHelper */
$root_node =& $xml_helper->Parse($xml_data);
/* @var $root_node kXMLNode */
$result = $root_node->FindChild('RESULT');
/* @var $result kXMLNode */
if ( is_object($result) ) {
// webservice responded -> save in local database
$fields_hash = Array ('MisspelledWord' => $keywords, 'SuggestedCorrection' => $result->Data);
$this->Conn->doInsert($fields_hash, $table_name);
$this->Application->setCache($cache_key, $result->Data);
return $result->Data;
}
return '';
}
/**
* Shows link for searching by suggested word
*
* @param Array $params
* @return string
*/
function SuggestionLink($params)
{
$params['keywords'] = $this->SpellingSuggestions($params);
return $this->Application->ProcessParsedTag('m', 'Link', $params);
}
function InitCatalogTab($params)
{
$tab_params['mode'] = $this->Application->GetVar('tm'); // single/multi selection possible
$tab_params['special'] = $this->Application->GetVar('ts'); // use special for this tab
$tab_params['dependant'] = $this->Application->GetVar('td'); // is grid dependant on categories grid
// set default params (same as in catalog)
if ($tab_params['mode'] === false) $tab_params['mode'] = 'multi';
if ($tab_params['special'] === false) $tab_params['special'] = '';
if ($tab_params['dependant'] === false) $tab_params['dependant'] = 'yes';
// pass params to block with tab content
$params['name'] = $params['render_as'];
$special = $tab_params['special'] ? $tab_params['special'] : $this->Special;
$params['prefix'] = trim($this->Prefix.'.'.$special, '.');
$prefix_append = $this->Application->GetVar('prefix_append');
if ($prefix_append) {
$params['prefix'] .= $prefix_append;
}
$default_grid = array_key_exists('default_grid', $params) ? $params['default_grid'] : 'Default';
$radio_grid = array_key_exists('radio_grid', $params) ? $params['radio_grid'] : 'Radio';
$params['cat_prefix'] = trim('c.'.($tab_params['special'] ? $tab_params['special'] : $this->Special), '.');
$params['tab_mode'] = $tab_params['mode'];
$params['grid_name'] = ($tab_params['mode'] == 'multi') ? $default_grid : $radio_grid;
$params['tab_dependant'] = $tab_params['dependant'];
$params['show_category'] = $tab_params['special'] == 'showall' ? 1 : 0; // this is advanced view -> show category name
if ($special == 'showall' || $special == 'user') {
$params['grid_name'] .= 'ShowAll';
}
// use $pass_params to be able to pass 'tab_init' parameter from m_ModuleInclude tag
return $this->Application->ParseBlock($params, 1);
}
/**
* Show CachedNavbar of current item primary category
*
* @param Array $params
* @return string
*/
function CategoryName($params)
{
// show category cachednavbar of
$object =& $this->getObject($params);
/* @var $object kDBItem */
$category_id = isset($params['cat_id']) ? $params['cat_id'] : $object->GetDBField('CategoryId');
$cache_key = 'category_paths[%CIDSerial:' . $category_id . '%][%PhrasesSerial%][Adm:' . (int)$this->Application->isAdmin . ']';
$category_path = $this->Application->getCache($cache_key);
if ($category_path === false) {
// not chached
if ($category_id > 0) {
$cached_navbar = $object->GetField('CachedNavbar');
if ($category_id == $object->GetDBField('ParentId')) {
// parent category cached navbar is one element smaller, then current ones
$cached_navbar = explode('&|&', $cached_navbar);
array_pop($cached_navbar);
$cached_navbar = implode('&|&', $cached_navbar);
}
else {
// no relation with current category object -> query from db
$language_id = (int)$this->Application->GetVar('m_lang');
if (!$language_id) {
$language_id = 1;
}
$sql = 'SELECT l' . $language_id . '_CachedNavbar
FROM ' . $object->TableName . '
WHERE ' . $object->IDField . ' = ' . $category_id;
$cached_navbar = $this->Conn->GetOne($sql);
}
$cached_navbar = preg_replace('/^(Content&\|&|Content)/i', '', $cached_navbar);
$category_path = trim($this->CategoryName( Array('cat_id' => 0) ).' > '.str_replace('&|&', ' > ', $cached_navbar), ' > ');
}
else {
$category_path = $this->Application->Phrase(($this->Application->isAdmin ? 'la_' : 'lu_') . 'rootcategory_name');
}
$this->Application->setCache($cache_key, $category_path);
}
return $category_path;
}
// structure related
/**
* Returns page object based on requested params
*
* @param Array $params
* @return CategoriesItem
*/
function &_getPage($params)
{
$page =& $this->Application->recallObject($this->Prefix . '.-virtual', null, $params);
/* @var $page kDBItem */
// 1. load by given id
$page_id = array_key_exists('page_id', $params) ? $params['page_id'] : false;
if ($page_id) {
if ($page_id != $page->GetID()) {
// load if different
$page->Load($page_id);
}
return $page;
}
// 2. load by template
$template = array_key_exists('page', $params) ? $params['page'] : '';
if (!$template) {
$template = $this->Application->GetVar('t');
}
// different path in structure AND design template differes from requested template
$structure_path_match = strtolower( $page->GetDBField('NamedParentPath') ) == strtolower('Content/' . $template);
$design_match = $page->GetDBField('CachedTemplate') == $template;
if (!$structure_path_match && !$design_match) {
// Same sql like in "c:getPassedID". Load, when current page object doesn't match requested page object
$themes_helper =& $this->Application->recallObject('ThemesHelper');
/* @var $themes_helper kThemesHelper */
$page_id = $themes_helper->getPageByTemplate($template);
$page->Load($page_id);
}
return $page;
}
/**
* Returns requested content block content of current or specified page
*
* @param Array $params
* @return string
*/
function ContentBlock($params)
{
$num = getArrayValue($params, 'num');
if (!$num) {
return 'NO CONTENT NUM SPECIFIED';
}
$page =& $this->_getPage($params);
/* @var $page kDBItem */
if (!$page->isLoaded()) {
// page is not created yet => all blocks are empty
return '';
}
$page_id = $page->GetID();
$content =& $this->Application->recallObject('content.-block', null, Array ('skip_autoload' => true));
/* @var $content kDBItem */
$data = Array ('PageId' => $page_id, 'ContentNum' => $num);
$content->Load($data);
if (!$content->isLoaded()) {
// bug: missing content blocks are created even if user have no SMS-management rights
$content->SetFieldsFromHash($data);
$content->Create();
}
$edit_code_before = $edit_code_after = '';
if (EDITING_MODE == EDITING_MODE_CONTENT) {
$bg_color = isset($params['bgcolor']) ? $params['bgcolor'] : '#ffffff';
$url_params = Array (
'pass' => 'm,c,content',
'm_opener' => 'd',
'c_id' => $page->GetID(),
'content_id' => $content->GetID(),
'front' => 1,
'admin' => 1,
'__URLENCODE__' => 1,
'__NO_REWRITE__'=> 1,
'escape' => 1,
'index_file' => 'index.php',
// 'bgcolor' => $bg_color,
// '__FORCE_SID__' => 1
);
// link from Front-End to admin, don't remove "index.php"
$edit_url = $this->Application->HREF('categories/edit_content', ADMIN_DIRECTORY, $url_params, 'index.php');
$edit_code_before = '
<div class="cms-edit-btn-container">
<div class="cms-edit-btn" onclick="$form_name=\'kf_cont_'.$content->GetID().'\'; std_edit_item(\'content\', \'categories/edit_content\');">
<div class="cms-btn-image">
<img src="' . $this->Application->BaseURL() . 'core/admin_templates/img/top_frame/icons/content_mode.png" width="15" height="16" alt=""/>
</div>
<div class="cms-btn-text">' . $this->Application->Phrase('la_btn_EditContent', false, true) . ' '.(defined('DEBUG_MODE') && DEBUG_MODE ? " - #{$num}" : '').'</div>
</div>
<div class="cms-btn-content">';
$edit_form = '<form method="POST" style="display: inline; margin: 0px" name="kf_cont_'.$content->GetID().'" id="kf_cont_'.$content->GetID().'" action="'.$edit_url.'">';
$edit_form .= '<input type="hidden" name="c_id" value="'.$page->GetID().'"/>';
$edit_form .= '<input type="hidden" name="content_id" value="'.$content->GetID().'"/>';
$edit_form .= '<input type="hidden" name="front" value="1"/>';
$edit_form .= '<input type="hidden" name="bgcolor" value="'.$bg_color.'"/>';
$edit_form .= '<input type="hidden" name="m_lang" value="'.$this->Application->GetVar('m_lang').'"/>';
$edit_form .= '</form>';
$edit_code_after = '</div></div>';
if (array_key_exists('forms_later', $params) && $params['forms_later']) {
$all_forms = $this->Application->GetVar('all_forms');
$this->Application->SetVar('all_forms', $all_forms . $edit_form);
}
else {
$edit_code_after .= $edit_form;
}
}
if ($this->Application->GetVar('_editor_preview_') == 1) {
$data = $this->Application->RecallVar('_editor_preview_content_');
} else {
$data = $content->GetField('Content');
}
$data = $edit_code_before . $this->_transformContentBlockData($data, $params) . $edit_code_after;
if ($data != '') {
$this->Application->Parser->DataExists = true;
}
return $data;
}
/**
* Apply all kinds of content block data transformations without rewriting ContentBlock tag
*
* @param string $data
* @param Array $params
* @return string
*/
function _transformContentBlockData(&$data, $params)
{
return $data;
}
/**
* Returns current page name or page based on page/page_id parameters
*
* @param Array $params
* @return string
* @todo Used?
*/
function PageName($params)
{
$page =& $this->_getPage($params);
return $page->GetDBField('Name');
}
/**
* Returns current/given page information
*
* @param Array $params
* @return string
*/
function PageInfo($params)
{
$page =& $this->_getPage($params);
switch ($params['type']) {
case 'title':
$db_field = 'Title';
break;
case 'htmlhead_title':
$db_field = 'Name';
break;
case 'meta_title':
$db_field = 'MetaTitle';
break;
case 'menu_title':
$db_field = 'MenuTitle';
break;
case 'meta_keywords':
$db_field = 'MetaKeywords';
$cat_field = 'Keywords';
break;
case 'meta_description':
$db_field = 'MetaDescription';
$cat_field = 'Description';
break;
case 'tracking':
case 'index_tools':
if (!EDITING_MODE) {
$tracking = $page->GetDBField('IndexTools');
return $tracking ? $tracking : $this->Application->ConfigValue('cms_DefaultTrackingCode');
}
// no break here on purpose
default:
return '';
}
$default = isset($params['default']) ? $params['default'] : '';
$val = $page->GetField($db_field);
if (!$default) {
if ($this->Application->isModuleEnabled('In-Portal')) {
if (!$val && ($params['type'] == 'meta_keywords' || $params['type'] == 'meta_description')) {
// take category meta if it's not set for the page
return $this->Application->ProcessParsedTag('c', 'Meta', Array('name' => $cat_field));
}
}
}
if (isset($params['force_default']) && $params['force_default']) {
return $default;
}
if (preg_match('/^_Auto:/', $val)) {
$val = $default;
/*if ($db_field == 'Title') {
$page->SetDBField($db_field, $default);
$page->Update();
}*/
}
elseif ($page->GetID() == false) {
return $default;
}
return $val;
}
/**
* Includes admin css and js, that are required for cms usage on Front-Edn
*
* @param Array $params
* @return string
* @access protected
*/
protected function EditingScripts($params)
{
if ( $this->Application->GetVar('admin_scripts_included') || !EDITING_MODE ) {
return '';
}
$this->Application->SetVar('admin_scripts_included', 1);
$js_url = $this->Application->BaseURL() . 'core/admin_templates/js';
$minify_helper =& $this->Application->recallObject('MinifyHelper');
/* @var $minify_helper MinifyHelper */
$to_compress = Array (
$js_url . '/jquery/thickbox/thickbox.css',
$js_url . '/../incs/cms.css',
);
$css_compressed = $minify_helper->CompressScriptTag(Array ('files' => implode('|', $to_compress)));
$ret = '<link rel="stylesheet" href="' . $css_compressed . '" type="text/css" media="screen"/>' . "\n";
if ( EDITING_MODE == EDITING_MODE_DESIGN ) {
$ret .= ' <style type="text/css" media="all">
div.movable-element .movable-header { cursor: move; }
</style>';
}
$ret .= '<script type="text/javascript" src="' . $js_url . '/jquery/jquery.pack.js"></script>' . "\n";
$ret .= '<script type="text/javascript" src="' . $js_url . '/jquery/jquery-ui.custom.min.js"></script>' . "\n";
$to_compress = Array (
$js_url . '/is.js',
$js_url . '/application.js',
$js_url . '/script.js',
$js_url . '/jquery/thickbox/thickbox.js',
$js_url . '/template_manager.js',
);
$js_compressed = $minify_helper->CompressScriptTag( Array ('files' => implode('|', $to_compress)) );
$ret .= '<script type="text/javascript" src="' . $js_compressed . '"></script>' . "\n";
$ret .= '<script language="javascript">' . "\n";
$ret .= "TB.pathToImage = '" . $js_url . "/jquery/thickbox/loadingAnimation.gif';" . "\n";
$template = $this->Application->GetVar('t');
$theme_id = $this->Application->GetVar('m_theme');
$url_params = Array ('block' => '#BLOCK#', 'theme-file_event' => '#EVENT#', 'theme_id' => $theme_id, 'source' => $template, 'pass' => 'all,theme-file', 'front' => 1, 'm_opener' => 'd', '__NO_REWRITE__' => 1, 'no_amp' => 1);
$edit_template_url = $this->Application->HREF('themes/template_edit', ADMIN_DIRECTORY, $url_params, 'index.php');
$url_params = Array ('theme-file_event' => 'OnSaveLayout', 'source' => $template, 'pass' => 'all,theme-file', '__NO_REWRITE__' => 1, 'no_amp' => 1);
$save_layout_url = $this->Application->HREF('index', '', $url_params);
$this_url = $this->Application->HREF('', '', Array ('editing_mode' => '#EDITING_MODE#', '__NO_REWRITE__' => 1, 'no_amp' => 1));
$ret .= "var aTemplateManager = new TemplateManager('" . $edit_template_url . "', '" . $this_url . "', '" . $save_layout_url . "', " . (int)EDITING_MODE . ");\n";
$ret .= "var main_title = '" . addslashes( $this->Application->ConfigValue('Site_Name') ) . "';" . "\n";
$use_popups = (int)$this->Application->ConfigValue('UsePopups');
$ret .= "var \$use_popups = " . ($use_popups > 0 ? 'true' : 'false') . ";\n";
$ret .= "var \$modal_windows = " . ($use_popups == 2 ? 'true' : 'false') . ";\n";
if ( EDITING_MODE != EDITING_MODE_BROWSE ) {
$ret .= "var base_url = '" . $this->Application->BaseURL() . "';" . "\n";
$ret .= 'TB.closeHtml = \'<img src="' . $js_url . '/../img/close_window15.gif" width="15" height="15" style="border-width: 0px;" alt="close"/><br/>\';' . "\n";
$url_params = Array ('m_theme' => '', 'pass' => 'm', 'm_opener' => 'r', '__NO_REWRITE__' => 1, 'no_amp' => 1);
$browse_url = $this->Application->HREF('catalog/catalog', ADMIN_DIRECTORY, $url_params, 'index.php');
$browse_url = preg_replace('/&(admin|editing_mode)=[\d]/', '', $browse_url);
$ret .= '
var topmost = window.top;
topmost.document.title = document.title + \' - ' . addslashes($this->Application->Phrase('la_AdministrativeConsole', false)) . '\';
t = \'' . $this->Application->GetVar('t') . '\';
if (window.parent.frames["menu"] != undefined) {
if ( $.isFunction(window.parent.frames["menu"].SyncActive) ) {
window.parent.frames["menu"].SyncActive("' . $browse_url . '");
}
}
';
}
$ret .= '</script>' . "\n";
if ( EDITING_MODE != EDITING_MODE_BROWSE ) {
// add form, so admin scripts could work
$ret .= '<form id="kernel_form" name="kernel_form" enctype="multipart/form-data" method="post" action="' . $browse_url . '">
<input type="hidden" name="MAX_FILE_SIZE" id="MAX_FILE_SIZE" value="' . MAX_UPLOAD_SIZE . '" />
<input type="hidden" name="sid" id="sid" value="' . $this->Application->GetSID() . '" />
</form>';
}
return $ret;
}
/**
* Prints "Edit Page" button on cms page
*
* @param Array $params
* @return string
*/
function EditPage($params)
{
if (!EDITING_MODE) {
return '';
}
$display_mode = array_key_exists('mode', $params) ? $params['mode'] : false;
$edit_code = '';
$page =& $this->_getPage($params);
if (!$page->isLoaded() || (($display_mode != 'end') && (EDITING_MODE == EDITING_MODE_BROWSE))) {
// when "EditingScripts" tag is not used, make sure, that scripts are also included
return $this->EditingScripts($params);
}
// show "EditPage" button only for pages, that exists in structure
if ($display_mode != 'end') {
$edit_btn = '';
if (EDITING_MODE == EDITING_MODE_CONTENT) {
$url_params = Array(
'pass' => 'm,c',
'm_opener' => 'd',
'c_id' => $page->GetID(),
'c_mode' => 't',
'c_event' => 'OnEdit',
'front' => 1,
'__URLENCODE__' => 1,
'__NO_REWRITE__'=> 1,
'index_file' => 'index.php',
);
$edit_url = $this->Application->HREF('categories/categories_edit', ADMIN_DIRECTORY, $url_params);
$edit_btn .= '
<div class="cms-section-properties-btn"' . ($display_mode === false ? ' style="margin: 0px;"' : '') . ' onmouseover="window.status=\'' . addslashes($edit_url) . '\'; return true" onclick="$form_name=\'kf_'.$page->GetID().'\'; std_edit_item(\'c\', \'categories/categories_edit\');">
<div class="cms-btn-image">
<img src="' . $this->Application->BaseURL() . 'core/admin_templates/img/top_frame/icons/section_properties.png" width="15" height="16" alt=""/>
</div>
<div class="cms-btn-text">' . $this->Application->Phrase('la_btn_SectionProperties', false, true) . '</div>
</div>' . "\n";
} elseif (EDITING_MODE == EDITING_MODE_DESIGN) {
$url_params = Array(
'pass' => 'm,theme,theme-file',
'm_opener' => 'd',
'theme_id' => $this->Application->GetVar('m_theme'),
'theme_mode' => 't',
'theme_event' => 'OnEdit',
'theme-file_id' => $this->_getThemeFileId(),
'front' => 1,
'__URLENCODE__' => 1,
'__NO_REWRITE__'=> 1,
'index_file' => 'index.php',
);
$edit_url = $this->Application->HREF('themes/file_edit', ADMIN_DIRECTORY, $url_params);
$edit_btn .= '
<div class="cms-layout-btn-container"' . ($display_mode === false ? ' style="margin: 0px;"' : '') . '>
<div class="cms-save-layout-btn" onclick="aTemplateManager.saveLayout(); return false;">
<div class="cms-btn-image">
<img src="' . $this->Application->BaseURL() . 'core/admin_templates/img/top_frame/icons/save_button.gif" width="16" height="16" alt=""/>
</div>
<div class="cms-btn-text">' . $this->Application->Phrase('la_btn_SaveChanges', false, true) . '</div>
</div>
<div class="cms-cancel-layout-btn" onclick="aTemplateManager.cancelLayout(); return false;">
<div class="cms-btn-image">
<img src="' . $this->Application->BaseURL() . 'core/admin_templates/img/top_frame/icons/cancel_button.gif" width="16" height="16" alt=""/>
</div>
<div class="cms-btn-text">' . $this->Application->Phrase('la_btn_Cancel', false, true) . '</div>
</div>
</div>
<div class="cms-section-properties-btn"' . ($display_mode === false ? ' style="margin: 0px;"' : '') . ' onmouseover="window.status=\'' . addslashes($edit_url) . '\'; return true" onclick="$form_name=\'kf_'.$page->GetID().'\'; std_edit_item(\'theme\', \'themes/file_edit\');">
<div class="cms-btn-image">
<img src="' . $this->Application->BaseURL() . 'core/admin_templates/img/top_frame/icons/section_properties.png" width="15" height="16" alt=""/>
</div>
<div class="cms-btn-text">' . $this->Application->Phrase('la_btn_SectionTemplate', false, true) . '</div>
</div>' . "\n";
}
if ($display_mode == 'start') {
// button with border around the page
$edit_code .= '<div class="cms-section-properties-btn-container">' . $edit_btn . '<div class="cms-btn-content">';
}
else {
// button without border around the page
$edit_code .= $edit_btn;
}
}
if ($display_mode == 'end') {
// draw border around the page
$edit_code .= '</div></div>';
}
if ($display_mode != 'end') {
$edit_code .= '<form method="POST" style="display: inline; margin: 0px" name="kf_'.$page->GetID().'" id="kf_'.$page->GetID().'" action="'.$edit_url.'"></form>';
// when "EditingScripts" tag is not used, make sure, that scripts are also included
$edit_code .= $this->EditingScripts($params);
}
return $edit_code;
}
function _getThemeFileId()
{
$template = $this->Application->GetVar('t');
if (!$this->Application->TemplatesCache->TemplateExists($template) && !$this->Application->isAdmin) {
$cms_handler =& $this->Application->recallObject($this->Prefix . '_EventHandler');
/* @var $cms_handler CategoriesEventHandler */
$template = ltrim($cms_handler->GetDesignTemplate(), '/');
}
$file_path = dirname($template) == '.' ? '' : '/' . dirname($template);
$file_name = basename($template);
$sql = 'SELECT FileId
FROM ' . TABLE_PREFIX . 'ThemeFiles
WHERE (ThemeId = ' . (int)$this->Application->GetVar('m_theme') . ') AND (FilePath = ' . $this->Conn->qstr($file_path) . ') AND (FileName = ' . $this->Conn->qstr($file_name . '.tpl') . ')';
return $this->Conn->GetOne($sql);
}
/**
* Builds site menu
*
* @param Array $params
* @return string
*/
function CachedMenu($params)
{
$menu_helper =& $this->Application->recallObject('MenuHelper');
/* @var $menu_helper MenuHelper */
return $menu_helper->menuTag($this->getPrefixSpecial(), $params);
}
/**
* Trick to allow some kind of output formatting when using CachedMenu tag
*
* @param Array $params
* @return bool
*/
function SplitColumn($params)
{
return $this->Application->GetVar($params['i']) > ceil($params['total'] / $params['columns']);
}
/**
* Returns direct children count of given category
*
* @param Array $params
* @return int
*/
function HasSubCats($params)
{
$sql = 'SELECT COUNT(*)
FROM ' . TABLE_PREFIX . 'Category
WHERE ParentId = ' . $params['cat_id'];
return $this->Conn->GetOne($sql);
}
/**
* Prints sub-pages of given/current page.
*
* @param Array $params
* @return string
* @todo This could be reached by using "parent_cat_id" parameter. Only difference here is new block parameter "path". Need to rewrite.
*/
function PrintSubPages($params)
{
$list =& $this->Application->recallObject($this->getPrefixSpecial(), $this->Prefix.'_List', $params);
/* @var $list kDBList */
$category_id = array_key_exists('category_id', $params) ? $params['category_id'] : $this->Application->GetVar('m_cat_id');
$list->addFilter('current_pages', TABLE_PREFIX . 'CategoryItems.CategoryId = ' . $category_id);
$list->Query();
$list->GoFirst();
$o = '';
$block_params = $this->prepareTagParams($params);
$block_params['name'] = $params['render_as'];
while (!$list->EOL()) {
$block_params['path'] = $list->GetDBField('Path');
$o .= $this->Application->ParseBlock($block_params);
$list->GoNext();
}
return $o;
}
/**
* Builds link for browsing current page on Front-End
*
* @param Array $params
* @return string
*/
function PageBrowseLink($params)
{
$object =& $this->getObject($params);
/* @var $object kDBItem */
$themes_helper =& $this->Application->recallObject('ThemesHelper');
/* @var $themes_helper kThemesHelper */
$site_config_helper =& $this->Application->recallObject('SiteConfigHelper');
/* @var $site_config_helper SiteConfigHelper */
$settings = $site_config_helper->getSettings();
$url_params = Array (
'm_cat_id' => $object->GetID(),
'm_theme' => $themes_helper->getCurrentThemeId(),
'editing_mode' => $settings['default_editing_mode'],
'pass' => 'm',
'admin' => 1,
'index_file' => 'index.php'
);
if ($this->Application->ConfigValue('UseModRewrite')) {
$url_params['__MOD_REWRITE__'] = 1;
}
return $this->Application->HREF($object->GetDBField('NamedParentPath'), '_FRONT_END_', $url_params);
}
function DirectLink($params)
{
$object =& $this->getObject($params);
/* @var $object kDBItem */
$themes_helper =& $this->Application->recallObject('ThemesHelper');
/* @var $themes_helper kThemesHelper */
$url_params = Array (
'm_cat_id' => $object->GetID(),
'm_theme' => $themes_helper->getCurrentThemeId(),
'pass' => 'm',
'index_file' => 'index.php',
'authkey' => $object->GetDBField('DirectLinkAuthKey'),
);
if ($this->Application->ConfigValue('UseModRewrite')) {
$url_params['__MOD_REWRITE__'] = 1;
}
return $this->Application->HREF($object->GetDBField('NamedParentPath'), '_FRONT_END_', $url_params);
}
/**
* Builds link to cms page (used?)
*
* @param Array $params
* @return string
*/
function ContentPageLink($params)
{
$object =& $this->getObject($params);
/* @var $object kDBItem */
$params['t'] = $object->GetDBField('NamedParentPath');
$params['m_cat_id'] = 0;
return $this->Application->ProcessParsedTag('m', 'Link', $params);
}
/**
* Prepares cms page description for search result page
*
* @param Array $params
* @return string
*/
function SearchDescription($params)
{
$object =& $this->getObject($params);
$desc = $object->GetField('MetaDescription');
if (!$desc) {
$sql = 'SELECT *
FROM ' . TABLE_PREFIX . 'PageContent
WHERE PageId = ' . $object->GetID() . ' AND ContentNum = 1';
$content = $this->Conn->GetRow($sql);
if ($content['l'.$this->Application->GetVar('m_lang').'_Content']) {
$desc = $content['l'.$this->Application->GetVar('m_lang').'_Content'];
}
else {
$desc = $content['l'.$this->Application->GetDefaultLanguageId().'_Content'];
}
}
return mb_substr($desc, 0, 300).(mb_strlen($desc) > 300 ? '...' : '');
}
/**
* Simplified version of "c:CategoryLink" for "c:PrintList"
*
* @param Array $params
* @return string
* @todo Used? Needs refactoring.
*/
function EnterCatLink($params)
{
$object =& $this->getObject($params);
$url_params = Array ('pass' => 'm', 'm_cat_id' => $object->GetID());
return $this->Application->HREF($params['template'], '', $url_params);
}
/**
* Simplified version of "c:CategoryPath", that do not use blocks for rendering
*
* @param Array $params
* @return string
* @todo Used? Maybe needs to be removed.
*/
function PagePath($params)
{
$object =& $this->getObject($params);
$path = $object->GetField('CachedNavbar');
if ($path) {
$items = explode('&|&', $path);
array_shift($items);
return implode(' -&gt; ', $items);
}
return '';
}
/**
* Returns configuration variable value
*
* @param Array $params
* @return string
* @todo Needs to be replaced with "m:GetConfig" tag; Not used now (were used on structure_edit.tpl).
*/
function AllowManualFilenames($params)
{
return $this->Application->ConfigValue('ProjCMSAllowManualFilenames');
}
/**
* Draws path to current page (each page can be link to it)
*
* @param Array $params
* @return string
*/
function CurrentPath($params)
{
$block_params = $this->prepareTagParams($params);
$block_params['name'] = $block_params['render_as'];
$object =& $this->Application->recallObject($this->Prefix);
/* @var $object kDBItem */
$category_ids = explode('|', substr($object->GetDBField('ParentPath'), 1, -1));
$id_field = $this->Application->getUnitOption($this->Prefix, 'IDField');
$table_name = $this->Application->getUnitOption($this->Prefix, 'TableName');
$language = (int)$this->Application->GetVar('m_lang');
if (!$language) {
$language = 1;
}
$sql = 'SELECT l'.$language.'_Name AS Name, NamedParentPath
FROM '.$table_name.'
WHERE '.$id_field.' IN ('.implode(',', $category_ids).')';
$categories_data = $this->Conn->Query($sql);
$ret = '';
foreach ($categories_data as $index => $category_data) {
if ($category_data['Name'] == 'Content') {
continue;
}
$block_params['title'] = $category_data['Name'];
$block_params['template'] = preg_replace('/^Content\//i', '', $category_data['NamedParentPath']);
$block_params['is_first'] = $index == 1; // because Content is 1st element
$block_params['is_last'] = $index == count($categories_data) - 1;
$ret .= $this->Application->ParseBlock($block_params);
}
return $ret;
}
/**
* Synonim to PrintList2 for "onlinestore" theme
*
* @param Array $params
* @return string
*/
function ListPages($params)
{
return $this->PrintList2($params);
}
/**
* Returns information about parser element locations in template
*
* @param Array $params
* @return mixed
*/
function BlockInfo($params)
{
if (!EDITING_MODE) {
return '';
}
$template_helper =& $this->Application->recallObject('TemplateHelper');
/* @var $template_helper TemplateHelper */
return $template_helper->blockInfo( $params['name'] );
}
/**
* Hide all editing tabs except permission tab, when editing "Home" (ID = 0) category
*
* @param Array $params
*/
function ModifyUnitConfig($params)
{
$root_category = $this->Application->RecallVar('IsRootCategory_' . $this->Application->GetVar('m_wid'));
if (!$root_category) {
return ;
}
$edit_tab_presets = $this->Application->getUnitOption($this->Prefix, 'EditTabPresets');
$edit_tab_presets['Default'] = Array (
'permissions' => $edit_tab_presets['Default']['permissions'],
);
$this->Application->setUnitOption($this->Prefix, 'EditTabPresets', $edit_tab_presets);
}
/**
* Prints catalog export templates
*
* @param Array $params
* @return string
*/
function PrintCatalogExportTemplates($params)
{
$prefixes = explode(',', $params['prefixes']);
$ret = Array ();
foreach ($prefixes as $prefix) {
if ($this->Application->prefixRegistred($prefix)) {
$module_path = $this->Application->getUnitOption($prefix, 'ModuleFolder') . '/';
$module_name = $this->Application->findModule('Path', $module_path, 'Name');
$ret[$prefix] = mb_strtolower($module_name) . '/export';
}
}
$json_helper =& $this->Application->recallObject('JSONHelper');
/* @var $json_helper JSONHelper */
return $json_helper->encode($ret);
}
/**
* Checks, that "view in browse mode" functionality available
*
* @param Array $params
* @return bool
*/
function BrowseModeAvailable($params)
{
$valid_special = $params['Special'] != 'user';
$not_selector = $this->Application->GetVar('type') != 'item_selector';
return $valid_special && $not_selector;
}
/**
* Returns a link for editing product
*
* @param Array $params
* @return string
*/
function ItemEditLink($params)
{
$object =& $this->getObject();
/* @var $object kDBList */
$edit_template = $this->Application->getUnitOption($this->Prefix, 'AdminTemplatePath') . '/' . $this->Application->getUnitOption($this->Prefix, 'AdminTemplatePrefix') . 'edit';
$url_params = Array (
'm_opener' => 'd',
$this->Prefix.'_mode' => 't',
$this->Prefix.'_event' => 'OnEdit',
$this->Prefix.'_id' => $object->GetID(),
'm_cat_id' => $object->GetDBField('ParentId'),
'pass' => 'all,'.$this->Prefix,
'no_pass_through' => 1,
);
return $this->Application->HREF($edit_template,'', $url_params);
}
function RelevanceIndicator($params)
{
$object =& $this->getObject($params);
/* @var $object kDBItem */
$search_results_table = TABLE_PREFIX.'ses_'.$this->Application->GetSID().'_'.TABLE_PREFIX.'Search';
$sql = 'SELECT Relevance
FROM '.$search_results_table.'
WHERE ResourceId = '.$object->GetDBField('ResourceId');
$percents_off = (int)(100 - (100 * $this->Conn->GetOne($sql)));
$percents_off = ($percents_off < 0) ? 0 : $percents_off;
if ($percents_off) {
$params['percent_off'] = $percents_off;
$params['percent_on'] = 100 - $percents_off;
$params['name'] = $this->SelectParam($params, 'relevance_normal_render_as,block_relevance_normal');
}
else {
$params['name'] = $this->SelectParam($params, 'relevance_full_render_as,block_relevance_full');
}
return $this->Application->ParseBlock($params);
}
/**
* Returns list of categories, that have category add/edit permission
*
* @param Array $params
* @return string
*/
function AllowedCategoriesJSON($params)
{
if ($this->Application->RecallVar('user_id') == USER_ROOT) {
$categories = true;
}
else {
$object =& $this->getObject($params);
/* @var $object kDBItem */
$perm_helper =& $this->Application->recallObject('PermissionsHelper');
/* @var $perm_helper kPermissionsHelper */
$perm_prefix = $this->Application->getUnitOption($this->Prefix, 'PermItemPrefix');
$categories = $perm_helper->getPermissionCategories($perm_prefix . '.' . ($object->IsNewItem() ? 'ADD' : 'MODIFY'));
}
$json_helper =& $this->Application->recallObject('JSONHelper');
/* @var $json_helper JSONHelper */
return $json_helper->encode($categories);
}
function PageEditable($params)
{
if ($this->Application->isDebugMode()) {
return true;
}
$object =& $this->getObject($params);
/* @var $object kDBItem */
return !$object->GetDBField('Protected');
}
}
\ No newline at end of file
Index: branches/5.2.x/core/units/helpers/email_message_helper.php
===================================================================
--- branches/5.2.x/core/units/helpers/email_message_helper.php (revision 14747)
+++ branches/5.2.x/core/units/helpers/email_message_helper.php (revision 14748)
@@ -1,76 +1,90 @@
<?php
-
- class EmailMessageHelper extends kHelper {
-
- /**
- * Extracts Subject, Headers, Body fields from email message translation
- *
- * @param string $text
- * @return Array
- */
- function parseTemplate($text)
- {
- $line_id = 1;
- $ret = Array ('Subject' => '', 'Headers' => '', 'Body' => '');
- $headers = Array();
- $lines = explode("\n", $text); // "\n" is lost in process
-
- foreach ($lines as $line_id => $line) {
- if (strlen(trim($line)) == 0 || ($line == '.')) {
- break;
- }
-
- $parts = explode(':', $line, 2);
- if (strtolower($parts[0]) == 'subject') {
- $ret['Subject'] = trim($parts[1]);
- }
- else {
- $headers[] = $line;
- }
+/**
+* @version $Id$
+* @package In-Portal
+* @copyright Copyright (C) 1997 - 2011 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 EmailMessageHelper extends kHelper {
+
+ /**
+ * Extracts Subject, Headers, Body fields from email message translation
+ *
+ * @param string $text
+ * @return Array
+ */
+ function parseTemplate($text)
+ {
+ $line_id = 1;
+ $ret = Array ('Subject' => '', 'Headers' => '', 'Body' => '');
+ $headers = Array();
+ $lines = explode("\n", $text); // "\n" is lost in process
+
+ foreach ($lines as $line_id => $line) {
+ if (strlen(trim($line)) == 0 || ($line == '.')) {
+ break;
}
- $ret['Headers'] = $headers ? implode("\n", $headers) : null; // it's null field
-
- $lines = array_slice($lines, $line_id + 1);
-
- // add "\n", that was lost before
- $ret['Body'] = implode("\n", $lines);
-
- return $ret;
+ $parts = explode(':', $line, 2);
+ if (strtolower($parts[0]) == 'subject') {
+ $ret['Subject'] = trim($parts[1]);
+ }
+ else {
+ $headers[] = $line;
+ }
}
- /**
- * Prepares email event content for language pack export
- *
- * @param Array $fields_hash
- * @return string
- */
- function buildTemplate($fields_hash)
- {
- if (!implode('', $fields_hash)) {
- return '';
- }
+ $ret['Headers'] = $headers ? implode("\n", $headers) : null; // it's null field
- $ret = array_key_exists('Headers', $fields_hash) ? $fields_hash['Headers'] : '';
- if ($ret) {
- $ret .= "\n";
- }
+ $lines = array_slice($lines, $line_id + 1);
- $ret = $this->_removeTrailingCRLF($ret);
- $ret .= 'Subject: ' . $fields_hash['Subject'] . "\n\n";
- $ret .= $fields_hash['Body'];
+ // add "\n", that was lost before
+ $ret['Body'] = implode("\n", $lines);
- return $ret;
+ return $ret;
+ }
+
+ /**
+ * Prepares email event content for language pack export
+ *
+ * @param Array $fields_hash
+ * @return string
+ */
+ function buildTemplate($fields_hash)
+ {
+ if (!implode('', $fields_hash)) {
+ return '';
}
- /**
- * Remove trailing CR/LF chars from string
- *
- * @param string $string
- * @return string
- */
- function _removeTrailingCRLF($string)
- {
- return preg_replace('/(\n|\r)+/',"\\1",$string);
+ $ret = array_key_exists('Headers', $fields_hash) ? $fields_hash['Headers'] : '';
+ if ($ret) {
+ $ret .= "\n";
}
- }
\ No newline at end of file
+
+ $ret = $this->_removeTrailingCRLF($ret);
+ $ret .= 'Subject: ' . $fields_hash['Subject'] . "\n\n";
+ $ret .= $fields_hash['Body'];
+
+ return $ret;
+ }
+
+ /**
+ * Remove trailing CR/LF chars from string
+ *
+ * @param string $string
+ * @return string
+ */
+ function _removeTrailingCRLF($string)
+ {
+ return preg_replace('/(\n|\r)+/',"\\1",$string);
+ }
+}
\ No newline at end of file
Index: branches/5.2.x/core/units/helpers/list_helper.php
===================================================================
--- branches/5.2.x/core/units/helpers/list_helper.php (revision 14747)
+++ branches/5.2.x/core/units/helpers/list_helper.php (revision 14748)
@@ -1,204 +1,218 @@
<?php
+/**
+* @version $Id$
+* @package In-Portal
+* @copyright Copyright (C) 1997 - 2011 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 ListHelper extends kHelper {
/**
* Detects, that current sorting of the list is not default
*
* @param kDBList $list
* @return bool
*/
function hasUserSorting(&$list)
{
static $cache = Array ();
if (array_key_exists($list->getPrefixSpecial(), $cache)) {
return $cache[ $list->getPrefixSpecial() ];
}
$user_sorting_start = $this->getUserSortIndex($list);
$sorting_configs = $this->Application->getUnitOption($list->Prefix, 'ConfigMapping', Array ());
$list_sortings = $this->Application->getUnitOption($list->Prefix, 'ListSortings', Array ());
$sorting_prefix = getArrayValue($list_sortings, $list->Special) ? $list->Special : '';
if (array_key_exists('DefaultSorting1Field', $sorting_configs)) {
$list_sortings[$sorting_prefix]['Sorting'] = Array (
$this->Application->ConfigValue($sorting_configs['DefaultSorting1Field']) => $this->Application->ConfigValue($sorting_configs['DefaultSorting1Dir']),
$this->Application->ConfigValue($sorting_configs['DefaultSorting2Field']) => $this->Application->ConfigValue($sorting_configs['DefaultSorting2Dir']),
);
}
$sorting = getArrayValue($list_sortings, $sorting_prefix, 'Sorting');
$sort_fields = is_array($sorting) ? array_keys($sorting) : Array ();
for ($order_number = 0; $order_number < 2; $order_number++) {
// current sorting in list
$sorting_pos = $user_sorting_start + $order_number;
$current_order_field = $list->GetOrderField($sorting_pos, true);
$current_order_direction = $list->GetOrderDirection($sorting_pos, true);
if (!$current_order_field || !$current_order_direction) {
// no sorting defined for this sorting position
continue;
}
// remove language prefix from field
$field_options = $list->GetFieldOptions($current_order_field);
if (array_key_exists('formatter', $field_options) && $field_options['formatter'] == 'kMultiLanguage') {
// remove language prefix
$current_order_field = preg_replace('/^l[\d]+_(.*)/', '\\1', $current_order_field);
}
// user sorting found
if (array_key_exists($order_number, $sort_fields)) {
// default sorting found
$default_order_field = $sort_fields[$order_number];
$default_order_direction = $sorting[$default_order_field]; // because people can write
if ($current_order_field != $default_order_field || strcasecmp($current_order_direction, $default_order_direction) != 0) {
// #1. user sorting differs from default sorting -> changed
$cache[ $list->getPrefixSpecial() ] = true;
return true;
}
}
else {
// #2. user sorting + no default sorting -> changed
$cache[ $list->getPrefixSpecial() ] = true;
return true;
}
}
// #3. user sorting match default or not defined -> not changed
$cache[ $list->getPrefixSpecial() ] = false;
return false;
}
/**
* Returns default per-page value for given prefix
*
* @param string $prefix
* @param int $default
* @return int
*/
function getDefaultPerPage($prefix, $default = 10)
{
$ret = false;
$config_mapping = $this->Application->getUnitOption($prefix, 'ConfigMapping');
if ($config_mapping) {
if (!array_key_exists('PerPage', $config_mapping)) {
trigger_error('Incorrect mapping of <span class="debug_error">PerPage</span> key in config for prefix <strong>' . $prefix . '</strong>', E_USER_WARNING);
}
$per_page = $this->Application->ConfigValue($config_mapping['PerPage']);
if ($per_page) {
return $per_page;
}
}
// none of checked above per-page locations are useful, then try default value
return $default;
}
/**
* Returns index where 1st changable sorting field begins
*
* @param kDBList $list
* @return int
* @todo This is copy of kDBTagProcessor::getUserSortIndex method.
* Can't call helper there, because it will slow down grid output
* when we have a lot of columns
*/
function getUserSortIndex(&$list)
{
$list_sortings = $this->Application->getUnitOption($list->Prefix, 'ListSortings', Array ());
$sorting_prefix = getArrayValue($list_sortings, $list->Special) ? $list->Special : '';
$user_sorting_start = 0;
$forced_sorting = getArrayValue($list_sortings, $sorting_prefix, 'ForcedSorting');
if ( $forced_sorting ) {
$user_sorting_start = count($forced_sorting);
}
return $user_sorting_start;
}
/**
* Returns ID of previous/next record related to current record
*
* @param kDBItem $object
* @param string $list_prefix
* @param bool $next
* @param string $select_fields
* @return int
*/
function getNavigationResource(&$object, $list_prefix, $next = true, $select_fields = null)
{
$list =& $this->Application->recallObject($list_prefix);
/* @var $list kDBList */
if ( !isset($select_fields) ) {
$select_fields = '%1$s.' . $object->IDField;
}
if ( is_array($select_fields) ) {
$select_fields = implode(', ', $select_fields);
}
$list->SetSelectSQL( str_replace(Array ('%1$s.*', '%2$s'), Array ($select_fields, ''), $list->GetPlainSelectSQL()) );
$operators = Array (
'asc' => $next ? '>' : '<',
'desc' => $next ? '<' : '>',
);
$where_clause = Array ();
$lang = $this->Application->GetVar('m_lang');
$order_fields = $order_fields_backup = $list->getOrderFields();
foreach ($order_fields as $index => $order) {
$where_clause[$index] = Array ();
if ( !$next ) {
$list->changeOrderDirection($index, $order_fields_backup[$index][1] == 'asc' ? 'desc' : 'asc');
}
for ($i = 0; $i <= $index; $i++) {
$order_field = $order_fields_backup[$i][0];
$is_expression = $order_fields_backup[$i][2];
if ( preg_match('/^IF\(COALESCE\(.*?\.(l' . $lang . '_.*?), ""\),/', $order_field, $regs) ) {
// undo result of kDBList::getMLSortField method
$order_field = $regs[1];
$is_expression = false;
}
$order_direction = $order_fields_backup[$i][1];
$field_prefix = $list->isVirtualField($order_field) || $is_expression ? '' : '%1$s.';
$actual_operator = $i == $index ? $operators[$order_direction] : '=';
$where_clause[$index][] = $field_prefix . $order_field . ' ' . $actual_operator . ' ' . $this->Conn->qstr($object->GetDBField($order_field));
}
$where_clause[$index] = '(' . implode(') AND (', $where_clause[$index]) . ')';
}
$where_clause = '(%1$s.' . $object->IDField . ' != ' . $object->GetID() . ') AND ((' . implode(') OR (', $where_clause) . '))';
$list->addFilter('navigation_filter', $where_clause);
$sql = $list->extractCalculatedFields($list->GetSelectSQL());
$list->removeFilter('navigation_filter');
$list->setOrderFields($order_fields_backup);
if ( $this->Application->isDebugMode() ) {
$this->Application->Debugger->appendHTML('Quering <strong>' . ($next ? 'next' : 'previous') . '</strong> item for "<strong>' . $list_prefix . '</strong>" list:');
}
return $this->Conn->GetOne($sql);
}
}
\ No newline at end of file
Index: branches/5.2.x/core/units/helpers/template_helper.php
===================================================================
--- branches/5.2.x/core/units/helpers/template_helper.php (revision 14747)
+++ branches/5.2.x/core/units/helpers/template_helper.php (revision 14748)
@@ -1,440 +1,442 @@
<?php
/**
* @version $Id$
* @package In-Portal
-* @copyright Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
+* @copyright Copyright (C) 1997 - 2011 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 TemplateHelper extends kHelper {
/**
* parser element location information
*
* @var Array
*/
var $_blockLocation = Array ();
/**
* Block name, that will be used
*
* @var string
*/
var $_blockName = '';
/**
* Function name, that represents compiled block
*
* @var sting
*/
var $_functionName = '';
/**
* Errors found during template parsing
*
* @var Array
*/
var $_parseErrors = Array ();
/**
* Source template, that is being edited
*
* @var string
*/
var $_sourceTemplate = '';
var $_initMade = false;
/**
* Performs init ot helper
*
* @param kDBItem $object
*/
function InitHelper(&$object)
{
if ($this->_initMade) {
return ;
}
// 1. get block information
$block_info = $this->Application->GetVar('block');
list ($this->_blockName, $this->_functionName) = explode(':', $block_info);
$this->_parseTemplate($object);
if (array_key_exists($this->_functionName, $this->Application->Parser->ElementLocations)) {
$this->_blockLocation = $this->Application->Parser->ElementLocations[$this->_functionName];
}
$this->_initMade = true;
}
function _getSourceTemplate()
{
// get source template
$t = $this->Application->GetVar('source');
if (!$this->Application->TemplatesCache->TemplateExists($t)) {
$cms_handler =& $this->Application->recallObject('st_EventHandler');
/* @var $cms_handler CategoriesEventHandler */
$t = ltrim($cms_handler->GetDesignTemplate($t), '/');
}
$this->_sourceTemplate = $t;
}
function _getThemeName()
{
$theme_id = (int)$this->Application->GetVar('theme_id');
$sql = 'SELECT Name
FROM ' . $this->Application->getUnitOption('theme', 'TableName') . '
WHERE ' . $this->Application->getUnitOption('theme', 'IDField') . ' = ' . $theme_id;
return $this->Conn->GetOne($sql);
}
/**
* Render source template to get parse errors OR it's element locations
*
* @param kDBItem $object
* @param string $append
* @return bool
*/
function _parseTemplate(&$object, $append = '')
{
try {
// 1. parse template
$this->Application->InitParser( $this->_getThemeName() ); // we have no parser when saving block content
$this->_getSourceTemplate();
// 2. design templates have leading "/" in the beginning
$this->Application->Parser->Run($this->_sourceTemplate . $append);
}
catch (ParserException $e) {
$this->_parseErrors[] = Array ('msg' => $e->getMessage(), 'file' => $e->getFile(), 'line' => $e->getLine());
}
if ($this->_parseErrors) {
if ($this->_isMainTemplate()) {
// 2.1. delete temporary file, that was parsed
$filename = $this->_getTemplateFile(false, $append . '.tpl');
if (!unlink($filename)) {
$error_file = $this->_getTemplateFile(true, $append . '.tpl');
$object->SetError('FileContents', 'template_delete_failed', '+Failed to delete temporary template "<strong>' . $error_file . '</strong>"');
return false;
}
}
else {
// 2.2. restore backup
if (!rename($this->_getTemplateFile(false, '.tpl.bak'), $this->_getTemplateFile(false))) {
$error_file = $this->_getTemplateFile(true);
$object->SetError('FileContents', 'template_restore_failed', '+Failed to restore template "<strong>' . $error_file . '</strong>" from backup.');
return false;
}
}
return false;
}
return true;
}
/**
* Move elements in template and save changes, when possible
*
* @param Array $target_order
* @return bool
*/
function moveTemplateElements($target_order)
{
// 2. parse template
$this->Application->InitParser(); // we have no parser when saving block content
$this->_getSourceTemplate();
$filename = $this->Application->TemplatesCache->GetRealFilename($this->_sourceTemplate) . '.tpl';
if (!is_writable($filename)) {
// we can't save changes, don't bother calculating new template contents
return false;
}
$data = file_get_contents($filename);
$line_ending = strpos($data, "\r") !== false ? "\r\n" : "\n";
// 1. get location of movable areas
$mask = '';
$start_pos = 0;
$elements = $area = Array ();
$areas = $this->_getDivPairs($data, 'movable-area');
foreach ($areas as $area_index => $area) {
// 1.1. get locations of all movable elements inside given area
$area_content = substr($area['data'], $area['open_len'], -$area['close_len']);
$elements = array_merge($elements, $this->_getDivPairs($area_content, 'movable-element', $area_index, $area['open_pos'] + $area['open_len']));
// 1.2. prepare mask to place movable elements into (don't include movable area div ifself)
$mask .= "\t" . substr($data, $start_pos, $area['open_pos'] + $area['open_len'] - $start_pos) . $line_ending . "\t\t" . '#AREA' . $area_index . '#' . $line_ending;
$start_pos = $area['close_pos'] - $area['close_len'];
}
$mask = trim($mask . "\t" . substr($data, $area['close_pos'] - $area['close_len']));
if (!$elements) {
// no elements found
return false;
}
foreach ($areas as $area_index => $area) {
$area_content = '';
$target_elements = $target_order[$area_index];
foreach ($target_order[$area_index] as $old_location) {
$area_content .= $elements[$old_location]['data'] . $line_ending . "\t\t";
}
$mask = str_replace('#AREA' . $area_index . '#', trim($area_content), $mask);
}
$fp = fopen($filename, 'w');
fwrite($fp, $mask);
fclose($fp);
return true;
}
/**
* Extracts div pairs with given class from given text
*
* @param string $data
* @param string $class
* @param int $area
* @param int $offset
* @return Array
*/
function _getDivPairs(&$data, $class, $area = null, $offset = 0)
{
preg_match_all('/(<div[^>]*>)|(<\/div>)/s', $data, $divs, PREG_SET_ORDER + PREG_OFFSET_CAPTURE);
$deep_level = 0;
$pairs = Array ();
$skip_count = Array (); // by deep level!
foreach ($divs as $div) {
if (strpos($div[0][0], '/') === false) {
// opening div
$skip_count[$deep_level] = 0;
if (strpos($div[0][0], $class) !== false) {
// ours opening (this deep level) -> save
$pair = Array ('open_pos' => $div[0][1], 'open_len' => strlen($div[0][0]));
}
else {
// not ours opening -> skip next closing (this deep level)
$skip_count[$deep_level]++;
}
$deep_level++;
}
else {
// closing div
$deep_level--;
if ($skip_count[$deep_level] == 0) {
// nothing to skip (this deep level) -> save
$pair['close_len'] = strlen($div[0][0]);
$pair['close_pos'] = $div[0][1] + $pair['close_len'];
$pair['data'] = substr($data, $pair['open_pos'], $pair['close_pos'] - $pair['open_pos']);
if (isset($area)) {
$pair['open_pos'] += $offset;
$pair['close_pos'] += $offset;
// index indicates area
$pairs['a' . $area . 'e' . count($pairs)] = $pair;
}
else {
$pairs[] = $pair;
}
}
else {
// skip closing div as requested
$skip_count[$deep_level]--;
}
}
}
return $pairs;
}
/**
* Returns information about parser element locations in template
*
* @param string $info_type
* @return mixed
*/
function blockInfo($info_type)
{
switch ($info_type) {
case 'block_name':
return $this->_blockName;
break;
case 'function_name':
return $this->_functionName;
break;
case 'start_pos':
case 'end_pos':
case 'template':
if (!array_key_exists($info_type, $this->_blockLocation)) {
// invalid block name
return 'invalid block name';
}
return $this->_blockLocation[$info_type];
break;
case 'template_file':
return $this->_getTemplateFile(true);
break;
case 'content':
$template_body = file_get_contents( $this->_getTemplateFile() );
$length = $this->_blockLocation['end_pos'] - $this->_blockLocation['start_pos'];
return substr($template_body, $this->_blockLocation['start_pos'], $length);
break;
}
return 'undefined';
}
/**
* Main template being edited (parse copy, instead of original)
*
* @return bool
*/
function _isMainTemplate()
{
return $this->_blockLocation['template'] == $this->_sourceTemplate;
}
/**
* Returns filename, that contains template, where block is located
*
* @param bool $relative
* @param string $extension
* @return string
*/
function _getTemplateFile($relative = false, $extension = '.tpl')
{
$filename = $this->Application->TemplatesCache->GetRealFilename( $this->_blockLocation['template'] ) . $extension;
if ($relative) {
$filename = preg_replace('/^' . preg_quote(FULL_PATH, '/') . '/', '', $filename, 1);
}
return $filename;
}
/**
* Saves new version of block to template, where it's located
*
* @param kDBItem $object
*/
function saveBlock(&$object)
{
$main_template = $this->_isMainTemplate();
$filename = $this->_getTemplateFile(false);
// 1. get new template content
$new_template_body = $this->_getNewTemplateContent($object, $filename, $lines_before);
if (is_bool($new_template_body) && ($new_template_body === true)) {
// when nothing changed -> stop processing
return true;
}
// 2. backup original template
if (!$main_template && !copy($filename, $filename . '.bak')) {
// backup failed
$error_file = $this->_getTemplateFile(true, '.tpl.bak');
$object->SetError('FileContents', 'template_backup_failed', '+Failed to create backup template "<strong>' . $error_file . '</strong>" backup.');
return false;
}
// 3. save changed template
$save_filename = $this->_getTemplateFile(false, $main_template ? '.tmp.tpl' : '.tpl');
$fp = fopen($save_filename, 'w');
if (!$fp) {
// backup template create failed OR existing template save
$error_file = $this->_getTemplateFile(true, $main_template ? '.tmp.tpl' : '.tpl');
$object->SetError('FileContents', 'template_changes_save_failed', '+Failed to save template "<strong>' . $error_file . '</strong>" changes.');
return false;
}
fwrite($fp, $new_template_body);
fclose($fp);
// 3. parse template to check for errors
$this->_parseTemplate($object, $main_template ? '.tmp' : '');
if ($this->_parseErrors) {
$error_msg = Array ();
foreach ($this->_parseErrors as $error_data) {
if (preg_match('/line ([\d]+)/', $error_data['msg'], $regs)) {
// another line number inside message -> patch it
$error_data['msg'] = str_replace('line ' . $regs[1], 'line ' . ($regs[1] - $lines_before), $error_data['msg']);
}
$error_msg[] = $error_data['msg'] . ' at line ' . ($error_data['line'] - $lines_before);
}
$object->SetError('FileContents', 'template_syntax_error', '+Template syntax errors:<br/>' . implode('<br/>', $error_msg));
return false;
}
if ($main_template) {
// 4.1. replace original file with temporary
if (!rename($this->_getTemplateFile(false, '.tmp.tpl'), $filename)) {
// failed to save new content to original template
$error_file = $this->_getTemplateFile(true);
$object->SetError('FileContents', 'template_save_failed', '+Failed to save template "<strong>' . $error_file . '</strong>".');
return false;
}
}
else {
// 4.2. delete backup
unlink( $this->_getTemplateFile(false, '.tpl.bak') );
}
return true;
}
/**
* Returns new template content of "true", when nothing is changed
*
* @param kDBItem $object
* @param string $filename
* @param int $lines_before
* @return mixed
*/
function _getNewTemplateContent(&$object, $filename, &$lines_before)
{
$new_content = $object->GetDBField('FileContents');
$template_body = file_get_contents($filename);
$lines_before = substr_count(substr($template_body, 0, $this->_blockLocation['start_pos']), "\n");
$new_template_body = substr($template_body, 0, $this->_blockLocation['start_pos']) .
$new_content .
substr($template_body, $this->_blockLocation['end_pos']);
return crc32($template_body) == crc32($new_template_body) ? true : $new_template_body;
}
}
\ No newline at end of file
Index: branches/5.2.x/core/units/helpers/xml_helper5.php
===================================================================
--- branches/5.2.x/core/units/helpers/xml_helper5.php (revision 14747)
+++ branches/5.2.x/core/units/helpers/xml_helper5.php (revision 14748)
@@ -1,83 +1,97 @@
<?php
+/**
+* @version $Id$
+* @package In-Portal
+* @copyright Copyright (C) 1997 - 2011 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 XMLIterator implements Iterator
{
private $var = array();
public function __construct($array)
{
if ( is_array($array) ) {
$this->var = $array;
}
}
public function rewind()
{
reset($this->var);
}
public function current()
{
$var = current($this->var);
return $var;
}
public function key()
{
$var = key($this->var);
return $var;
}
public function next()
{
$var = next($this->var);
return $var;
}
public function valid()
{
$var = $this->current() !== false;
return $var;
}
}
class kXMLNode5 extends kXMLNode implements IteratorAggregate {
public function getIterator()
{
$ret = new XMLIterator($this->Children);
return $ret;
}
public function __destruct()
{
// echo number_format(memory_get_usage()). ' &lt;-- Entered destructor for '.$this->Name.'<br/>';
unset($this->Attributes, $this->OriginalAttributes);
if ( isset($this->Children) ) {
foreach ($this->Children as $key => $child) {
if ( $this->Children[$key] instanceof kXMLNode5 ) {
$this->Children[$key]->__destruct();
}
unset( $this->Children[$key] );
}
}
unset($this->Children);
// echo number_format(memory_get_usage()). ' &lt;-- Destructed '.$this->Name.' Children <br/>';
unset($this->Name, $this->OriginalName);
unset($this->Data);
unset($this->firstChild);
unset($this->lastChild);
unset($this->Parent);
unset($this->Position);
unset($this->CRC);
unset($this);
}
}
Index: branches/5.2.x/core/units/images/image_tag_processor.php
===================================================================
--- branches/5.2.x/core/units/images/image_tag_processor.php (revision 14747)
+++ branches/5.2.x/core/units/images/image_tag_processor.php (revision 14748)
@@ -1,497 +1,497 @@
<?php
/**
* @version $Id$
* @package In-Portal
-* @copyright Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
+* @copyright Copyright (C) 1997 - 2011 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 ImageTagProcessor extends kDBTagProcessor {
/**
* Prepares all image parameters as list block parameters (for easy usage)
*
* @param kDBList $object
* @param Array $block_params
* @return void
* @access protected
* @author Alex
*/
protected function PrepareListElementParams(&$object, &$block_params)
{
$image_url = $this->ImageSrc($block_params);
if ( !$image_url ) {
return ;
}
$parent_prefix = $this->Application->getUnitOption($object->Prefix, 'ParentPrefix');
$parent_item =& $this->Application->recallObject($parent_prefix);
/* @var $parent_item kDBItem */
$block_params['img_path'] = $image_url;
$image_dimensions = $this->ImageSize($block_params);
$block_params['img_size'] = $image_dimensions ? $image_dimensions : ' width="' . $block_params['DefaultWidth'] . '"';
$block_params['alt'] = $object->GetField('AltName') ? $object->GetField('AltName') : htmlspecialchars($this->getItemTitle($parent_item));
$block_params['align'] = array_key_exists('align', $block_params) ? $block_params['align'] : 'left';
}
/**
* Returns value of object's title field
*
* @param kDBItem $object
* @return string
* @access protected
*/
protected function getItemTitle(&$object)
{
$title_field = $this->Application->getUnitOption($object->Prefix, 'TitleField');
return $object->GetField($title_field);
}
/**
* [AGGREGATED TAGS] works as <inp2:CatalogItemPrefix_Image, ImageSize, ImageSrc ..../>
*
* @param Array $params
* @return string
*/
function ItemImageTag($params)
{
$this->LoadItemImage($params);
return $this->$params['original_tag']($params);
}
function LargeImageExists($params)
{
$object =& $this->getObject($params);
if ($object->GetDBField('SameImages') == null || $object->GetDBField('SameImages') == 1) {
return false;
}
else {
return true;
}
}
function LoadItemImage($params)
{
$parent_item =& $this->Application->recallObject($params['PrefixSpecial']);
/* @var $parent_item kCatDBItem */
$object =& $this->Application->recallObject($this->getPrefixSpecial(), null, Array('skip_autoload' => true));
/* @var $object kDBItem */
$object->Clear();
// if we need primary thumbnail which is preloaded with category item's list
$is_primary = $this->SelectParam($params, 'primary,Primary');
$image_name = $this->SelectParam($params, 'name,Name');
$image_field = $this->SelectParam($params, 'field,Field'); // ie. virtual names PrimaryImage, Image1, Image2
$image_id = $this->Application->GetVar($this->Prefix.'_id');
if (
// is primary, when primary mark set OR name & field not given
($is_primary || !($image_name || $image_field)) &&
// primary image is preloaded AND direct id not given
$parent_item->isField('ThumbPath') && !$image_id
) {
if (is_null($parent_item->GetDBField('SameImages'))) {
// JOIN definetly failed, because it's not-null column
$object->setLoaded(false);
}
else {
$object->SetDBField('Url', $parent_item->GetDBField('FullUrl'));
$object->SetDBFieldsFromHash($parent_item->GetFieldValues(), Array('AltName', 'SameImages', 'LocalThumb', 'ThumbPath', 'ThumbUrl', 'LocalImage', 'LocalPath'));
if (!$object->GetDBField('AltName')) {
$object->SetDBField('AltName', $this->getItemTitle($parent_item));
}
$object->setLoaded();
}
}
else { // if requested image is not primary thumbnail - load it directly
$id_field = $this->Application->getUnitOption($this->Prefix, 'ForeignKey');
$parent_table_key = $this->Application->getUnitOption($this->Prefix, 'ParentTableKey');
$keys[$id_field] = $parent_item->GetDBField($parent_table_key);
// which image to load?
if ($is_primary) {
// by PrimaryImage mark
$keys['DefaultImg'] = 1;
}
elseif ($image_name) {
// by ImageName
$keys['Name'] = $image_name;
}
elseif ($image_field) {
// by virtual field name in main object
$field_options = $parent_item->GetFieldOptions( $image_field );
$keys['Name'] = isset($field_options['original_field']) ? $field_options['original_field'] : $image_field;
}
elseif ($image_id) {
// by ID
$keys['ImageId'] = $image_id;
}
else {
// by PrimaryImage if no other criteria given
$keys['DefaultImg'] = 1;
}
$object->Load($keys);
if ( $image_field ) {
$image_src = $parent_item->GetDBField( $image_field );
// when image is uploaded to virtual field in main item, but not saved to db
$object->SetDBField('ThumbPath', $image_src);
if (!$object->isLoaded() && $image_src) {
// set fields for displaing new image during main item suggestion with errors
$fields_hash = Array (
'Url' => '',
'ThumbUrl' => '',
'LocalPath' => '',
'SameImages' => 1,
'LocalThumb' => 1,
'LocalImage' => 1,
);
$object->SetDBFieldsFromHash($fields_hash);
$object->setLoaded();
}
}
}
}
function getImageDimension($type, $params)
{
$ret = isset($params['Max'.$type]) ? $params['Max'.$type] : false;
if (!$ret) {
return $ret;
}
$parent_prefix = $this->Application->getUnitOption($this->Prefix, 'ParentPrefix');
if ($ret == 'thumbnail') {
$ret = $this->Application->ConfigValue($parent_prefix.'_ThumbnailImage'.$type);
}
if ($ret == 'fullsize') {
$ret = $this->Application->ConfigValue($parent_prefix.'_FullImage'.$type);
}
return $ret;
}
/**
* Appends "/" to beginning of image path (in case when missing)
*
* @param kDBItem $object
* @todo old in-portal doesn't append first slash, but we do => append first slash for him :)
*/
function makeRelativePaths(&$object)
{
$thumb_path = $object->GetDBField('ThumbPath');
if ($thumb_path && substr($thumb_path, 0, 1) != DIRECTORY_SEPARATOR) {
$object->SetDBField('ThumbPath', DIRECTORY_SEPARATOR . $thumb_path);
}
$local_path = $object->GetDBField('LocalPath');
if ($local_path && substr($local_path, 0, 1) != DIRECTORY_SEPARATOR) {
$object->SetDBField('LocalPath', DIRECTORY_SEPARATOR . $local_path);
}
}
function ImageSrc($params)
{
$object =& $this->getObject($params);
/* @var $object kDBItem */
$this->makeRelativePaths($object);
// show "noimage.gif" when requested image is missing OR was not uploaded
$use_default_image = !(defined('DBG_IMAGE_RECOVERY') && DBG_IMAGE_RECOVERY);
$src_image_url = $this->_getImageUrl($params);
$src_image = $this->_getImagePath($src_image_url);
if (!$object->isLoaded() || ($src_image_url && $src_image)) {
// we can auto-resize image, when it is stored locally
$max_width = $this->getImageDimension('Width', $params);
$max_height = $this->getImageDimension('Height', $params);
$format = array_key_exists('format', $params) ? $params['format'] : false;
if (!$max_width && $format) {
// user watermarks from format param
$max_width = $format;
}
if ($max_width > 0 || $max_height > 0 || $format) {
list ($max_width, $max_height) = $this->_transformParams($params, $max_width, $max_height);
if ($object->isLoaded() && file_exists($src_image)) {
$image_helper =& $this->Application->recallObject('ImageHelper');
/* @var $image_helper ImageHelper */
return $image_helper->ResizeImage($src_image, $max_width, $max_height);
}
elseif ($use_default_image) {
return $this->_getDefaultImage($params, $max_width, $max_height);
}
return $src_image_url;
}
}
if ($src_image_url) {
// convert full url to full path!
$dst_image = $this->_getImagePath($src_image_url);
$image_found = $dst_image ? file_exists($dst_image) : true;
if ($image_found) {
// image isn't deleted OR is stored on remote location
return $src_image_url;
}
}
// return Default Image or false if NOT specified (only for case, when SameImages = 0)
return $use_default_image ? $this->_getDefaultImage($params) : $src_image_url;
}
/**
* Get location on disk for images, stored locally and false for remote images
*
* @param string $src_image
* @return string
*/
function _getImagePath($src_image)
{
if (!$src_image) {
return false;
}
$file_helper =& $this->Application->recallObject('FileHelper');
/* @var $file_helper FileHelper */
$dst_image = $file_helper->urlToPath($src_image);
return $dst_image != $src_image ? $dst_image : false;
}
function _getImageUrl($params)
{
$object =& $this->getObject($params);
/* @var $object kDBItem */
$base_url = rtrim($this->Application->BaseURL(), '/');
// if we need thumbnail, or full image is same as thumbnail
$show_thumbnail = $this->SelectParam($params, 'thumbnail,Thumbnail') || // old style
(isset($params['MaxWidth']) && $params['MaxWidth'] == 'thumbnail') || // new style
(isset($params['MaxHeight']) && $params['MaxHeight'] == 'thumbnail');
if ($show_thumbnail || $object->GetDBField('SameImages')) {
// return local image or url
$ret = $object->GetDBField('LocalThumb') ? $base_url . $object->GetDBField('ThumbPath') : $object->GetDBField('ThumbUrl');
}
else { // if we need full which is not the same as thumb
$ret = $object->GetDBField('LocalImage') ? $base_url . $object->GetDBField('LocalPath') : $object->GetDBField('Url');
}
return $ret == $base_url ? '' : $ret;
}
/**
* Transforms Image/ImageSrc aggregated tag parameters into ones, that ResizeImage method understands
*
* @param Array $params
* @param int|bool $max_width
* @param int|bool $max_height
* @return Array
*/
function _transformParams($params, $max_width = false, $max_height = false)
{
$resize_format = 'resize:' . $max_width . 'x' . $max_height;
$crop = $this->SelectParam($params, 'Crop,crop');
if ($crop) {
if (strpos($crop, ';') === false) {
$crop = 'c|c';
}
$max_width = (is_null($max_height) ? $max_width : $resize_format) . ';crop:' . $crop;
$max_height = null;
}
$fill = $this->SelectParam($params, 'Fill,fill');
if ($fill) {
$max_width = (is_null($max_height) ? $max_width : $resize_format) . ';fill:' . $fill;
$max_height = null;
}
$watermark = $this->SelectParam($params, 'Watermark,watermark');
if ($watermark) {
$max_width = (is_null($max_height) ? $max_width : $resize_format) . ';wm:' . $watermark;
$max_height = null;
}
return Array ($max_width, $max_height);
}
/**
* Returns default full url to default images
*
* @param Array $params
* @param int|bool $max_width
* @param int|bool $max_height
* @return string
*/
function _getDefaultImage($params, $max_width = false, $max_height = false)
{
$default_image = $this->SelectParam($params, 'default_image,DefaultImage');
if (!$default_image) {
return '';
}
// show default image, use different base urls for admin and front-end
$base_url = rtrim($this->Application->BaseURL(), '/');
$sub_folder = $this->Application->isAdmin ? rtrim(IMAGES_PATH, '/') : THEMES_PATH;
if (($max_width !== false) || ($max_height !== false)) {
$image_helper =& $this->Application->recallObject('ImageHelper');
/* @var $image_helper ImageHelper */
$src_image = FULL_PATH . $sub_folder . '/' . $default_image;
return $image_helper->ResizeImage($src_image, $max_width, $max_height);
}
return $base_url . $sub_folder . '/' . $default_image;
}
function getFullPath($path)
{
if (!$path) {
return $path;
}
// absolute url
if (preg_match('/^(.*):\/\/(.*)$/U', $path)) {
$file_helper =& $this->Application->recallObject('FileHelper');
/* @var $file_helper FileHelper */
return $file_helper->urlToPath($path);
}
// TODO: change to urlToPath usage later
// relative url (we add sort of <inp2:m_TemplatesBase/> does
return FULL_PATH . '/' . mb_substr(THEMES_PATH, 1) . '/' . rawurldecode($path);
}
/**
* Makes size clause for img tag, such as
* ' width="80" height="100"' according to max_width
* and max_heght limits.
*
* @param array $params
* @return string
*/
function ImageSize($params)
{
$img_path = $this->getFullPath($params['img_path']);
$image_helper =& $this->Application->recallObject('ImageHelper');
/* @var $image_helper ImageHelper */
$max_width = $this->getImageDimension('Width', $params);
$max_height = $this->getImageDimension('Height', $params);
$image_dimensions = $image_helper->GetImageDimensions($img_path, $max_width, $max_height, $params);
if (!$image_dimensions) {
return false;
}
return ' width="'.$image_dimensions[0].'" height="'.$image_dimensions[1].'"';
}
/**
* Prepares image parameters & parses block with them (for admin)
*
* @param Array $params
* @return string
* @access protected
*/
protected function Image($params)
{
$image_url = $this->ImageSrc($params);
if ( !$image_url ) {
return '';
}
$object =& $this->getObject($params);
/* @var $object kDBItem */
$params['img_path'] = $image_url;
$image_dimensions = $this->ImageSize($params);
$params['img_size'] = $image_dimensions ? $image_dimensions : ' width="' . $params['DefaultWidth'] . '"';
$params['alt'] = htmlspecialchars($object->GetField('AltName')); // really used ?
$params['name'] = $this->SelectParam($params, 'block,render_as');
$params['align'] = array_key_exists('align', $params) ? $params['align'] : 'left';
$params['no_editing'] = 1;
if ( !$object->isLoaded() && !$this->SelectParam($params, 'default_image,DefaultImage') ) {
return '';
}
return $this->Application->ParseBlock($params);
}
/**
* Returns url for image in case when image source is url (for admin)
*
* @param Array $params
* @return string
*/
function ImageUrl($params)
{
$object =& $this->getObject($params);
if ($object->GetDBField('SameImages') ? $object->GetDBField('LocalThumb') : $object->GetDBField('LocalImage') ) {
$ret = $this->Application->Phrase(getArrayValue($params,'local_phrase'));
}
else {
$ret = $object->GetDBField('SameImages') ? $object->GetDBField('ThumbUrl') : $object->GetDBField('Url');
}
return $ret;
}
/**
* If data was modfied & is in TempTables mode, then parse block with name passed;
* remove modification mark if not in TempTables mode
*
* @param Array $params
* @return string
* @access public
* @author Alexey
*/
function SaveWarning($params)
{
if ($this->Prefix == 'c-img') {
return $this->Application->ProcessParsedTag('c', 'SaveWarning', $params);
}
return parent::SaveWarning($params);
}
}
\ No newline at end of file
Index: branches/5.2.x/core/units/forms/form_submissions/form_submission_tp.php
===================================================================
--- branches/5.2.x/core/units/forms/form_submissions/form_submission_tp.php (revision 14747)
+++ branches/5.2.x/core/units/forms/form_submissions/form_submission_tp.php (revision 14748)
@@ -1,46 +1,60 @@
<?php
+/**
+* @version $Id$
+* @package In-Portal
+* @copyright Copyright (C) 1997 - 2011 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 FormSubmissionTagProcessor extends kDBTagProcessor {
+
+ /**
+ * Returns phrase translation by name
+ *
+ * @param Array $params
+ * @return string
+ * @access public
+ */
+ function PhraseFromRequest($params)
+ {
+ $phrase_name = $this->Application->GetVar($params['name']);
- class FormSubmissionTagProcessor extends kDBTagProcessor {
+ if (array_key_exists('default', $params) && !$phrase_name) {
+ $phrase_name = $params['default'];
+ }
- /**
- * Returns phrase translation by name
- *
- * @param Array $params
- * @return string
- * @access public
- */
- function PhraseFromRequest($params)
- {
- $phrase_name = $this->Application->GetVar($params['name']);
-
- if (array_key_exists('default', $params) && !$phrase_name) {
- $phrase_name = $params['default'];
- }
+ return $this->Application->Phrase($phrase_name);
+ }
- return $this->Application->Phrase($phrase_name);
- }
+ /**
+ * Allows to retrieve for submission field by it's name or role in email communications
+ *
+ * @param Array $params
+ * @return string
+ */
+ function FormField($params)
+ {
+ $object =& $this->getObject($params);
+ /* @var $object kDBItem */
- /**
- * Allows to retrieve for submission field by it's name or role in email communications
- *
- * @param Array $params
- * @return string
- */
- function FormField($params)
- {
- $object =& $this->getObject($params);
- /* @var $object kDBItem */
-
- $form_submission_helper =& $this->Application->recallObject('FormSubmissionHelper');
- /* @var $form_submission_helper FormSubmissionHelper */
-
- $formatted = !(array_key_exists('db', $params) && $params['db']);
- $format = $formatted ? (array_key_exists('format', $params) ? $params['format'] : null) : null;
-
- if (array_key_exists('role', $params)) {
- return $form_submission_helper->getFieldByRole($object, $params['role'], $formatted, $format);
- }
+ $form_submission_helper =& $this->Application->recallObject('FormSubmissionHelper');
+ /* @var $form_submission_helper FormSubmissionHelper */
- return $form_submission_helper->getFieldByName($params['name'], $formatted, $format);
+ $formatted = !(array_key_exists('db', $params) && $params['db']);
+ $format = $formatted ? (array_key_exists('format', $params) ? $params['format'] : null) : null;
+
+ if (array_key_exists('role', $params)) {
+ return $form_submission_helper->getFieldByRole($object, $params['role'], $formatted, $format);
}
+
+ return $form_submission_helper->getFieldByName($params['name'], $formatted, $format);
}
+}
Index: branches/5.2.x/core/units/phrases/phrase_tp.php
===================================================================
--- branches/5.2.x/core/units/phrases/phrase_tp.php (revision 14747)
+++ branches/5.2.x/core/units/phrases/phrase_tp.php (revision 14748)
@@ -1,59 +1,61 @@
<?php
/**
* @version $Id$
* @package In-Portal
-* @copyright Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
+* @copyright Copyright (C) 1997 - 2011 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.
*/
- class PhraseTagProcessor extends kDBTagProcessor {
+defined('FULL_PATH') or die('restricted access!');
- /**
- * Determines, that we can close phrase editing form without parent window refreshing
- *
- * @param Array $params
- * @return bool
- */
- function UseQuickFormCancel($params)
- {
- return $this->Application->GetVar('simple_mode') && (int)$this->Application->ConfigValue('UsePopups');
+class PhraseTagProcessor extends kDBTagProcessor {
+
+ /**
+ * Determines, that we can close phrase editing form without parent window refreshing
+ *
+ * @param Array $params
+ * @return bool
+ */
+ function UseQuickFormCancel($params)
+ {
+ return $this->Application->GetVar('simple_mode') && (int)$this->Application->ConfigValue('UsePopups');
+ }
+
+ function PhraseCount($params)
+ {
+ static $cache = null;
+
+ if (!isset($cache)) {
+ $sql = 'SELECT COUNT(*), Module
+ FROM ' . $this->Application->getUnitOption($this->Prefix, 'TableName') . '
+ GROUP BY Module';
+ $cache = $this->Conn->GetCol($sql, 'Module');
}
- function PhraseCount($params)
- {
- static $cache = null;
-
- if (!isset($cache)) {
- $sql = 'SELECT COUNT(*), Module
- FROM ' . $this->Application->getUnitOption($this->Prefix, 'TableName') . '
- GROUP BY Module';
- $cache = $this->Conn->GetCol($sql, 'Module');
- }
+ $module = $params['module'];
- $module = $params['module'];
+ return array_key_exists($module, $cache) ? $cache[$module] : 0;
+ }
- return array_key_exists($module, $cache) ? $cache[$module] : 0;
+ function EventCount($params)
+ {
+ static $cache = null;
+
+ if (!isset($cache)) {
+ $sql = 'SELECT COUNT(*), IF(Module LIKE "Core:%", "Core", Module) AS Module
+ FROM ' . $this->Application->getUnitOption('emailevents', 'TableName') . '
+ GROUP BY Module';
+ $cache = $this->Conn->GetCol($sql, 'Module');
}
- function EventCount($params)
- {
- static $cache = null;
-
- if (!isset($cache)) {
- $sql = 'SELECT COUNT(*), IF(Module LIKE "Core:%", "Core", Module) AS Module
- FROM ' . $this->Application->getUnitOption('emailevents', 'TableName') . '
- GROUP BY Module';
- $cache = $this->Conn->GetCol($sql, 'Module');
- }
-
- $module = $params['module'];
+ $module = $params['module'];
- return array_key_exists($module, $cache) ? $cache[$module] : 0;
- }
- }
\ No newline at end of file
+ return array_key_exists($module, $cache) ? $cache[$module] : 0;
+ }
+}
\ No newline at end of file

Event Timeline