Page MenuHomeIn-Portal Phabricator

in-portal
No OneTemporary

File Metadata

Created
Sat, Oct 4, 11:25 PM

in-portal

Index: branches/5.2.x/core/kernel/event_handler.php
===================================================================
--- branches/5.2.x/core/kernel/event_handler.php (revision 14674)
+++ branches/5.2.x/core/kernel/event_handler.php (revision 14675)
@@ -1,191 +1,191 @@
<?php
/**
* @version $Id$
* @package In-Portal
* @copyright Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
* @license GNU/GPL
* In-Portal is Open Source software.
* This means that this software may have been modified pursuant
* the GNU General Public License, and as distributed it includes
* or is derivative of works licensed under the GNU General Public License
* or other free or open source software licenses.
* See http://www.in-portal.org/license for copyright notices and details.
*/
defined('FULL_PATH') or die('restricted access!');
/**
* Note:
* 1. When adressing variables from submit containing
* Prefix_Special as part of their name use
* $event->getPrefixSpecial(true) instead of
* $event->getPrefixSpecial() as usual. This is due PHP
* is converting "." symbols in variable names during
* submit info "_". $event->getPrefixSpecial optional
* 1st parameter returns correct corrent Prefix_Special
* for variables beeing submitted such way (e.g. variable
* name that will be converted by PHP: "users.read_only_id"
* will be submitted as "users_read_only_id".
*
* 2. When using $this->Application->LinkVar on variables submitted
* from the form which contains $Prefix_Special then note 1st item.
* Example: LinkVar($event->getPrefixSpecial(true).'_varname', $event->getPrefixSpecial().'_varname')
*
*/
/**
* Default event handler. Mostly abstract class
*
*/
class kEventHandler extends kBase {
/**
* In case if event should be handled with method, which name differs from
* event name, then it should be specified here.
* key - event name, value - event method
*
* @var Array
* @access protected
*/
protected $eventMethods = Array ();
/**
* Defines mapping vs event names and permission names
*
* @var Array
* @access protected
*/
protected $permMapping = Array ();
public function __construct()
{
parent::__construct();
$this->mapEvents();
$this->mapPermissions();
}
/**
* Define alternative event processing method names
*
* @see kEventHandler::$eventMethods
* @access protected
*/
protected function mapEvents()
{
}
/**
- * Allows to override standart permission mapping
+ * Allows to override standard permission mapping
*
* @access protected
* @see kEventHandler::$permMapping
*/
protected function mapPermissions()
{
}
/**
* Returns prefix and special (when present) joined by a "."
*
* @return string
* @access private
*/
public function getPrefixSpecial()
{
throw new Exception('Usage of getPrefixSpecial() method is forbidden in kEventHandler class children. Use $event->getPrefixSpecial(true); instead');
}
/**
* Executes event, specified in $event variable
*
* @param kEvent $event
* @access public
*/
public function processEvent(&$event)
{
$event_name = $event->Name;
if ( array_key_exists($event_name, $this->eventMethods) ) {
$event_name = $this->eventMethods[$event_name];
}
if ( method_exists($this, $event_name) ) {
$this->$event_name($event);
}
else {
throw new Exception('Event <strong>' . $event->Name . '</strong> not implemented in class <strong>' . get_class($this) . '</strong>');
}
}
/**
* Sample dummy event
*
* @param kEvent $event
* @access protected
*/
protected function OnBuild(&$event)
{
}
/**
* Returns to previous template in opener stack
*
* @param kEvent $event
* @access protected
*/
protected function OnGoBack(&$event)
{
$url = $this->Application->RecallVar('export_finish_url');
if ($url) {
$this->Application->Redirect('external:' . $url);
}
$event->SetRedirectParam('opener', 'u');
}
/**
* Apply some special processing to object being
* recalled before using it in other events that
* call prepareObject
*
* @param kDBItem|kDBList $object
* @param kEvent $event
* @return void
* @access protected
*/
protected function prepareObject(&$object, &$event)
{
}
/**
* Checks user permission to execute given $event
*
* @param kEvent $event
* @return bool
* @access public
*/
public function CheckPermission(&$event)
{
$perm_helper =& $this->Application->recallObject('PermissionsHelper');
/* @var $perm_helper kPermissionsHelper */
return $perm_helper->CheckEventPermission($event, $this->permMapping);
}
/**
* Occurs, when config was parsed, allows to change config data dynamically
*
* @param kEvent $event
*/
protected function OnAfterConfigRead(&$event)
{
}
}
\ No newline at end of file
Index: branches/5.2.x/core/kernel/nparser/nparser.php
===================================================================
--- branches/5.2.x/core/kernel/nparser/nparser.php (revision 14674)
+++ branches/5.2.x/core/kernel/nparser/nparser.php (revision 14675)
@@ -1,1202 +1,1204 @@
<?php
/**
* @version $Id$
* @package In-Portal
* @copyright Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
* @license GNU/GPL
* In-Portal is Open Source software.
* This means that this software may have been modified pursuant
* the GNU General Public License, and as distributed it includes
* or is derivative of works licensed under the GNU General Public License
* or other free or open source software licenses.
* See http://www.in-portal.org/license for copyright notices and details.
*/
defined('FULL_PATH') or die('restricted access!');
include_once(KERNEL_PATH.'/nparser/ntags.php');
define('TAG_NAMESPACE', 'inp2:');
define('TAG_NAMESPACE_LENGTH', 5);
class NParser extends kBase {
var $Stack = Array ();
var $Level = 0;
var $Buffers = array();
var $InsideComment = false;
/**
* Parse tags inside HTML comments
*
* @var bool
*/
var $SkipComments = true;
var $Params = array();
var $ParamsStack = array();
var $ParamsLevel = 0;
var $Definitions = '';
/**
* Holds dynamic elements to function names mapping during execution
*
* @var Array
*/
var $Elements = Array ();
/**
* Holds location of element definitions inside templates.
* key - element function name, value - array of 2 keys: {from_pos, to_pos}
*
* @var Array
*/
var $ElementLocations = Array ();
var $DataExists = false;
var $TemplateName = null;
var $TempalteFullPath = null;
var $CachePointers = Array ();
var $Cachable = Array ();
/**
* Deep level during parsing
- *
+ *
* @var int
*/
var $CacheLevel = 0;
/**
* Caching in templates enabled
*
* @var bool
*/
var $CachingEnabled = false;
/**
* Completely cache given page
*
* @var bool
*/
var $FullCachePage = false;
/**
* Prefixes, that are used on current page
*
* @var Array
*/
var $PrefixesInUse = Array ();
/**
* Parser parameter names, that are created via m_Capture tag are listed here
*
* @var Array
*/
var $Captures = array();
/**
* Phrases, used on "Edit" buttons, that parser adds during block decoration
*
* @var Array
*/
var $_btnPhrases = Array ();
/**
* Mod-rewrite system enabled
*
* @var bool
*/
var $RewriteUrls = false;
/**
* Current user is logged-in
*
* @var bool
*/
var $UserLoggedIn = false;
/**
* Creates template parser object
*
* @access public
*/
public function __construct()
{
parent::__construct();
if (defined('EDITING_MODE') && (EDITING_MODE == EDITING_MODE_DESIGN)) {
$this->_btnPhrases['design'] = $this->Application->Phrase('la_btn_EditDesign', false, true);
$this->_btnPhrases['block'] = $this->Application->Phrase('la_btn_EditBlock', false, true);
}
$this->RewriteUrls = $this->Application->RewriteURLs();
$this->UserLoggedIn = $this->Application->LoggedIn();
// cache only Front-End templated, when memory caching is available and template caching is enabled in configuration
$this->CachingEnabled = !$this->Application->isAdmin && $this->Application->ConfigValue('SystemTagCache') && $this->Application->isCachingType(CACHING_TYPE_MEMORY);
}
function Compile($pre_parsed, $template_name = 'unknown')
{
$data = file_get_contents($pre_parsed['tname']);
if (!$this->CompileRaw($data, $pre_parsed['tname'], $template_name)) {
// compilation failed during errors in template
// trigger_error('Template "<strong>' . $template_name . '</strong>" not compiled because of errors', E_USER_WARNING);
return false;
}
// saving compiled version (only when compilation was successful)
$this->Application->TemplatesCache->saveTemplate($pre_parsed['fname'], $this->Buffers[0]);
return true;
}
function Parse($raw_template, $name = null)
{
$this->CompileRaw($raw_template, $name);
ob_start();
$_parser =& $this;
eval('?'.'>'.$this->Buffers[0]);
return ob_get_clean();
}
function CompileRaw($data, $t_name, $template_name = 'unknown')
{
$code = "extract (\$_parser->Params);\n";
$code .= "\$_parser->ElementLocations['{$template_name}'] = Array('template' => '{$template_name}', 'start_pos' => 0, 'end_pos' => " . strlen($data) . ");\n";
// $code .= "__@@__DefinitionsMarker__@@__\n";
// $code .= "if (!\$this->CacheStart('".abs(crc32($t_name))."_0')) {\n";
$this->Buffers[0] = '<?'."php $code ?>\n";
$this->Cacheable[0] = true;
$this->Definitions = '';
// finding all the tags
$reg = '(.*?)(<[\\/]?)' . TAG_NAMESPACE . '([^>]*?)([\\/]?>)(\r\n){0,1}';
preg_match_all('/'.$reg.'/s', $data, $results, PREG_SET_ORDER + PREG_OFFSET_CAPTURE);
$this->InsideComment = false;
foreach ($results as $tag_data) {
$tag = array(
'opening' => $tag_data[2][0],
'tag' => $tag_data[3][0],
'closing' => $tag_data[4][0],
'line' => substr_count(substr($data, 0, $tag_data[2][1]), "\n")+1,
'pos' => $tag_data[2][1],
'file' => $t_name,
'template' => $template_name,
);
// the idea is to count number of comment openings and closings before current tag
// if the numbers do not match we inverse the status of InsideComment
if ($this->SkipComments && (substr_count($tag_data[1][0], '<!--') != substr_count($tag_data[1][0], '-->'))) {
$this->InsideComment = !$this->InsideComment;
}
// appending any text/html data found before tag
$this->Buffers[$this->Level] .= $tag_data[1][0];
if (!$this->InsideComment) {
$tmp_tag = $this->Application->CurrentNTag;
$this->Application->CurrentNTag = $tag;
if ($this->ProcessTag($tag) === false) {
$this->Application->CurrentNTag = $tmp_tag;
return false;
}
$this->Application->CurrentNTag = $tmp_tag;
}
else {
$this->Buffers[$this->Level] .= $tag_data[2][0].$tag_data[3][0].$tag_data[4][0];
}
}
if ($this->Level > 0) {
$error_tag = Array (
'file' => $this->Stack[$this->Level]->Tag['file'],
'line' => $this->Stack[$this->Level]->Tag['line'],
);
throw new ParserException('Unclosed tag opened by ' . $this->TagInfo($this->Stack[$this->Level]->Tag), 0, null, $error_tag);
return false;
}
// appending text data after last tag (after its closing pos),
// if no tag was found at all ($tag_data is not set) - append the whole $data
$this->Buffers[$this->Level] .= isset($tag_data) ? substr($data, $tag_data[4][1]+strlen($tag_data[4][0])) : $data;
$this->Buffers[$this->Level] = preg_replace('/<!--##(.*?)##-->/s', '', $this->Buffers[$this->Level]); // remove hidden comments IB#23065
// $this->Buffers[$this->Level] .= '<?'.'php '."\n\$_parser->CacheEnd();\n}\n"." ?".">\n";
// $this->Buffers[$this->Level] = str_replace('__@@__DefinitionsMarker__@@__', $this->Definitions, $this->Buffers[$this->Level]);
return true;
}
function SplitParamsStr($params_str)
{
preg_match_all('/([\${}a-zA-Z0-9_.\\-\\\\#\\[\\]]+)=(["\']{1,1})(.*?)(?<!\\\)\\2/s', $params_str, $rets, PREG_SET_ORDER);
$values = Array();
// we need to replace all occurences of any current param $key with {$key} for correct variable substitution
foreach ($rets AS $key => $val){
$values[$val[1]] = str_replace('\\' . $val[2], $val[2], $val[3]);
}
return $values;
}
function SplitTag($tag)
{
if (!preg_match('/([^_ \t\r\n]*)[_]?([^ \t\r\n]*)[ \t\r\n]*(.*)$$/s', $tag['tag'], $parts)) {
// this is virtually impossible, but just in case
throw new ParserException('Incorrect tag format: ' . $tag['tag'], 0, null, $tag);
return false;
}
$splited['prefix'] = $parts[2] ? $parts[1] : '__auto__';
$splited['name'] = $parts[2] ? $parts[2] : $parts[1];
$splited['attrs'] = $parts[3];
return $splited;
}
function ProcessTag($tag)
{
$splited = $this->SplitTag($tag);
if ($splited === false) {
return false;
}
$tag = array_merge($tag, $splited);
$tag['processed'] = false;
$tag['NP'] = $this->SplitParamsStr($tag['attrs']);
$o = '';
$tag['is_closing'] = $tag['opening'] == '</' || $tag['closing'] == '/>';
if (class_exists('_Tag_'.$tag['name'])) { // block tags should have special handling class
if ($tag['opening'] == '<') {
$class = '_Tag_'.$tag['name'];
$instance = new $class($tag);
$instance->Parser =& $this;
/* @var $instance _BlockTag */
$this->Stack[++$this->Level] =& $instance;
$this->Buffers[$this->Level] = '';
$this->Cachable[$this->Level] = true;
$open_code = $instance->Open($tag);
if ($open_code === false) {
return false;
}
$o .= $open_code;
}
if ($tag['is_closing']) { // not ELSE here, because tag may be <empty/> and still has a handler-class
if ($this->Level == 0) {
$dump = array();
foreach ($this->Stack as $instance) {
$dump[] = $instance->Tag;
}
if ( $this->Application->isDebugMode() ) {
$this->Application->Debugger->dumpVars($dump);
}
$error_msg = 'Closing tag without an opening: ' . $this->TagInfo($tag) . ' - <strong>probably opening tag was removed or nested tags error</strong>';
throw new ParserException($error_msg, 0, null, $tag);
return false;
}
if ($this->Stack[$this->Level]->Tag['name'] != $tag['name']) {
$opening_tag = $this->Stack[$this->Level]->Tag;
$error_msg = ' Closing tag ' . $this->TagInfo($tag) . ' does not match
opening tag at current nesting level
(' . $this->TagInfo($opening_tag) . ' opened at line ' . $opening_tag['line'] . ')';
throw new ParserException($error_msg, 0, null, $tag);
return false;
}
$o .= $this->Stack[$this->Level]->Close($tag); // DO NOT use $this->Level-- here because it's used inside Close
$this->Level--;
}
}
else { // regular tags - just compile
if (!$tag['is_closing']) {
$error_msg = 'Tag without a handler: ' . $this->TagInfo($tag) . ' - <strong>probably missing &lt;empty <span style="color: red">/</span>&gt; tag closing</strong>';
throw new ParserException($error_msg, 0, null, $tag);
return false;
}
if ($this->Level > 0) $o .= $this->Stack[$this->Level]->PassThrough($tag);
if (!$tag['processed']) {
$compiled = $this->CompileTag($tag);
if ($compiled === false) return false;
if (isset($tag['NP']['cachable']) && (!$tag['NP']['cachable'] || $tag['NP']['cachable'] == 'false')) {
$this->Cachable[$this->Level] = false;
}
$o .= '<?'.'php ' . $compiled . " ?>\n";
// $o .= '<?'.'php ';
// $o .= (isset($tag['NP']['cachable']) && (!$tag['NP']['cachable'] || $tag['NP']['cachable'] == 'false')) ? $this->BreakCache($compiled, $this->GetPointer($tag)) : $compiled;
// $o .= " ?".">\n";
}
}
$this->Buffers[$this->Level] .= $o;
return true;
}
function GetPointer($tag)
{
return abs(crc32($tag['file'])).'_'.$tag['line'];
}
function BreakCache($code, $pointer, $condition='')
{
return "\$_parser->CacheEnd();\n}\n" . $code."\nif ( !\$_parser->CacheStart('{$pointer}'" . ($condition ? ", {$condition}" : '') . ") ) {\n";
}
function TagInfo($tag, $with_params=false)
{
return "<b>{$tag['prefix']}_{$tag['name']}".($with_params ? ' '.$tag['attrs'] : '')."</b>";
}
function CompileParamsArray($arr)
{
$to_pass = 'Array(';
foreach ($arr as $name => $val) {
$to_pass .= '"'.$name.'" => "'.str_replace('"', '\"', $val).'",';
}
$to_pass .= ')';
return $to_pass;
}
function CompileTag($tag)
{
$code = '';
$to_pass = $this->CompileParamsArray($tag['NP']);
if ($tag['prefix'] == '__auto__') {
$prefix = $this->GetParam('PrefixSpecial');
$code .= '$_p_ =& $_parser->GetProcessor($PrefixSpecial);'."\n";
$code .= 'echo $_p_->ProcessParsedTag(\''.$tag['name'].'\', '.$to_pass.', "$PrefixSpecial", \''.$tag['file'].'\', '.$tag['line'].');'."\n";
}
else {
$prefix = $tag['prefix'];
$code .= '$_p_ =& $_parser->GetProcessor("'.$tag['prefix'].'");'."\n";
$code .= 'echo $_p_->ProcessParsedTag(\''.$tag['name'].'\', '.$to_pass.', "'.$tag['prefix'].'", \''.$tag['file'].'\', '.$tag['line'].');'."\n";
}
if (array_key_exists('result_to_var', $tag['NP']) && $tag['NP']['result_to_var']) {
$code .= "\$params['{$tag['NP']['result_to_var']}'] = \$_parser->GetParam('{$tag['NP']['result_to_var']}');\n";
$code .= "\${$tag['NP']['result_to_var']} = \$params['{$tag['NP']['result_to_var']}'];\n";
}
if ($prefix && strpos($prefix, '$') === false) {
$p =& $this->GetProcessor($prefix);
if (!is_object($p) || !$p->CheckTag($tag['name'], $tag['prefix'])) {
$error_msg = 'Unknown tag: ' . $this->TagInfo($tag) . ' - <strong>incorrect tag name or prefix</strong>';
throw new ParserException($error_msg, 0, null, $tag);
return false;
}
}
return $code;
}
function CheckTemplate($t, $silent = null)
{
$pre_parsed = $this->Application->TemplatesCache->GetPreParsed($t);
if (!$pre_parsed) {
if (!$silent) {
throw new ParserException('Cannot include "<strong>' . $t . '</strong>" - file does not exist');
}
return false;
}
$force_compile = defined('DBG_NPARSER_FORCE_COMPILE') && DBG_NPARSER_FORCE_COMPILE;
if (!$pre_parsed || !$pre_parsed['active'] || $force_compile) {
$inc_parser = new NParser();
if ($force_compile) {
// remove Front-End theme markings during total compilation
$t = preg_replace('/^theme:.*?\//', '', $t);
}
if (!$inc_parser->Compile($pre_parsed, $t)) {
return false;
}
}
return $pre_parsed;
}
function Run($t, $silent = null)
{
if ((strpos($t, '../') !== false) || (trim($t) !== $t)) {
// when relative paths or special chars are found template names from url, then it's hacking attempt
return false;
}
$pre_parsed = $this->CheckTemplate($t, $silent);
if (!$pre_parsed) {
return false;
}
$backup_template = $this->TemplateName;
$backup_fullpath = $this->TempalteFullPath;
$this->TemplateName = $t;
$this->TempalteFullPath = $pre_parsed['tname'];
if (!isset($backup_template) && $this->CachingEnabled && !$this->UserLoggedIn && !EDITING_MODE) {
// this is main page template -> check for page-based aggressive caching settings
$output =& $this->RunMainPage($pre_parsed);
}
else {
$output =& $this->Application->TemplatesCache->runTemplate($this, $pre_parsed);
}
$this->TemplateName = $backup_template;
$this->TempalteFullPath = $backup_fullpath;
return $output;
}
function &RunMainPage($pre_parsed)
{
$page =& $this->Application->recallObject('st.-virtual');
/* @var $page kDBItem */
if ($page->isLoaded()) {
// page found in database
$debug_mode = $this->Application->isDebugMode(); // don't cache debug output
$template_path = preg_replace('/^' . preg_quote(FULL_PATH, '/') . '/', '', $this->TempalteFullPath, 1);
$element = ($debug_mode ? 'DEBUG_MODE:' : '') . 'file=' . $template_path;
$this->FullCachePage = $page->GetDBField('EnablePageCache');
if ($this->FullCachePage && $page->GetDBField('PageCacheKey')) {
// page caching enabled -> try to get from cache
$cache_key = $this->FormCacheKey($element, $page->GetDBField('PageCacheKey'));
$output = $this->getCache($cache_key);
if ($output !== false) {
return $output;
}
}
// page not cached OR cache expired
$output =& $this->Application->TemplatesCache->runTemplate($this, $pre_parsed);
$this->generatePageCacheKey($page);
if ($this->FullCachePage && $page->GetDBField('PageCacheKey')) {
$cache_key = $this->FormCacheKey($element, $page->GetDBField('PageCacheKey'));
$this->setCache($cache_key, $output, (int)$page->GetDBField('PageExpiration'));
}
}
else {
// page not found in database
$output =& $this->Application->TemplatesCache->runTemplate($this, $pre_parsed);
}
return $output;
}
/**
* Generate page caching key based on prefixes used on it + prefix IDs passed in url
*
* @param kDBItem $page
*/
function generatePageCacheKey(&$page)
{
if (!$page->isLoaded() || $page->GetDBField('OverridePageCacheKey')) {
return ;
}
$page_cache_key = Array ();
// nobody resets "m" prefix serial, don't count no user too
unset($this->PrefixesInUse['m'], $this->PrefixesInUse['u']);
if (array_key_exists('st', $this->PrefixesInUse)) {
// prefix "st" serial will never be changed
unset($this->PrefixesInUse['st']);
$this->PrefixesInUse['c'] = 1;
}
$prefix_ids = Array ();
$prefixes = array_keys($this->PrefixesInUse);
asort($prefixes);
foreach ($prefixes as $index => $prefix) {
$id = $this->Application->GetVar($prefix . '_id');
if (is_numeric($id)) {
if (defined('DEBUG_MODE') && DEBUG_MODE && $this->Application->isDebugMode()) {
$this->Application->Debugger->appendHTML('Found: "' . $prefix . '_id" = ' . $id . ' during PageCacheKey forming.');
}
$prefix_ids[] = $prefix;
unset($prefixes[$index]);
}
}
if ($prefix_ids) {
$page_cache_key[] = 'prefix_id:' . implode(',', $prefix_ids);
}
if ($prefixes) {
$page_cache_key[] = 'prefix:' . implode(',', $prefixes);
}
$page_cache_key = implode(';', $page_cache_key);
if ($page_cache_key != $page->GetOriginalField('PageCacheKey')) {
if (defined('DEBUG_MODE') && DEBUG_MODE && $this->Application->isDebugMode()) {
$this->Application->Debugger->appendHTML('Canging PageCacheKey from "<strong>' . $page->GetOriginalField('PageCacheKey') . '</strong>" to "<strong>' . $page_cache_key . '</strong>".');
}
$page->SetDBField('PageCacheKey', $page_cache_key);
// don't use kDBItem::Update(), because it will change ModifiedById to current front-end user
$sql = 'UPDATE ' . $page->TableName . '
SET PageCacheKey = ' . $page->Conn->qstr($page_cache_key) . '
WHERE ' . $page->IDField . ' = ' . $page->GetID();
$page->Conn->Query($sql);
// increment serial, because we issue direct sql above!
$this->Application->incrementCacheSerial('c');
$this->Application->incrementCacheSerial('c', $page->GetID());
}
}
/**
* Creates tag processor and stores it in local cache + factory
*
* @param string $prefix
* @return kTagProcessor
*/
function &GetProcessor($prefix)
{
static $processors = Array ();
if ( !isset($processors[$prefix]) ) {
$processors[$prefix] = $this->Application->recallObject($prefix . '_TagProcessor');
}
return $processors[$prefix];
}
/**
* Not tag. Method for parameter selection from list in this TagProcessor
*
* @param Array $params
* @param Array $possible_names
*
* @return string
* @access protected
*/
protected function SelectParam($params, $possible_names)
{
if ( !is_array($params) ) {
return '';
}
if ( !is_array($possible_names) ) {
$possible_names = explode(',', $possible_names);
}
foreach ($possible_names as $name) {
if ( isset($params[$name]) ) {
return $params[$name];
}
}
return '';
}
function SetParams($params)
{
$this->Params = $params;
$keys = array_keys($this->Params);
}
function GetParam($name)
{
return isset($this->Params[$name]) ? $this->Params[$name] : false;
}
function SetParam($name, $value)
{
$this->Params[$name] = $value;
}
function PushParams($params)
{
$this->ParamsStack[$this->ParamsLevel++] = $this->Params;
$this->Params = $params;
}
function PopParams()
{
$this->Params = $this->ParamsStack[--$this->ParamsLevel];
}
function ParseBlock($params, $pass_params=false)
{
if (array_key_exists('cache_timeout', $params) && $params['cache_timeout']) {
$ret = $this->getCache( $this->FormCacheKey('element_' . $params['name']) );
if ($ret) {
return $ret;
}
}
if (substr($params['name'], 0, 5) == 'html:') {
return substr($params['name'], 5);
}
if (!array_key_exists($params['name'], $this->Elements) && array_key_exists('default_element', $params)) {
// when given element not found, but default element name given, then render it instead
$params['name'] = $params['default_element'];
unset($params['default_element']);
return $this->ParseBlock($params, $pass_params);
}
$original_params = $params;
if ($pass_params || isset($params['pass_params'])) $params = array_merge($this->Params, $params);
$this->PushParams($params);
$data_exists_bak = $this->DataExists;
// if we are parsing design block and we have block_no_data - we need to wrap block_no_data into design,
// so we should set DataExists to true manually, otherwise the design block will be skipped because of data_exists in params (by Kostja)
//
// keep_data_exists is used by block RenderElement (always added in ntags.php), to keep the DataExists value
// from inside-content block, otherwise when parsing the design block DataExists will be reset to false resulting missing design block (by Kostja)
//
// Inside-content block parsing result is given to design block in "content" parameter (ntags.php) and "keep_data_exists"
// is only passed, when parsing design block. In case, when $this->DataExists is set to true, but
// zero-length content (in 2 cases: method NParser::CheckNoData set it OR really empty block content)
// is returned from inside-content block, then design block also should not be shown (by Alex)
$this->DataExists = (isset($params['keep_data_exists']) && isset($params['content']) && $params['content'] != '' && $this->DataExists) || (isset($params['design']) && isset($params['block_no_data']) && $params['name'] == $params['design']);
if (!array_key_exists($params['name'], $this->Elements)) {
$pre_parsed = $this->Application->TemplatesCache->GetPreParsed($params['name']);
if ($pre_parsed) {
$ret = $this->IncludeTemplate($params);
if (array_key_exists('no_editing', $params) && $params['no_editing']) {
// when individual render element don't want to be edited
return $ret;
}
return defined('EDITING_MODE') ? $this->DecorateBlock($ret, $params, true) : $ret;
}
$trace_results = debug_backtrace();
$error_tag = Array (
'file' => $trace_results[0]['file'],
'line' => $trace_results[0]['line'],
);
$error_msg = '<strong>Rendering of undefined element ' . $params['name'] . '</strong>';
throw new ParserException($error_msg, 0, null, $error_tag);
return false;
}
$m_processor =& $this->GetProcessor('m');
$flag_values = $m_processor->PreparePostProcess($params);
$f_name = $this->Elements[$params['name']];
+ /* @var $f_name Closure */
+
$ret = $f_name($this, $params);
$ret = $m_processor->PostProcess($ret, $flag_values);
$block_params = $this->Params; // input parameters, but modified inside rendered block
$this->PopParams();
if (array_key_exists('result_to_var', $flag_values) && $flag_values['result_to_var']) {
// when "result_to_var" used inside ParseBlock, then $$result_to_var parameter is set inside ParseBlock,
// but not outside it as expected and got lost at all after PopParams is called, so make it work by
// setting it's value on current parameter deep level (from where ParseBlock was called)
$this->SetParam($flag_values['result_to_var'], $block_params[ $flag_values['result_to_var'] ]);
}
$this->CheckNoData($ret, $params);
$this->DataExists = $data_exists_bak || $this->DataExists;
if (array_key_exists('cache_timeout', $original_params) && $original_params['cache_timeout']) {
$cache_key = $this->FormCacheKey('element_' . $original_params['name']);
$this->setCache($cache_key, $ret, (int)$original_params['cache_timeout']);
}
if (array_key_exists('no_editing', $block_params) && $block_params['no_editing']) {
// when individual render element don't want to be edited
return $ret;
}
return defined('EDITING_MODE') ? $this->DecorateBlock($ret, $params) : $ret;
}
/**
* Checks, that given block is defined
*
* @param string $name
* @return bool
*/
function blockFound($name)
{
return array_key_exists($name, $this->Elements);
}
function DecorateBlock($block_content, $block_params, $is_template = false)
{
static $used_ids = Array (), $base_url = null;
if (!isset($base_url)) {
$base_url = $this->Application->BaseURL();
}
// $prepend = '[name: ' . $block_params['name'] . '] [params: ' . implode(', ', array_keys($block_params)) . ']';
$decorate = false;
$design = false;
if (EDITING_MODE == EDITING_MODE_DESIGN) {
$decorate = true;
if ($is_template) {
// content inside pair RenderElement tag
}
else {
if (strpos($block_params['name'], '__capture_') === 0) {
// capture tag (usually inside pair RenderElement)
$decorate = false;
}
elseif (array_key_exists('content', $block_params)) {
// pair RenderElement (on template, were it's used)
$design = true;
}
}
}
if (!$decorate) {
return $block_content;
}
/*else {
$block_content = $prepend . $block_content;
}*/
$block_name = $block_params['name'];
$function_name = $is_template ? $block_name : $this->Elements[$block_name];
$block_title = '';
if (array_key_exists($function_name, $this->Application->Parser->ElementLocations)) {
$element_location = $this->Application->Parser->ElementLocations[$function_name];
$block_title .= $element_location['template'] . '.tpl';
$block_title .= ' (' . $element_location['start_pos'] . ' - ' . $element_location['end_pos'] . ')';
}
// ensure unique id for every div (used from print lists)
$container_num = 1;
$container_id = 'parser_block[' . $function_name . ']';
while (in_array($container_id . '_' . $container_num, $used_ids)) {
$container_num++;
}
$container_id .= '_' . $container_num;
$used_ids[] = $container_id;
// prepare parameter string
$param_string = $block_name . ':' . $function_name;
if ($design) {
$btn_text = $this->_btnPhrases['design'];
$btn_class = 'cms-edit-design-btn';
$btn_container_class = 'block-edit-design-btn-container';
$btn_name = 'design';
}
else {
$btn_text = $this->_btnPhrases['block'];
$btn_class = 'cms-edit-block-btn';
$btn_container_class = 'block-edit-block-btn-container';
$btn_name = 'content';
}
$block_editor = '
<div id="' . $container_id . '" params="' . $param_string . '" class="' . $btn_container_class . '" title="' . htmlspecialchars($block_title) . '">
<div class="' . $btn_class . '">
<div class="cms-btn-image">
<img src="' . $base_url . 'core/admin_templates/img/top_frame/icons/' . $btn_name . '_mode.png" width="15" height="16" alt=""/>
</div>
<div class="cms-btn-text" id="' . $container_id . '_btn">' . $btn_text . '</div>
</div>
<div class="cms-btn-content">
%s
</div>
</div>';
// 1 - text before, 2 - open tag, 3 - open tag attributes, 4 - content inside tag, 5 - closing tag, 6 - text after closing tag
if (preg_match('/^(\s*)<(td|span)(.*?)>(.*)<\/(td|span)>(.*)$/is', $block_content, $regs)) {
// div inside span -> put div outside span
return $regs[1] . '<' . $regs[2] . ' ' . $regs[3] . '>' . str_replace('%s', $regs[4], $block_editor) . '</' . $regs[5] . '>' . $regs[6];
}
return str_replace('%s', $block_content, $block_editor);
}
function IncludeTemplate($params, $silent=null)
{
$t = is_array($params) ? $this->SelectParam($params, 't,template,block,name') : $params;
$cache_timeout = array_key_exists('cache_timeout', $params) ? $params['cache_timeout'] : false;
if ($cache_timeout) {
$cache_key = $this->FormCacheKey('template:' . $t);
$ret = $this->getCache($cache_key);
if ($ret !== false) {
return $ret;
}
}
$t = preg_replace('/\.tpl$/', '', $t);
$data_exists_bak = $this->DataExists;
$this->DataExists = false;
if (!isset($silent) && array_key_exists('is_silent', $params)) {
$silent = $params['is_silent'];
}
if (isset($params['pass_params'])) {
// ability to pass params from block to template
$params = array_merge($this->Params, $params);
}
$this->PushParams($params);
$ret = $this->Run($t, $silent);
$this->PopParams();
$this->CheckNoData($ret, $params);
$this->DataExists = $data_exists_bak || $this->DataExists;
if ($cache_timeout) {
$this->setCache($cache_key, $ret, (int)$cache_timeout);
}
return $ret;
}
function CheckNoData(&$ret, $params)
{
if (array_key_exists('data_exists', $params) && $params['data_exists'] && !$this->DataExists) {
$block_no_data = isset($params['BlockNoData']) ? $params['BlockNoData'] : (isset($params['block_no_data']) ? $params['block_no_data'] : false);
if ($block_no_data) {
$ret = $this->ParseBlock(array('name'=>$block_no_data));
}
else {
$ret = '';
}
}
}
function getCache($name)
{
if (!$this->CachingEnabled) {
return false;
}
$ret = $this->Application->getCache($name, false);
if (preg_match('/^\[DE_MARK:(.*?)\]$/', substr($ret, -11), $regs)) {
$this->DataExists = $regs[1] ? true : false;
$ret = substr($ret, 0, -11);
}
return $ret;
}
function setCache($name, $value, $expiration = 0)
{
if (!$this->CachingEnabled) {
return false;
}
// remeber DataExists in cache, because after cache will be restored
// it will not be available naturally (no tags, that set it will be called)
$value .= '[DE_MARK:' . (int)$this->DataExists . ']';
return $this->Application->setCache($name, $value, $expiration);
}
function FormCacheKey($element, $key_string = '')
{
if (strpos($key_string, 'guest_only') !== false && $this->UserLoggedIn) {
// don't cache, when user is logged-in "guest_only" is specified in key
return '';
}
$parts = Array ();
// 1. replace INLINE variable (from request) into key parts
if (preg_match_all('/\(%(.*?)\)/', $key_string, $regs)) {
// parts in form "(%variable_name)" were found
foreach ($regs[1] as $variable_name) {
$variable_value = $this->Application->GetVar($variable_name);
$key_string = str_replace('(%' . $variable_name . ')', $variable_value, $key_string);
}
}
// 2. replace INLINE serial numbers (they may not be related to any prefix at all)
// Serial number also could be composed of inline variables!
if (preg_match_all('/\[%(.*?)%\]/', $key_string, $regs)) {
// format "[%LangSerial%]" - prefix-wide serial in case of any change in "lang" prefix
// format "[%LangIDSerial:5%]" - one id-wide serial in case of data, associated with given id was changed
// format "[%CiIDSerial:ItemResourceId:5%]" - foreign key-based serial in case of data, associated with given foreign key was changed
foreach ($regs[1] as $serial_name) {
$serial_value = $this->Application->getCache('[%' . $serial_name . '%]');
$key_string = str_replace('[%' . $serial_name . '%]', '[%' . $serial_name . '=' . $serial_value . '%]', $key_string);
}
}
/*
Always add:
===========
* "var:m_lang" - show content on current language
* "var:t" - template from url, used to differ multiple pages using same physical template (like as design)
* "var:admin,editing_mode" - differ cached content when different editing modes are used
* "var:m_cat_id,m_cat_page" - pass current category
* "var:page,per_page,sort_by" - list pagination/sorting parameters
* "prefix:theme-file" - to be able to reset all cached templated using "Rebuild Theme Files" function
* "prefix:phrases" - use latest phrase translations
* "prefix:conf" - output could slighly differ based on configuration settings
*/
$key_string = rtrim('var:m_lang,t,admin,editing_mode,m_cat_id,m_cat_page,page,per_page,sort_by;prefix:theme-file,phrases,conf;' . $key_string, ';');
$keys = explode(';', $key_string);
/*
Possible parts of a $key_string (all can have multiple occurencies):
====================================================================
* prefix:<prefixA>[,<prefixB>,<prefixC>] - include global serial for given prefix(-es)
* skip_prefix:<prefix1>[,<prefix2>,<prefix3>] - exclude global serial for given prefix(-es)
* prefix_id:<prefixA>[,<prefixB>,<prefixC>] - include id-based serial for given prefix(-es)
* skip_prefix_id:<prefix1>[,<prefix2>,<prefix3>] - exclude id-based serial for given prefix(-es)
* var:<aaa>[,<bbb>,<ccc>] - include request variable value(-s)
* skip_var:<varA>[,<varB>,<varC>] - exclude request variable value(-s)
* (%variable_name) - include request variable value (only value without variable name ifself, like in "var:variable_name")
* [%SerialName%] - use to retrieve serial value in free form
*/
// 3. get variable names, prefixes and prefix ids, that should be skipped
$skip_prefixes = $skip_prefix_ids = $skip_variables = Array ();
foreach ($keys as $index => $key) {
if (preg_match('/^(skip_var|skip_prefix|skip_prefix_id):(.*?)$/i', $key, $regs)) {
unset($keys[$index]);
$tmp_parts = explode(',', $regs[2]);
switch ($regs[1]) {
case 'skip_var':
$skip_variables = array_merge($skip_variables, $tmp_parts);
break;
case 'skip_prefix':
$skip_prefixes = array_merge($skip_prefixes, $tmp_parts);
break;
case 'skip_prefix_id':
$skip_prefix_ids = array_merge($skip_prefix_ids, $tmp_parts);
break;
}
}
}
$skip_prefixes = array_unique($skip_prefixes);
$skip_variables = array_unique($skip_variables);
$skip_prefix_ids = array_unique($skip_prefix_ids);
// 4. process keys
foreach ($keys as $key) {
if (preg_match('/^(var|prefix|prefix_id):(.*?)$/i', $key, $regs)) {
$tmp_parts = explode(',', $regs[2]);
switch ($regs[1]) {
case 'var':
// format: "var:country_id" will become "country_id=<country_id>"
$tmp_parts = array_diff($tmp_parts, $skip_variables);
foreach ($tmp_parts as $variable_name) {
$variable_value = $this->Application->GetVar($variable_name);
if ($variable_value !== false) {
$parts[] = $variable_name . '=' . $variable_value;
}
}
break;
case 'prefix':
// format: "prefix:country" will become "[%CountrySerial%]"
$tmp_parts = array_diff($tmp_parts, $skip_prefixes);
foreach ($tmp_parts as $prefix) {
$serial_name = $this->Application->incrementCacheSerial($prefix, null, false);
$parts[] = '[%' . $serial_name . '=' . $this->Application->getCache($serial_name) . '%]';
if (!$this->RewriteUrls) {
// add env-style page and per-page variable, when mod-rewrite is off
$prefix_variables = Array ($prefix . '_Page', $prefix . '_PerPage');
foreach ($prefix_variables as $variable_name) {
$variable_value = $this->Application->GetVar($variable_name);
if ($variable_value !== false) {
$parts[] = $variable_name . '=' . $variable_value;
}
}
}
}
break;
case 'prefix_id':
// format: "id:country" will become "[%CountryIDSerial:5%]"
$tmp_parts = array_diff($tmp_parts, $skip_prefix_ids);
foreach ($tmp_parts as $prefix_id) {
$id = $this->Application->GetVar($prefix_id . '_id');
if ($id !== false) {
$serial_name = $this->Application->incrementCacheSerial($prefix_id, $id, false);
$parts[] = '[%' . $serial_name . '=' . $this->Application->getCache($serial_name) . '%]';
}
}
break;
}
}
elseif ($key == 'currency') {
// based on current currency
$parts[] = 'curr_iso=' . $this->Application->RecallVar('curr_iso');
}
elseif ($key == 'groups') {
// based on logged-in user groups
$parts[] = 'groups=' . $this->Application->RecallVar('UserGroups');
}
elseif ($key == 'guest_only') {
// we know this key, but process it at method beginning
}
else {
throw new ParserException('Unknown key part "<strong>' . $key . '</strong>" used in "<strong>key</strong>" parameter of <inp2:m_Cache key="..."/> tag');
}
}
// 5. add unique given cache key identifier on this page
$parts[] = $element;
$key = implode(':', $parts);
if (defined('DEBUG_MODE') && DEBUG_MODE && $this->Application->isDebugMode()) {
$this->Application->Debugger->appendHTML('Parser Key: ' . $key);
}
return 'parser_' . crc32($key);
}
function PushPointer($pointer, $key)
{
$cache_key = $this->FullCachePage || !$this->CachingEnabled ? '' : $this->FormCacheKey('pointer:' . $pointer, $key);
$this->CachePointers[++$this->CacheLevel] = $cache_key;
return $this->CachePointers[$this->CacheLevel];
}
function PopPointer()
{
return $this->CachePointers[$this->CacheLevel--];
}
function CacheStart($pointer, $key)
{
$pointer = $this->PushPointer($pointer, $key);
if ($pointer) {
$ret = $this->getCache($pointer);
$debug_mode = defined('DEBUG_MODE') && DEBUG_MODE && $this->Application->isDebugMode();
if ($ret !== false) {
echo $debug_mode ? '<!-- CACHED OUTPUT START -->' . $ret . '<!-- /CACHED OUTPUT END -->' : $ret;
$this->PopPointer();
return true;
}
if ($debug_mode) {
echo '<!-- NO CACHE FOR POINTER: ' . $pointer . ' -->';
}
}
ob_start();
return false;
}
function CacheEnd($expiration = 0)
{
$ret = ob_get_clean();
$pointer = $this->PopPointer();
if ($pointer) {
$res = $this->setCache($pointer, $ret, $expiration);
if (defined('DEBUG_MODE') && DEBUG_MODE && $this->Application->isDebugMode()) {
echo '<!-- STORING CACHE FOR POINTER: ' . $pointer . ' [' . $res . '] -->';
}
}
echo $ret;
}
/**
* Performs compression of given files or text
*
* @param mixed $data
* @param bool $raw_script
* @param string $file_extension
* @return string
*/
function CompressScript($data, $raw_script = false, $file_extension = '')
{
$minify_helper =& $this->Application->recallObject('MinifyHelper');
/* @var $minify_helper MinifyHelper */
if ($raw_script) {
$minify_helper->compressString($data, $file_extension);
return $data;
}
return $minify_helper->CompressScriptTag($data);
}
}
class ParserException extends Exception {
public function __construct($message = null, $code = 0, Exception $previous = null, $tag = null)
{
parent::__construct($message, $code, $previous);
if ( isset($tag) ) {
$this->file = $tag['file'];
$this->line = $tag['line'];
}
}
}
\ 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 14674)
+++ branches/5.2.x/core/units/priorites/priority_eh.php (revision 14675)
@@ -1,370 +1,370 @@
<?php
class PriorityEventHandler extends kDBEventHandler {
/**
- * Allows to override standart permission mapping
+ * 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/visits/visits_event_handler.php
===================================================================
--- branches/5.2.x/core/units/visits/visits_event_handler.php (revision 14674)
+++ branches/5.2.x/core/units/visits/visits_event_handler.php (revision 14675)
@@ -1,138 +1,138 @@
<?php
/**
* @version $Id$
* @package In-Portal
* @copyright Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
* @license GNU/GPL
* In-Portal is Open Source software.
* This means that this software may have been modified pursuant
* the GNU General Public License, and as distributed it includes
* or is derivative of works licensed under the GNU General Public License
* or other free or open source software licenses.
* See http://www.in-portal.org/license for copyright notices and details.
*/
defined('FULL_PATH') or die('restricted access!');
class VisitsEventHandler extends kDBEventHandler {
/**
- * Allows to override standart permission mapping
+ * Allows to override standard permission mapping
*
*/
function mapPermissions()
{
parent::mapPermissions();
$permissions = Array(
'OnItemBuild' => Array('self' => true),
);
$this->permMapping = array_merge($this->permMapping, $permissions);
}
/**
* Registers user visit to site
*
* @param kEvent $event
*
* @return void
* @access protected
*/
protected function OnRegisterVisit(&$event)
{
if ( $this->Application->isAdmin || !$this->Application->ConfigValue('UseVisitorTracking') || $this->Application->RecallVar('visit_id') ) {
// admin logins are not registered in visits list
return ;
}
$object =& $event->getObject(Array ('skip_autoload' => true));
/* @var $object kDBItem */
$object->SetDBField('VisitDate_date', adodb_mktime());
$object->SetDBField('VisitDate_time', adodb_mktime());
$object->SetDBField('Referer', getArrayValue($_SERVER, 'HTTP_REFERER'));
$object->SetDBField('IPAddress', $_SERVER['REMOTE_ADDR']);
if ( $object->Create() ) {
$this->Application->StoreVar('visit_id', $object->GetID());
$this->Application->SetVar('visits_id', $object->GetID());
}
}
/**
* Apply any custom changes to list's sql query
*
* @param kEvent $event
* @return void
* @access protected
* @see kDBEventHandler::OnListBuild()
*/
protected function SetCustomQuery(&$event)
{
$object =& $event->getObject();
/* @var $object kDBList */
$types = $event->getEventParam('types');
if ( $types == 'myvisitors' ) {
$user_id = $this->Application->RecallVar('user_id');
$object->addFilter('myitems_user1', 'au.PortalUserId = ' . $user_id);
$object->addFilter('myitems_user2', 'au.PortalUserId >0');
//$object->AddGroupByField('VisitDate');
$object->AddGroupByField('%1$s.VisitId');
}
if ( $types == 'myvisitororders' && $event->Special == 'incommerce' ) {
$user_id = $this->Application->RecallVar('user_id');
$object->addFilter('myitems_orders', 'ord.OrderId IS NOT NULL');
$object->addFilter('myitems_user1', 'au.PortalUserId = ' . $user_id);
$object->addFilter('myitems_user2', 'au.PortalUserId >0');
$object->addFilter('myitems_orders_processed', 'ord.Status = 4');
}
}
/**
* Apply some special processing to object being
* recalled before using it in other events that
* call prepareObject
*
* @param kDBItem|kDBList $object
* @param kEvent $event
* @return void
* @access protected
*/
protected function prepareObject(&$object, &$event)
{
$types = $event->getEventParam('types');
if(method_exists($object, 'AddGroupByField'))
{
if( ($types == 'myvisitors' || !$types) && $object->Special == 'incommerce')
{
$object->addCalculatedField('OrderTotalAmountSum', 'SUM(IF(ord.Status = 4, ord.SubTotal+ord.ShippingCost+ord.VAT, 0))');
$object->addCalculatedField('OrderAffiliateCommissionSum', 'SUM( IF(ord.Status = 4,ord.AffiliateCommission,0))');
$object->addCalculatedField('OrderCountByVisit', 'SUM( IF(ord.Status = 4, 1, 0) )');
}
if (!$types){
$object->AddGroupByField('%1$s.VisitId');
}
}
}
/**
* [HOOK] Updates user_id in current visit
*
* @param kEvent $event
*/
function OnUserLogin(&$event)
{
if ($event->MasterEvent->status == kEvent::erSUCCESS) {
$user_id = $this->Application->RecallVar('user_id');
if ($user_id > 0) {
// for real users only, not root,guest
$this->Application->setVisitField('PortalUserId', $user_id);
}
}
}
}
\ No newline at end of file
Index: branches/5.2.x/core/units/theme_files/theme_file_eh.php
===================================================================
--- branches/5.2.x/core/units/theme_files/theme_file_eh.php (revision 14674)
+++ branches/5.2.x/core/units/theme_files/theme_file_eh.php (revision 14675)
@@ -1,228 +1,228 @@
<?php
/**
* @version $Id$
* @package In-Portal
* @copyright Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
* @license GNU/GPL
* In-Portal is Open Source software.
* This means that this software may have been modified pursuant
* the GNU General Public License, and as distributed it includes
* or is derivative of works licensed under the GNU General Public License
* or other free or open source software licenses.
* See http://www.in-portal.org/license for copyright notices and details.
*/
defined('FULL_PATH') or die('restricted access!');
class ThemeFileEventHandler extends kDBEventHandler {
/**
- * Allows to override standart permission mapping
+ * Allows to override standard permission mapping
*
*/
function mapPermissions()
{
parent::mapPermissions();
$permissions = Array (
'OnLoadBlock' => Array ('subitem' => true),
'OnSaveBlock' => Array ('subitem' => true),
'OnSaveLayout' => Array ('subitem' => true),
);
$this->permMapping = array_merge($this->permMapping, $permissions);
}
/**
* Checks user permission to execute given $event
*
* @param kEvent $event
* @return bool
* @access public
*/
public function CheckPermission(&$event)
{
if ($event->Name == 'OnLoadBlock' || $event->Name == 'OnSaveBlock') {
return $this->Application->isAdminUser;
}
return parent::CheckPermission($event);
}
/**
* Loads template contents into virtual field
*
* @param kEvent $event
* @return void
* @access protected
*/
protected function OnAfterItemLoad(&$event)
{
parent::OnAfterItemLoad($event);
$object =& $event->getObject();
/* @var $object kDBItem */
$filename = $this->_getTemplatePath($object);
if ( file_exists($filename) ) {
$object->SetDBField('FileContents', file_get_contents($filename));
}
else {
$object->SetError('FileContents', 'template_file_missing', 'la_error_TemplateFileMissing');
}
}
/**
* Trim contents of edited template
*
* @param kEvent $event
* @return void
* @access protected
*/
protected function OnBeforeItemUpdate(&$event)
{
parent::OnBeforeItemUpdate($event);
$object =& $event->getObject();
/* @var $object kDBItem */
$file_data = $object->GetDBField('FileContents');
$file_data = str_replace("\r\n", "\n", $file_data);
$file_data = str_replace("\r", "\n", $file_data);
$object->SetDBField('FileContents', trim($file_data));
}
/**
* Saves updated content to template
*
* @param kEvent $event
*/
function OnAfterItemUpdate(&$event)
{
parent::OnAfterItemUpdate($event);
$object =& $event->getObject();
/* @var $object kDBItem */
$filename = $this->_getTemplatePath($object);
if (file_exists($filename) && is_writable($filename)) {
$fp = fopen($filename, 'w');
fwrite($fp, $object->GetDBField('FileContents'));
fclose($fp);
$themes_helper =& $this->Application->recallObject('ThemesHelper');
/* @var $themes_helper kThemesHelper */
$meta_info = $themes_helper->parseTemplateMetaInfo($filename);
$file_description = array_key_exists('desc', $meta_info) ? $meta_info['desc'] : '';
$object->SetDBField('Description', $file_description);
$object->SetDBField('FileMetaInfo', serialize($meta_info));
$object->Update();
}
}
/**
* Returns full path to template file
*
* @param kDBItem $object
* @return string
*/
function _getTemplatePath(&$object)
{
$theme =& $this->Application->recallObject('theme');
/* @var $theme kDBItem */
$path = FULL_PATH . '/themes/' . $theme->GetDBField('Name');
$path .= $object->GetDBField('FilePath') . '/' . $object->GetDBField('FileName');
return $path;
}
/**
* Loads block data based on it's name in request
*
* @param kEvent $event
*/
function OnLoadBlock(&$event)
{
parent::OnNew($event);
$object =& $event->getObject();
/* @var $object kDBItem */
$template_helper =& $this->Application->recallObject('TemplateHelper');
/* @var $template_helper TemplateHelper */
$template_helper->InitHelper($object);
$object->SetDBField('FileName', $template_helper->blockInfo('template_file'));
$object->SetDBField('BlockPosition', $template_helper->blockInfo('start_pos') . ' - ' . $template_helper->blockInfo('end_pos'));
$object->SetDBField('FileContents', $template_helper->blockInfo('content'));
}
/**
* Saves changed template block
*
* @param kEvent $event
*/
function OnSaveBlock(&$event)
{
$object =& $event->getObject( Array('skip_autoload' => true) );
/* @var $object kDBItem */
$items_info = $this->Application->GetVar( $event->getPrefixSpecial(true) );
if ($items_info) {
list ($id, $field_values) = each($items_info);
$object->SetFieldsFromHash($field_values);
$object->setID($id);
}
$status = $object->Validate();
$template_helper =& $this->Application->recallObject('TemplateHelper');
/* @var $template_helper TemplateHelper */
$template_helper->InitHelper($object);
$status = $status && $template_helper->saveBlock($object);
if ($status) {
$event->SetRedirectParam('opener', 'u');
}
else {
$event->status = kEvent::erFAIL;
}
}
/**
* Saves layout on given template
*
* @param kEvent $event
*/
function OnSaveLayout(&$event)
{
$event->status = kEvent::erSTOP;
if (($this->Application->GetVar('ajax') != 'yes') || (EDITING_MODE != EDITING_MODE_DESIGN)) {
return ;
}
$target_order = $this->Application->GetVar('target_order');
$template_helper =& $this->Application->recallObject('TemplateHelper');
/* @var $template_helper TemplateHelper */
if ($template_helper->moveTemplateElements($target_order)) {
echo 'OK';
return ;
}
echo 'FAILED';
}
}
\ No newline at end of file
Index: branches/5.2.x/core/units/categories/categories_tag_processor.php
===================================================================
--- branches/5.2.x/core/units/categories/categories_tag_processor.php (revision 14674)
+++ branches/5.2.x/core/units/categories/categories_tag_processor.php (revision 14675)
@@ -1,2009 +1,2020 @@
<?php
/**
* @version $Id$
* @package In-Portal
* @copyright Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
* @license GNU/GPL
* In-Portal is Open Source software.
* This means that this software may have been modified pursuant
* the GNU General Public License, and as distributed it includes
* or is derivative of works licensed under the GNU General Public License
* or other free or open source software licenses.
* See http://www.in-portal.org/license for copyright notices and details.
*/
class CategoriesTagProcessor extends kDBTagProcessor {
function SubCatCount($params)
{
$object =& $this->getObject($params);
+ /* @var $object kDBItem */
- if (isset($params['today']) && $params['today']) {
+ if ( isset($params['today']) && $params['today'] ) {
$sql = 'SELECT COUNT(*)
- FROM '.$object->TableName.'
- WHERE (ParentPath LIKE "'.$object->GetDBField('ParentPath').'%") AND (CreatedOn > '.(adodb_mktime() - 86400).')';
+ 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
$mod_rewrite_helper = $this->Application->recallObject('ModRewriteHelper');
/* @var $mod_rewrite_helper kModRewriteHelper */
$category_params = Array (
'CategoryId' => $object->GetID(),
'ParentPath' => $object->GetDBField('ParentPath'),
);
$item_template = $mod_rewrite_helper->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->HttpQuery->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
* @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/themes/themes_eh.php
===================================================================
--- branches/5.2.x/core/units/themes/themes_eh.php (revision 14674)
+++ branches/5.2.x/core/units/themes/themes_eh.php (revision 14675)
@@ -1,202 +1,202 @@
<?php
/**
* @version $Id$
* @package In-Portal
* @copyright Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
* @license GNU/GPL
* In-Portal is Open Source software.
* This means that this software may have been modified pursuant
* the GNU General Public License, and as distributed it includes
* or is derivative of works licensed under the GNU General Public License
* or other free or open source software licenses.
* See http://www.in-portal.org/license for copyright notices and details.
*/
defined('FULL_PATH') or die('restricted access!');
class ThemesEventHandler extends kDBEventHandler {
/**
- * Allows to override standart permission mapping
+ * Allows to override standard permission mapping
*
*/
function mapPermissions()
{
parent::mapPermissions();
$permissions = Array(
'OnChangeTheme' => Array('self' => true),
);
$this->permMapping = array_merge($this->permMapping, $permissions);
}
/**
* Checks user permission to execute given $event
*
* @param kEvent $event
* @return bool
* @access public
*/
public function CheckPermission(&$event)
{
if ($event->Name == 'OnItemBuild') {
// check permission without using $event->getSection(),
// so first cache rebuild won't lead to "ldefault_Name" field being used
return true;
}
return parent::CheckPermission($event);
}
/**
* Allows to set selected theme as primary
*
* @param kEvent $event
*/
function OnSetPrimary(&$event)
{
if ($this->Application->CheckPermission('SYSTEM_ACCESS.READONLY', 1)) {
$event->status = kEvent::erFAIL;
return;
}
$ids = $this->StoreSelectedIDs($event);
if ($ids) {
$id = array_shift($ids);
$this->setPrimary($id);
$rebuild_event = new kEvent('adm:OnRebuildThemes');
$this->Application->HandleEvent($rebuild_event);
}
$this->clearSelectedIDs($event);
}
function setPrimary($id)
{
$id_field = $this->Application->getUnitOption($this->Prefix, 'IDField');
$table_name = $this->Application->getUnitOption($this->Prefix, 'TableName');
$sql = 'UPDATE '.$table_name.'
SET PrimaryTheme = 0';
$this->Conn->Query($sql);
$sql = 'UPDATE '.$table_name.'
SET PrimaryTheme = 1, Enabled = 1
WHERE '.$id_field.' = '.$id;
$this->Conn->Query($sql);
}
/**
* Set's primary theme (when checkbox used on editing form)
*
* @param kEvent $event
*/
function OnAfterCopyToLive(&$event)
{
$object =& $this->Application->recallObject($event->Prefix.'.-item', null, Array('skip_autoload' => true, 'live_table' => true));
/* @var $object kDBItem */
$object->Load($event->getEventParam('id'));
if ($object->GetDBField('PrimaryTheme')) {
$this->setPrimary($event->getEventParam('id'));
}
}
/**
* Also rebuilds theme files, when enabled theme is saved
*
* @param kEvent $event
* @return void
* @access protected
*/
protected function OnSave(&$event)
{
parent::OnSave($event);
if ( ($event->status != kEvent::erSUCCESS) || !$event->getEventParam('ids') ) {
return ;
}
$ids = $event->getEventParam('ids');
$id_field = $this->Application->getUnitOption($event->Prefix, 'IDField');
$table_name = $this->Application->getUnitOption($event->Prefix, 'TableName');
$sql = 'SELECT COUNT(*)
FROM ' . $table_name . '
WHERE ' . $id_field . ' IN (' . $ids . ') AND (Enabled = 1)';
$enabled_themes = $this->Conn->GetOne($sql);
if ( $enabled_themes ) {
$rebuild_event = new kEvent('adm:OnRebuildThemes');
$this->Application->HandleEvent($rebuild_event);
}
}
/**
* Allows to change the theme
*
* @param kEvent $event
*/
function OnChangeTheme(&$event)
{
if ($this->Application->isAdminUser) {
// for structure theme dropdown
$this->Application->StoreVar('theme_id', $this->Application->GetVar('theme'));
$this->Application->StoreVar('RefreshStructureTree', 1);
return ;
}
$this->Application->SetVar('t', 'index');
$this->Application->SetVar('m_cat_id', 0);
if (MOD_REWRITE) {
$mod_rewrite_helper =& $this->Application->recallObject('ModRewriteHelper');
/* @var $mod_rewrite_helper kModRewriteHelper */
$mod_rewrite_helper->removePages();
}
$this->Application->SetVar('m_theme', $this->Application->GetVar('theme'));
}
/**
* Apply system filter to themes list
*
* @param kEvent $event
* @return void
* @access protected
* @see kDBEventHandler::OnListBuild()
*/
protected function SetCustomQuery(&$event)
{
parent::SetCustomQuery($event);
$object =& $event->getObject();
/* @var $object kDBList */
if (in_array($event->Special, Array ('enabled', 'selected', 'available')) || !$this->Application->isAdminUser) {
// "enabled" special or Front-End
$object->addFilter('enabled_filter', '%1$s.Enabled = ' . STATUS_ACTIVE);
}
// site domain theme picker
if ($event->Special == 'selected' || $event->Special == 'available') {
$edit_picker_helper =& $this->Application->recallObject('EditPickerHelper');
/* @var $edit_picker_helper EditPickerHelper */
$edit_picker_helper->applyFilter($event, 'Themes');
}
// apply domain-based theme filtering
$themes = $this->Application->siteDomainField('Themes');
if (strlen($themes)) {
$themes = explode('|', substr($themes, 1, -1));
$object->addFilter('domain_filter', '%1$s.ThemeId IN (' . implode(',', $themes) . ')');
}
}
}
Index: branches/5.2.x/core/units/translator/translator_event_handler.php
===================================================================
--- branches/5.2.x/core/units/translator/translator_event_handler.php (revision 14674)
+++ branches/5.2.x/core/units/translator/translator_event_handler.php (revision 14675)
@@ -1,174 +1,174 @@
<?php
/**
* @version $Id$
* @package In-Portal
* @copyright Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
* @license GNU/GPL
* In-Portal is Open Source software.
* This means that this software may have been modified pursuant
* the GNU General Public License, and as distributed it includes
* or is derivative of works licensed under the GNU General Public License
* or other free or open source software licenses.
* See http://www.in-portal.org/license for copyright notices and details.
*/
defined('FULL_PATH') or die('restricted access!');
class TranslatorEventHandler extends kDBEventHandler
{
/**
- * Allows to override standart permission mapping
+ * Allows to override standard permission mapping
*
*/
function mapPermissions()
{
parent::mapPermissions();
$permissions = Array(
'OnChangeLanguage' => Array('subitem' => 'add|edit'),
'OnSaveAndClose' => Array('subitem' => 'add|edit'),
);
$this->permMapping = array_merge($this->permMapping, $permissions);
}
/**
* Check permission of item, that being translated
*
* @param kEvent $event
* @return bool
* @access public
*/
public function CheckPermission(&$event)
{
list($prefix, $field) = $this->getPrefixAndField($event);
$top_prefix = $this->Application->GetTopmostPrefix($prefix, true);
$event->setEventParam('top_prefix', $top_prefix);
return parent::CheckPermission($event);
}
/**
* Returns prefix and field being translated
*
* @param kEvent $event
*/
function getPrefixAndField(&$event)
{
$field = $this->Application->GetVar($event->getPrefixSpecial(true).'_field');
if (strpos($field,':') !== false) {
list($prefix, $field) = explode(':', $field);
}
else {
$prefix = $this->Application->GetVar($event->getPrefixSpecial(true).'_prefix');
}
return Array($prefix, $field);
}
/**
* Loads record to be translated
*
* @param kEvent $event
* @return void
* @access protected
*/
protected function OnLoad(&$event)
{
list($obj_prefix, $field) = $this->getPrefixAndField($event);
$object =& $this->Application->recallObject($obj_prefix);
/* @var $object kDBItem */
$translator =& $event->getObject();
/* @var $translator kDBItem */
$def_lang = $this->Application->GetDefaultLanguageId();
$current_lang = $translator->GetDBField('Language');
if (!$current_lang) $current_lang = $this->Application->RecallVar('trans_lang');
if (!$current_lang) $current_lang = $this->Application->GetVar('m_lang');
/*if ($current_lang == $def_lang) {
$current_lang = $def_lang + 1;
}*/
$this->Application->StoreVar('trans_lang', $current_lang); //remember translation language for user friendlyness
$translator->SetID(1);
$translator->SetDBField('Original', $object->GetDBField('l'.$this->Application->GetVar('m_lang').'_'.$field));
$translator->SetDBField('Language', $current_lang);
$translator->SetDBField('SwitchLanguage', $current_lang);
$translator->SetDBField('Translation', $object->GetDBField('l'.$current_lang.'_'.$field));
$cur_lang =& $this->Application->recallObject('lang.current');
/* @var $cur_lang LanguagesItem */
$cur_lang->Load($current_lang);
$translator->SetDBField('Charset', $cur_lang->GetDBField('Charset'));
$event->redirect = false;
}
/**
* Saves changes into temporary table and closes editing window
- *
+ *
* @param kEvent $event
* @return void
* @access protected
*/
protected function OnSaveAndClose(&$event)
{
$event->CallSubEvent('OnPreSave');
$event->SetRedirectParam('opener', 'u');
}
/**
* Saves edited item into temp table
* If there is no id, new item is created in temp table
*
* @param kEvent $event
* @return void
* @access protected
*/
protected function OnPreSave(&$event)
{
$translator =& $event->getObject();
/* @var $translator kDBItem */
$translator->SetFieldsFromHash( $this->getSubmittedFields($event) );
list($obj_prefix, $field) = $this->getPrefixAndField($event);
$object =& $this->Application->recallObject($obj_prefix);
/* @var $object kDBItem */
$lang = $translator->GetDBField('Language');
$object->SetFieldOptions('l' . $lang . '_' . $field, Array ());
$object->SetDBField('l' . $lang . '_' . $field, $translator->GetDBField('Translation'));
$this->RemoveRequiredFields($object);
$object->Update();
}
/**
* Changes current language in translation popup
*
* @param kEvent $event
* @return void
* @access protected
*/
protected function OnChangeLanguage(&$event)
{
$event->CallSubEvent('OnPreSave');
$object =& $event->getObject();
/* @var $object kDBItem */
$object->SetDBField('Language', $object->GetDBField('SwitchLanguage'));
$event->CallSubEvent('OnLoad');
$event->redirect = false;
}
}
\ No newline at end of file
Index: branches/5.2.x/core/units/mailing_lists/mailing_list_eh.php
===================================================================
--- branches/5.2.x/core/units/mailing_lists/mailing_list_eh.php (revision 14674)
+++ branches/5.2.x/core/units/mailing_lists/mailing_list_eh.php (revision 14675)
@@ -1,330 +1,330 @@
<?php
/**
* @version $Id$
* @package In-Portal
* @copyright Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
* @license GNU/GPL
* In-Portal is Open Source software.
* This means that this software may have been modified pursuant
* the GNU General Public License, and as distributed it includes
* or is derivative of works licensed under the GNU General Public License
* or other free or open source software licenses.
* See http://www.in-portal.org/license for copyright notices and details.
*/
defined('FULL_PATH') or die('restricted access!');
class MailingListEventHandler extends kDBEventHandler {
/**
- * Allows to override standart permission mapping
+ * Allows to override standard permission mapping
*
*/
function mapPermissions()
{
parent::mapPermissions();
$permissions = Array (
'OnCancelMailing' => Array ('self' => 'edit'),
'OnGenerateEmailQueue' => Array ('self' => true),
'OnProcessEmailQueue' => Array ('self' => true),
);
$this->permMapping = array_merge($this->permMapping, $permissions);
}
/**
* Prepare recipient list
*
* @param kEvent $event
*/
function OnNew(&$event)
{
parent::OnNew($event);
$recipient_type = $this->Application->GetVar('mailing_recipient_type');
if (!$recipient_type) {
return ;
}
$recipients = $this->Application->GetVar($recipient_type);
if ($recipients) {
$object =& $event->getObject();
/* @var $object kDBItem */
$to = $recipient_type . '_' . implode(';' . $recipient_type . '_', array_keys($recipients));
$object->SetDBField('To', $to);
}
}
/**
* Don't allow to delete mailings in progress
*
* @param kEvent $event
* @param string $type
* @return void
* @access protected
*/
protected function customProcessing(&$event, $type)
{
if ($event->Name == 'OnMassDelete' && $type == 'before') {
$ids = $event->getEventParam('ids');
if ($ids) {
$id_field = $this->Application->getUnitOption($event->Prefix, 'IDField');
$table_name = $this->Application->getUnitOption($event->Prefix, 'TableName');
$sql = 'SELECT ' . $id_field . '
FROM ' . $table_name . '
WHERE ' . $id_field . ' IN (' . implode(',', $ids) . ') AND Status <> ' . MailingList::PARTIALLY_PROCESSED;
$allowed_ids = $this->Conn->GetCol($sql);
$event->setEventParam('ids', $allowed_ids);
}
}
}
/**
* Delete all realted mails in email queue
*
* @param kEvent $event
*/
function OnAfterItemDelete(&$event)
{
parent::OnAfterItemDelete($event);
$this->_deleteQueue($event);
$object =& $event->getObject();
/* @var $object kDBItem */
// delete mailing attachments after mailing is deleted
$attachments = $object->GetField('Attachments', 'file_paths');
if ($attachments) {
$attachments = explode('|', $attachments);
foreach ($attachments as $attachment_file) {
if (file_exists($attachment_file)) {
unlink($attachment_file);
}
}
}
}
/**
* Cancels given mailing and deletes all it's email queue
*
* @param kEvent $event
*/
function OnCancelMailing(&$event)
{
$object =& $event->getObject( Array('skip_autoload' => true) );
/* @var $object kDBItem */
$ids = $this->StoreSelectedIDs($event);
if ($ids) {
foreach ($ids as $id) {
$object->Load($id);
$object->SetDBField('Status', MailingList::CANCELLED);
$object->Update();
}
}
$this->clearSelectedIDs($event);
}
/**
* Checks, that at least one message text field is filled
*
* @param kEvent $event
* @return void
* @access protected
*/
protected function OnBeforeItemCreate(&$event)
{
parent::OnBeforeItemCreate($event);
$object =& $event->getObject();
/* @var $object kDBItem */
if ( !$this->Application->GetVar('mailing_recipient_type') ) {
// user manually typed email addresses -> normalize
$recipients = str_replace(',', ';', $object->GetDBField('To'));
$recipients = array_map('trim', explode(';', $recipients));
$object->SetDBField('To', implode(';', $recipients));
}
if ( !$object->GetDBField('MessageText') ) {
$object->setRequired('MessageHtml');
}
// remember user, who created mailing, because of his name
// is needed for "From" field, but mailing occurs from cron
$user_id = $this->Application->RecallVar('user_id');
$object->SetDBField('PortalUserId', $user_id);
}
/**
* Deletes mailing list email queue, when it becomes cancelled
*
* @param kEvent $event
*/
function OnAfterItemUpdate(&$event)
{
parent::OnAfterItemUpdate($event);
$object =& $event->getObject();
/* @var $object kDBItem */
$status = $object->GetDBField('Status');
if (($status != $object->GetOriginalField('Status')) && ($status == MailingList::CANCELLED)) {
$this->_deleteQueue($event);
}
}
/**
* Deletes email queue records related with given mailing list
*
* @param kEvent $event
*/
function _deleteQueue(&$event)
{
$object =& $event->getObject();
/* @var $object kDBItem */
$sql = 'DELETE FROM ' . $this->Application->getUnitOption('email-queue', 'TableName') . '
WHERE MailingId = ' . $object->GetID();
$this->Conn->Query($sql);
}
/**
* Allows to safely get mailing configuration variables
*
* @param string $variable_name
* @return int
*/
function _ensureDefault($variable_name)
{
$value = $this->Application->ConfigValue($variable_name);
if ($value === false) {
// ensure default value, when configuration variable is missing
return 10;
}
if (!$value) {
// configuration variable found, but it's value is empty or zero
return false;
}
return $value;
}
/**
* Generates email queue for active mailing lists
*
* @param kEvent $event
*/
function OnGenerateEmailQueue(&$event)
{
$id_field = $this->Application->getUnitOption($event->Prefix, 'IDField');
$table_name = $this->Application->getUnitOption($event->Prefix, 'TableName');
$where_clause = Array (
'Status NOT IN (' . MailingList::CANCELLED . ',' . MailingList::PROCESSED . ')',
'(EmailsQueued < EmailsTotal) OR (EmailsTotal = 0)',
'`To` <> ""',
);
$sql = 'SELECT *
FROM ' . $table_name . '
WHERE (' . implode(') AND (', $where_clause) . ')
ORDER BY ' . $id_field . ' ASC';
$mailing_lists = $this->Conn->Query($sql, $id_field);
if (!$mailing_lists) {
return ;
}
// queue 10 emails per step summary from all mailing lists (FIFO logic)
$to_queue = $this->_ensureDefault('MailingListQueuePerStep');
if ($to_queue === false) {
return ;
}
$mailing_list_helper =& $this->Application->recallObject('MailingListHelper');
/* @var $mailing_list_helper MailingListHelper */
foreach ($mailing_lists as $mailing_id => $mailing_data) {
if ($mailing_data['EmailsTotal'] == 0) {
// no work performed on this mailing list -> calculate totals
$updated_fields = $mailing_list_helper->generateRecipients($mailing_id, $mailing_data);
$updated_fields['Status'] = MailingList::PARTIALLY_PROCESSED;
$mailing_data = array_merge($mailing_data, $updated_fields);
$this->Conn->doUpdate($updated_fields, $table_name, $id_field . ' = ' . $mailing_id);
}
$emails = unserialize( $mailing_data['ToParsed'] );
if (!$emails) {
continue;
}
// queue allowed count of emails
$i = 0;
$process_count = count($emails) >= $to_queue ? $to_queue : count($emails);
while ($i < $process_count) {
$mailing_list_helper->queueEmail($emails[$i], $mailing_id, $mailing_data);
$i++;
}
// remove processed emails from array
$to_queue -= $process_count; // decrement available for processing email count
array_splice($emails, 0, $process_count);
$updated_fields = Array (
'ToParsed' => serialize($emails),
'EmailsQueued' => $mailing_data['EmailsQueued'] + $process_count,
);
$mailing_data = array_merge($mailing_data, $updated_fields);
$this->Conn->doUpdate($updated_fields, $table_name, $id_field . ' = ' . $mailing_id);
if (!$to_queue) {
// emails to be queued per step reached -> leave
break;
}
}
}
/**
* Process email queue from cron
*
* @param kEvent $event
*/
function OnProcessEmailQueue(&$event)
{
$deliver_count = $this->_ensureDefault('MailingListSendPerStep');
if ($deliver_count === false) {
return ;
}
$queue_table = $this->Application->getUnitOption('email-queue', 'TableName');
// get queue part to send
$sql = 'SELECT *
FROM ' . $queue_table . '
WHERE (SendRetries < 5) AND (LastSendRetry < ' . strtotime('-2 hours') . ')
LIMIT 0,' . $deliver_count;
$messages = $this->Conn->Query($sql);
if (!$messages) {
// no more messages left in queue
return ;
}
$mailing_list_helper =& $this->Application->recallObject('MailingListHelper');
/* @var $mailing_list_helper MailingListHelper */
$mailing_list_helper->processQueue($messages);
}
}
\ No newline at end of file
Index: branches/5.2.x/core/units/favorites/favorites_eh.php
===================================================================
--- branches/5.2.x/core/units/favorites/favorites_eh.php (revision 14674)
+++ branches/5.2.x/core/units/favorites/favorites_eh.php (revision 14675)
@@ -1,104 +1,104 @@
<?php
/**
* @version $Id$
* @package In-Portal
* @copyright Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
* @license GNU/GPL
* In-Portal is Open Source software.
* This means that this software may have been modified pursuant
* the GNU General Public License, and as distributed it includes
* or is derivative of works licensed under the GNU General Public License
* or other free or open source software licenses.
* See http://www.in-portal.org/license for copyright notices and details.
*/
defined('FULL_PATH') or die('restricted access!');
class FavoritesEventHandler extends kDBEventHandler {
/**
- * Allows to override standart permission mapping
+ * Allows to override standard permission mapping
*
*/
function mapPermissions()
{
parent::mapPermissions();
$permissions = Array (
'OnFavoriteToggle' => Array('subitem' => true),
);
$this->permMapping = array_merge($this->permMapping, $permissions);
}
/**
* Adds/removes item from favorites
*
* @param kEvent $event
*/
function OnFavoriteToggle(&$event)
{
$parent_prefix = $this->Application->getUnitOption($event->Prefix, 'ParentPrefix');
$parent_object =& $this->Application->recallObject($parent_prefix);
/* @var $parent_object kDBItem */
if (!$parent_object->isLoaded() || !$this->Application->CheckPermission('FAVORITES', 0, $parent_object->GetDBField('ParentPath'))) {
$event->status = kEvent::erPERM_FAIL;
return ;
}
$user_id = $this->Application->RecallVar('user_id');
$sql = 'SELECT FavoriteId
FROM '.$this->Application->getUnitOption($event->Prefix, 'TableName').'
WHERE (PortalUserId = '.$user_id.') AND (ResourceId = '.$parent_object->GetDBField('ResourceId').')';
$favorite_id = $this->Conn->GetOne($sql);
$object =& $event->getObject(Array('skip_autoload' => true));
/* @var $object kDBItem */
if ($favorite_id) {
$object->Delete($favorite_id);
}
else {
$object->Create();
}
$event->SetRedirectParam('pass', 'm,'.$parent_prefix);
}
/**
* Prepares Favorite record fields
*
* @param kEvent $event
* @return void
* @access protected
*/
protected function OnBeforeItemCreate(&$event)
{
$object =& $event->getObject();
/* @var $object kDBItem */
$user_id = $this->Application->RecallVar('user_id');
$object->SetDBField('PortalUserId', $user_id);
$parent_prefix = $this->Application->getUnitOption($event->Prefix, 'ParentPrefix');
$parent_object =& $this->Application->recallObject($parent_prefix);
/* @var $parent_object kDBItem */
$object->SetDBField('ResourceId', $parent_object->GetDBField('ResourceId'));
$object->SetDBField('ItemTypeId', $this->Application->getUnitOption($parent_prefix, 'ItemType'));
}
/**
* [HOOK] Deletes favorite record to item, that is beeing deleted
*
* @param kEvent $event
*/
function OnDeleteFavoriteItem(&$event)
{
$main_object =& $event->MasterEvent->getObject();
$sql = 'DELETE FROM '.$this->Application->getUnitOption($event->Prefix, 'TableName').'
WHERE ResourceId = '.$main_object->GetDBField('ResourceId');
$this->Conn->Query($sql);
}
}
\ No newline at end of file
Index: branches/5.2.x/core/units/files/file_eh.php
===================================================================
--- branches/5.2.x/core/units/files/file_eh.php (revision 14674)
+++ branches/5.2.x/core/units/files/file_eh.php (revision 14675)
@@ -1,107 +1,107 @@
<?php
/**
* @version $Id$
* @package In-Portal
* @copyright Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
* @license GNU/GPL
* In-Portal is Open Source software.
* This means that this software may have been modified pursuant
* the GNU General Public License, and as distributed it includes
* or is derivative of works licensed under the GNU General Public License
* or other free or open source software licenses.
* See http://www.in-portal.org/license for copyright notices and details.
*/
defined('FULL_PATH') or die('restricted access!');
class FileEventHandler extends kDBEventHandler {
/**
- * Allows to override standart permission mapping
+ * Allows to override standard permission mapping
*
*/
function mapPermissions()
{
parent::mapPermissions();
$permissions = Array(
'OnDownloadFile' => Array('subitem' => 'view'),
);
$this->permMapping = array_merge($this->permMapping, $permissions);
}
/**
* Remembers user, who is created file record. Makes file primary if no other files are uploaded.
*
* @param kEvent $event
* @return void
* @access protected
*/
protected function OnBeforeItemCreate(&$event)
{
parent::OnBeforeItemCreate($event);
$object =& $event->getObject();
/* @var $object kDBItem */
$object->SetDBField('CreatedById', $this->Application->RecallVar('user_id'));
}
/**
* Resets primary file mark when more then one file is marked as primary
*
* @param kEvent $event
* @return void
* @access protected
*/
protected function OnBeforeItemUpdate(&$event)
{
parent::OnBeforeItemUpdate($event);
$object =& $event->getObject();
/* @var $object kDBItem */
if ( !$object->GetDBField('FileName') ) {
$object->SetDBField('FileName', basename($object->GetDBField('FilePath')));
}
}
/**
* Apply any custom changes to list's sql query
*
* @param kEvent $event
* @return void
* @access protected
* @see kDBEventHandler::OnListBuild()
*/
protected function SetCustomQuery(&$event)
{
parent::SetCustomQuery($event);
$object =& $event->getObject();
/* @var $object kDBList */
-
+
if (!$this->Application->isAdminUser) {
$object->addFilter('active_filter', '%1$s.Status = '.STATUS_ACTIVE);
}
}
/**
* Returns file contents associated with item
*
* @param kEvent $event
*/
function OnDownloadFile(&$event)
{
$object =& $event->getObject();
/* @var $object kDBItem */
$file_helper =& $this->Application->recallObject('FileHelper');
/* @var $file_helper FileHelper */
$filename = $object->GetField('FilePath', 'full_path');
$file_helper->DownloadFile($filename);
$event->status = kEvent::erSTOP;
}
}
\ No newline at end of file
Index: branches/5.2.x/core/units/selectors/selectors_event_handler.php
===================================================================
--- branches/5.2.x/core/units/selectors/selectors_event_handler.php (revision 14674)
+++ branches/5.2.x/core/units/selectors/selectors_event_handler.php (revision 14675)
@@ -1,436 +1,436 @@
<?php
/**
* @version $Id$
* @package In-Portal
* @copyright Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
* @license GNU/GPL
* In-Portal is Open Source software.
* This means that this software may have been modified pursuant
* the GNU General Public License, and as distributed it includes
* or is derivative of works licensed under the GNU General Public License
* or other free or open source software licenses.
* See http://www.in-portal.org/license for copyright notices and details.
*/
defined('FULL_PATH') or die('restricted access!');
class SelectorsEventHandler extends kDBEventHandler
{
/**
- * Allows to override standart permission mapping
+ * Allows to override standard permission mapping
*
*/
function mapPermissions()
{
parent::mapPermissions();
$permissions = Array(
'OnResetToBase' => Array('subitem' => 'add|edit'),
'OnMassResetToBase' => Array('subitem' => 'add|edit'),
'OnOpenStyleEditor' => Array('subitem' => 'add|edit'),
'OnSaveStyle' => Array('subitem' => 'add|edit'),
);
$this->permMapping = array_merge($this->permMapping, $permissions);
}
/**
* Occurs before an item has been cloned
* Id of newly created item is passed as event' 'id' param
*
* @param kEvent $event
* @return void
* @access protected
*/
protected function OnBeforeClone(&$event)
{
parent::OnBeforeClone($event);
$event->Init($event->Prefix, '-item');
$object =& $event->getObject();
/* @var $object kDBItem */
$title_field = 'SelectorName';
$new_name = $object->GetDBField($title_field);
$original_checked = false;
$foreign_key = $event->getEventParam('foreign_key'); // in case if whole stylesheet is cloned
if ( $foreign_key === false ) {
$foreign_key = $object->GetDBField('StylesheetId');
} // in case if selector is copied ifself
do {
if ( preg_match('/(.*)-([\d]+)/', $new_name, $regs) ) {
$new_name = $regs[1] . '-' . ($regs[2] + 1);
}
elseif ( $original_checked ) {
$new_name = $new_name . '-1';
}
// if we are cloning in temp table this will look for names in temp table,
// since object' TableName contains correct TableName (for temp also!)
// if we are cloning live - look in live
$query = ' SELECT ' . $title_field . '
FROM ' . $object->TableName . '
WHERE ' . $title_field . ' = ' . $this->Conn->qstr($new_name) . ' AND StylesheetId = ' . $foreign_key;
$res = $this->Conn->GetOne($query);
/*// if not found in live table, check in temp table if applicable
if ($res === false && $object->Special == 'temp') {
$query = 'SELECT '.$name_field.' FROM '.$this->GetTempName($master['TableName']).'
WHERE '.$name_field.' = '.$this->Conn->qstr($new_name);
$res = $this->Conn->GetOne($query);
}*/
$original_checked = true;
} while ( $res !== false );
$object->SetDBField($title_field, $new_name);
}
/**
* Show base styles or block styles
*
* @param kEvent $event
* @return void
* @access protected
* @see kDBEventHandler::OnListBuild()
*/
protected function SetCustomQuery(&$event)
{
$object =& $event->getObject();
/* @var $object kDBList */
switch ( $event->Special ) {
case 'base':
$object->addFilter('type_filter', '%1$s.Type = 1');
break;
case 'block':
$object->addFilter('type_filter', '%1$s.Type = 2');
break;
}
}
/**
* Occurs before updating item
*
* @param kEvent $event
* @return void
* @access protected
*/
protected function OnBeforeItemUpdate(&$event)
{
parent::OnBeforeItemUpdate($event);
$this->SerializeSelectorData($event);
}
/**
* Occurs before creating item
*
* @param kEvent $event
* @return void
* @access protected
*/
protected function OnBeforeItemCreate(&$event)
{
parent::OnBeforeItemCreate($event);
-
+
$this->SerializeSelectorData($event);
}
/**
* Enter description here...
*
* @param kEvent $event
*/
function OnAfterItemUpdate(&$event)
{
$this->UnserializeSelectorData($event);
}
/**
* Occurs after creating item
*
* @param kEvent $event
* @return void
* @access protected
*/
protected function OnAfterItemCreate(&$event)
{
parent::OnAfterItemCreate($event);
$this->UnserializeSelectorData($event);
}
/**
* Gets special of main item for linking with sub-item
*
* @param kEvent $event
* @return string
*/
function getMainSpecial(&$event)
{
return '';
}
/**
* Save css-style name & description before opening css editor
*
* @param kEvent $event
*/
function OnOpenStyleEditor(&$event)
{
$this->SaveChanges($event);
$event->redirect = false;
}
/**
* Saves Changes to Item
*
* @param kEvent $event
*/
function SaveChanges(&$event)
{
$object =& $event->getObject( Array('skip_autoload' => true) );
/* @var $object kDBItem */
$items_info = $this->Application->GetVar($event->getPrefixSpecial(true));
if ( $items_info ) {
list($id, $field_values) = each($items_info);
-
+
if ( $id == 0 ) {
$parent_id = getArrayValue($field_values, 'ParentId');
if ( $parent_id ) {
$object->Load($parent_id);
}
$object->SetFieldsFromHash($field_values);
$object->Create();
$this->Application->SetVar($event->getPrefixSpecial() . '_id', $object->GetID());
}
else {
$object->Load($id);
$object->SetFieldsFromHash($field_values);
$object->Update();
}
}
}
/**
* Save style changes from style editor
*
* @param kEvent $event
*/
function OnSaveStyle(&$event)
{
$this->SaveChanges($event);
$object =& $event->getObject();
$this->Application->SetVar($event->getPrefixSpecial().'_id', $object->GetId() );
$this->finalizePopup($event);
}
/**
* Extract styles
*
* @param kEvent $event
* @return void
* @access protected
*/
protected function OnAfterItemLoad(&$event)
{
parent::OnAfterItemLoad($event);
$object =& $event->getObject();
/* @var $object kDBItem */
$selector_data = $object->GetDBField('SelectorData');
if ( $selector_data ) {
$selector_data = unserialize($selector_data);
$object->SetDBField('SelectorData', $selector_data);
}
else {
$selector_data = Array ();
}
$this->AddParentProperties($event, $selector_data);
}
/**
* Serialize item before saving to db
*
* @param kEvent $event
*/
function SerializeSelectorData(&$event)
{
$object =& $event->getObject();
/* @var $object kDBItem */
$selector_data = $object->GetDBField('SelectorData');
if ( !$selector_data ) {
$selector_data = Array ();
}
$selector_data = $this->RemoveParentProperties($event, $selector_data);
if ( !kUtil::IsSerialized($selector_data) ) {
$selector_data = serialize($selector_data);
}
$object->SetDBField('SelectorData', $selector_data);
}
/**
* Unserialize data back when update was made
*
* @param kEvent $event
*/
function UnserializeSelectorData(&$event)
{
$object =& $event->getObject();
/* @var $object kDBItem */
$selector_data = $object->GetDBField('SelectorData');
if ( !$selector_data ) {
$selector_data = Array ();
}
if ( kUtil::IsSerialized($selector_data) ) {
$selector_data = unserialize($selector_data);
}
$selector_data = $this->AddParentProperties($event, $selector_data);
$object->SetDBField('SelectorData', $selector_data);
}
/**
* Populate options based on temporary table :)
*
* @param kEvent $event
*/
function OnPrepareBaseStyles(&$event)
{
$object =& $event->getObject();
$parent_info = $object->getLinkedInfo();
$title_field = $this->Application->getUnitOption($event->Prefix,'TitleField');
$sql = 'SELECT '.$title_field.', '.$object->IDField.' FROM '.$object->TableName.' WHERE Type = 1 AND StylesheetId = '.$parent_info['ParentId'].' ORDER BY '.$title_field;
$options = $this->Conn->GetCol($sql,$object->IDField);
$object->SetFieldOption('ParentId', 'options', $options);
}
/**
* Remove properties of parent style that match by value from style
*
* @param kEvent $event
*/
function RemoveParentProperties(&$event, $selector_data)
{
$object =& $event->getObject();
/* @var $object kDBItem */
$parent_id = $object->GetDBField('ParentId');
if ( $parent_id ) {
$sql = 'SELECT SelectorData
FROM ' . $object->TableName . '
WHERE ' . $object->IDField . ' = ' . $parent_id;
$base_selector_data = $this->Conn->GetOne($sql);
if ( kUtil::IsSerialized($base_selector_data) ) {
$base_selector_data = unserialize($base_selector_data);
}
foreach ($selector_data as $prop_name => $prop_value) {
if ( !$prop_value || getArrayValue($base_selector_data, $prop_name) == $prop_value ) {
unset($selector_data[$prop_name]);
}
}
}
else {
foreach ($selector_data as $prop_name => $prop_value) {
if ( !$prop_value ) {
unset($selector_data[$prop_name]);
}
}
}
$object->SetDBField('SelectorData', $selector_data);
return $selector_data;
}
/**
* Add back properties from parent style, that match this style property values
*
* @param kEvent $event
*/
function AddParentProperties(&$event, $selector_data)
{
$object =& $event->getObject();
/* @var $object kDBItem */
$parent_id = $object->GetDBField('ParentId');
if ( $parent_id ) {
$sql = 'SELECT SelectorData
FROM ' . $object->TableName . '
WHERE ' . $object->IDField . ' = ' . $parent_id;
$base_selector_data = $this->Conn->GetOne($sql);
if ( kUtil::IsSerialized($base_selector_data) ) {
$base_selector_data = unserialize($base_selector_data);
}
$selector_data = kUtil::array_merge_recursive($base_selector_data, $selector_data);
$object->SetDBField('SelectorData', $selector_data);
return $selector_data;
}
return Array ();
}
/**
* Reset Style definition to base style -> no customizations
*
* @param kEvent $event
*/
function OnResetToBase(&$event)
{
$object =& $event->getObject();
/* @var $object SelectorsItem */
$object->SetFieldsFromHash( $this->getSubmittedFields($event) );
$object->ResetStyle();
$event->SetRedirectParam('pass', 'all,' . $event->getPrefixSpecial());
}
/**
* Resets selected styles properties to values of their base classes
*
* @param kEvent $event
*/
function OnMassResetToBase(&$event)
{
$object =& $event->getObject( Array('skip_autoload' => true) );
/* @var $object SelectorsItem */
$items_info = $this->Application->GetVar( $event->getPrefixSpecial(true) );
if ( $items_info ) {
foreach ($items_info as $id => $field_values) {
$object->Load($id);
$object->ResetStyle();
}
}
}
}
\ No newline at end of file
Index: branches/5.2.x/core/units/forms/forms/forms_eh.php
===================================================================
--- branches/5.2.x/core/units/forms/forms/forms_eh.php (revision 14674)
+++ branches/5.2.x/core/units/forms/forms/forms_eh.php (revision 14675)
@@ -1,622 +1,622 @@
<?php
/**
* @version $Id$
* @package In-Portal
* @copyright Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
* @license GNU/GPL
* In-Portal is Open Source software.
* This means that this software may have been modified pursuant
* the GNU General Public License, and as distributed it includes
* or is derivative of works licensed under the GNU General Public License
* or other free or open source software licenses.
* See http://www.in-portal.org/license for copyright notices and details.
*/
defined('FULL_PATH') or die('restricted access!');
class FormsEventHandler extends kDBEventHandler {
/**
- * Allows to override standart permission mapping
+ * Allows to override standard permission mapping
*
*/
function mapPermissions()
{
parent::mapPermissions();
$permissions = Array(
// user can view any form on front-end
'OnItemBuild' => Array('self' => true),
);
$this->permMapping = array_merge($this->permMapping, $permissions);
}
function OnCreateSubmissionNodes(&$event)
{
if (defined('IS_INSTALL') && IS_INSTALL) {
// skip any processing, because Forms table doesn't exists until install is finished
return ;
}
$forms = $this->getForms();
if (!$forms) {
return ;
}
$form_subsection = Array(
'parent' => 'in-portal:forms',
'icon' => 'form_submission',
'label' => '',
'url' => Array('t' => 'submissions/submissions_list', 'pass' => 'm,form'),
'permissions' => Array('view', 'add', 'edit', 'delete'),
'priority' => 1,
'type' => stTREE,
);
$priority = 1;
$sections = $this->Application->getUnitOption($event->Prefix, 'Sections');
foreach ($forms as $form_id => $form_name) {
$this->Application->Phrases->AddCachedPhrase('form_sub_label_'.$form_id, $form_name);
$this->Application->Phrases->AddCachedPhrase('la_description_in-portal:submissions:'.$form_id, $form_name.' Submissions');
$form_subsection['label'] = 'form_sub_label_'.$form_id;
$form_subsection['url']['form_id'] = $form_id;
$form_subsection['priority'] = $priority++;
$sections['in-portal:submissions:'.$form_id] = $form_subsection;
}
$this->Application->setUnitOption($event->Prefix, 'Sections', $sections);
}
function getForms()
{
$cache_key = 'forms[%FormSerial%]';
$forms = $this->Application->getCache($cache_key);
if ($forms === false) {
$this->Conn->nextQueryCachable = true;
$sql = 'SELECT Title, FormId
FROM ' . TABLE_PREFIX . 'Forms
ORDER BY Title ASC';
$forms = $this->Conn->GetCol($sql, 'FormId');
$this->Application->setCache($cache_key, $forms);
}
return $forms;
}
/**
* Saves content of temp table into live and
* redirects to event' default redirect (normally grid template)
*
* @param kEvent $event
* @return void
* @access protected
*/
protected function OnSave(&$event)
{
parent::OnSave($event);
if ( $event->status == kEvent::erSUCCESS ) {
$this->OnCreateFormFields($event);
$this->_deleteSectionCache();
}
}
/**
* Deletes all selected items.
* Automatically recurse into sub-items using temp handler, and deletes sub-items
* by calling its Delete method if sub-item has AutoDelete set to true in its config file
*
* @param kEvent $event
* @return void
* @access protected
*/
protected function OnMassDelete(&$event)
{
parent::OnMassDelete($event);
if ( $event->status == kEvent::erSUCCESS ) {
$this->_deleteSectionCache();
}
}
function _deleteSectionCache()
{
$reset_event = new kEvent('adm:OnResetSections');
$this->Application->HandleEvent($reset_event);
$this->Application->StoreVar('RefreshStructureTree', 1);
}
/**
* Dynamically fills custom data config
*
* @param kEvent $event
*/
function OnCreateFormFields(&$event)
{
$cur_fields = $this->Conn->Query('DESCRIBE '.TABLE_PREFIX.'FormSubmissions', 'Field');
$cur_fields = array_keys($cur_fields);
// keep all fields, that are not created on the fly (includes ones, that are added during customizations)
foreach ($cur_fields as $field_index => $field_name) {
if (!preg_match('/^fld_[\d]+/', $field_name)) {
unset($cur_fields[$field_index]);
}
}
$desired_fields = $this->Conn->GetCol('SELECT CONCAT(\'fld_\', FormFieldId) FROM '.TABLE_PREFIX.'FormFields ORDER BY FormFieldId');
$sql = array();
$fields_to_add = array_diff($desired_fields, $cur_fields);
foreach ($fields_to_add as $field) {
$field_expression = $field.' Text NULL';
$sql[] = 'ADD COLUMN '.$field_expression;
}
$fields_to_drop = array_diff($cur_fields, $desired_fields);
foreach ($fields_to_drop as $field) {
$sql[] = 'DROP COLUMN '.$field;
}
if ($sql) {
$query = 'ALTER TABLE '.TABLE_PREFIX.'FormSubmissions '.implode(', ', $sql);
$this->Conn->Query($query);
}
}
/**
* Enter description here...
*
* @param kEvent $event
* @return void
* @access protected
*/
protected function OnFormSubmit(&$event)
{
$object =& $event->getObject();
/* @var $object kDBItem */
$fields = explode(',',$this->Application->GetVar('fields'));
$required_fields = explode(',', $this->Application->GetVar('required_fields'));
$fields_params = $this->Application->GetVar('fields_params');
$virtual_fields = $this->Application->getUnitOption($event->Prefix, 'VirtualFields');
foreach ($fields as $field) {
$virtual_fields[$field] = Array ();
if ( in_array($field, $required_fields) ) {
$virtual_fields[$field]['required'] = 1;
}
$params = getArrayValue($fields_params, $field);
if ( $params !== false ) {
if ( getArrayValue($params, 'Type') == 'email' ) {
$virtual_fields[$field]['formatter'] = 'kFormatter';
$virtual_fields[$field]['regexp'] = '/^(' . REGEX_EMAIL_USER . '@' . REGEX_EMAIL_DOMAIN . ')$/i';
$virtual_fields[$field]['error_msgs'] = Array ('invalid_format' => '!la_invalid_email!');
}
if ( getArrayValue($params, 'Type') == 'file' ) {
$virtual_fields[$field]['formatter'] = 'kUploadFormatter';
$virtual_fields[$field]['upload_dir'] = '/uploads/sketches/';
}
}
}
$object->SetVirtualFields($virtual_fields);
$field_values = $this->getSubmittedFields($event);
$checkboxes = explode(',', $this->Application->GetVar('checkbox_fields')); // MailingList,In-Link,In-Newz,In-Bulletin
foreach ($checkboxes as $checkbox) {
if (isset($field_values[$checkbox])) {
$field_values[$checkbox] = 1;
}
else {
$field_values[$checkbox] = '0';
}
}
$object->SetFieldsFromHash($field_values);
if ( $object->Validate() ) {
$event->redirect = $this->Application->GetVar('success_template');
$this->Application->EmailEventAdmin($this->Application->GetVar('email_event'));
$send_params = Array (
'to_email' => $field_values[$this->Application->GetVar('email_field')],
'to_name' => $field_values[$this->Application->GetVar('name_field')]
);
$this->Application->EmailEventUser($this->Application->GetVar('email_event'), null, $send_params);
if ( $field_values['MailingList'] ) {
$this->Application->StoreVar('SubscriberEmail', $field_values['Email']);
$this->Application->HandleEvent($sub_event, 'u:OnSubscribeUser', Array ('no_unsubscribe' => 1));
}
}
else {
$event->status = kEvent::erFAIL;
}
}
/**
* Don't use security image, when form requires login
*
* @param kEvent $event
* @return void
* @access protected
*/
protected function OnBeforeItemCreate(&$event)
{
parent::OnBeforeItemCreate($event);
$this->itemChanged($event);
}
/**
* Don't use security image, when form requires login
*
* @param kEvent $event
* @return void
* @access protected
*/
protected function OnBeforeItemUpdate(&$event)
{
parent::OnBeforeItemUpdate($event);
$this->itemChanged($event);
}
/**
* Occurs before item is changed
*
* @param kEvent $event
*/
function itemChanged(&$event)
{
$this->_validatePopSettings($event);
$this->_disableSecurityImage($event);
$this->_setRequired($event);
}
/**
* Validates POP3 settings (performs test connect)
*
* @param kEvent $event
*/
function _validatePopSettings(&$event)
{
$object =& $event->getObject();
/* @var $object kDBItem */
$modes = Array ('Reply', 'Bounce');
$fields = Array ('Server', 'Port', 'Username', 'Password');
$changed_fields = array_keys( $object->GetChangedFields() );
foreach ($modes as $mode) {
$set = true;
$changed = false;
foreach ($fields as $field) {
$value = $object->GetDBField($mode . $field);
if (strlen( trim($value) ) == 0) {
$set = false;
break;
}
if (!$changed && in_array($mode . $field, $changed_fields)) {
$changed = true;
}
}
if ($set && $changed) {
// fields are set and at least on of them is changed
$connection_info = Array ();
foreach ($fields as $field) {
$connection_info[ strtolower($field) ] = $object->GetDBField($mode . $field);
}
$pop3_helper =& $this->Application->makeClass('POP3Helper', Array ($connection_info, 10));
/* @var $pop3_helper POP3Helper */
switch ( $pop3_helper->initMailbox(true) ) {
case 'socket':
$object->SetError($mode . 'Server', 'connection_failed');
break;
case 'login':
$object->SetError($mode . 'Username', 'login_failed');
break;
case 'list':
$object->SetError($mode . 'Server', 'message_listing_failed');
break;
}
}
}
}
/**
* Makes email communication fields required, when form uses email communication
*
* @param kEvent $event
*/
function _setRequired(&$event)
{
$object =& $event->getObject();
/* @var $object kDBItem */
$required = $object->GetDBField('EnableEmailCommunication');
$fields = Array (
'ReplyFromName', 'ReplyFromEmail', 'ReplyServer', 'ReplyPort', 'ReplyUsername', 'ReplyPassword',
);
if ($required && $object->GetDBField('BounceEmail')) {
$bounce_fields = Array ('BounceEmail', 'BounceServer', 'BouncePort', 'BounceUsername', 'BouncePassword');
$fields = array_merge($fields, $bounce_fields);
}
$object->setRequired($fields, $required);
}
/**
* Don't use security image, when form requires login
*
* @param kEvent $event
*/
function _disableSecurityImage(&$event)
{
$object =& $event->getObject();
/* @var $object kDBItem */
if ($object->GetDBField('RequireLogin')) {
$object->SetDBField('UseSecurityImage', 0);
}
}
/**
* Queries pop3 server about new incoming mail
*
* @param kEvent $event
*/
function OnProcessReplies(&$event)
{
$this->_processMailbox($event, false);
}
/**
* Queries pop3 server about new incoming mail
*
* @param kEvent $event
*/
function OnProcessBouncedReplies(&$event)
{
$this->_processMailbox($event, true);
}
/**
* Queries pop3 server about new incoming mail
*
* @param kEvent $event
*/
function _processMailbox(&$event, $bounce_mode = false)
{
$this->Application->SetVar('client_mode', 1);
$id_field = $this->Application->getUnitOption($event->Prefix, 'IDField');
$table_name = $this->Application->getUnitOption($event->Prefix, 'TableName');
$sql = 'SELECT *
FROM ' . $table_name . '
WHERE EnableEmailCommunication = 1';
$forms = $this->Conn->Query($sql, $id_field);
$mailbox_helper =& $this->Application->recallObject('MailboxHelper');
/* @var $mailbox_helper MailboxHelper */
$field_prefix = $bounce_mode ? 'Bounce' : 'Reply';
foreach ($forms as $form_id => $form_info) {
$recipient_email = $bounce_mode ? $form_info['BounceEmail'] : $form_info['ReplyFromEmail'];
if (!$recipient_email) {
continue;
}
$mailbox_helper->process(
Array (
'server' => $form_info[$field_prefix . 'Server'],
'port' => $form_info[$field_prefix . 'Port'],
'username' => $form_info[$field_prefix . 'Username'],
'password' => $form_info[$field_prefix . 'Password']
),
Array (&$this, 'isValidRecipient'),
Array (&$this, 'processEmail'),
Array (
'recipient_email' => $recipient_email,
'bounce_mode' => $bounce_mode,
'form_info' => $form_info,
)
);
}
}
function isValidRecipient($params)
{
$mailbox_helper =& $this->Application->recallObject('MailboxHelper');
/* @var $mailbox_helper MailboxHelper */
$recipients = $mailbox_helper->getRecipients();
$recipient_email = $params['recipient_email'];
$emails_found = preg_match_all('/((' . REGEX_EMAIL_USER . ')(@' . REGEX_EMAIL_DOMAIN . '))/i', $recipients, $all_emails);
if (is_array($all_emails)) {
for ($i = 0; $i < $emails_found; $i++) {
if ($all_emails[1][$i] == $recipient_email) {
// only read messages, that are addresses to submission reply email
return true;
}
}
}
// If this is a forwarded message - we drop all the other aliases and deliver only to the x-forward to address;
if (preg_match('/((' . REGEX_EMAIL_USER . ')(@' . REGEX_EMAIL_DOMAIN . '))/i', $mailbox_helper->headers['x-forward-to'], $get_to_email)) {
if ($get_to_email[1] == $recipient_email) {
// only read messages, that are addresses to submission reply email
return true;
}
}
return false;
}
function processEmail($params, &$fields_hash)
{
if ($params['bounce_mode']) {
// mark original message as bounced
$mailbox_helper =& $this->Application->recallObject('MailboxHelper');
/* @var $mailbox_helper MailboxHelper */
if (!array_key_exists('attachments', $mailbox_helper->parsedMessage)) {
// for now only parse bounces based on attachments, skip other bounce types
return false;
}
for ($i = 0; $i < count($mailbox_helper->parsedMessage['attachments']); $i++) {
$attachment =& $mailbox_helper->parsedMessage['attachments'][$i];
switch ($attachment['headers']['content-type']) {
case 'message/delivery-status':
// save as BounceInfo
$mime_decode_helper =& $this->Application->recallObject('MimeDecodeHelper');
/* @var $mime_decode_helper MimeDecodeHelper */
$charset = $mailbox_helper->parsedMessage[ $fields_hash['MessageType'] ][0]['charset'];
$fields_hash['Message'] = $mime_decode_helper->convertEncoding($charset, $attachment['data']);
break;
case 'message/rfc822':
// undelivered message
$fields_hash['Subject'] = $attachment['filename2'] ? $attachment['filename2'] : $attachment['filename'];
break;
}
}
}
if (!preg_match('/^(.*) #verify(.*)$/', $fields_hash['Subject'], $regs)) {
// incorrect subject, no verification code
$form_info = $params['form_info'];
if ($form_info['ProcessUnmatchedEmails'] && ($fields_hash['FromEmail'] != $params['recipient_email'])) {
// it's requested to convert unmatched emails to new submissions
$form_id = $form_info['FormId'];
$this->Application->SetVar('form_id', $form_id);
$sql = 'SELECT ' . $this->Application->getUnitOption('formsubs', 'IDField') . '
FROM ' . $this->Application->getUnitOption('formsubs', 'TableName') . '
WHERE MessageId = ' . $this->Conn->qstr($fields_hash['MessageId']);
$found = $this->Conn->GetOne($sql);
if ($found) {
// don't process same message twice
return false;
}
$sql = 'SELECT *
FROM ' . TABLE_PREFIX . 'FormFields
WHERE (FormId = ' . $form_info['FormId'] . ') AND (EmailCommunicationRole > 0)';
$form_fields = $this->Conn->Query($sql, 'EmailCommunicationRole');
// what roles are filled from what fields
$role_mapping = Array (
SubmissionFormField::COMMUNICATION_ROLE_EMAIL => 'FromEmail',
SubmissionFormField::COMMUNICATION_ROLE_NAME => 'FromName',
SubmissionFormField::COMMUNICATION_ROLE_SUBJECT => 'Subject',
SubmissionFormField::COMMUNICATION_ROLE_BODY => 'Message',
);
$submission_fields = Array ();
foreach ($role_mapping as $role => $email_field) {
if (array_key_exists($role, $form_fields)) {
$submission_fields[ 'fld_' . $form_fields[$role]['FormFieldId'] ] = $fields_hash[$email_field];
}
}
if ($submission_fields) {
// remove object, because it's linked to single form upon creation forever
$this->Application->removeObject('formsubs.-item');
$form_submission =& $this->Application->recallObject('formsubs.-item', null, Array ('skip_autoload' => true));
/* @var $form_submission kDBItem */
// in case that other non-role mapped fields are required
$form_submission->IgnoreValidation = true;
$form_submission->SetDBFieldsFromHash($submission_fields);
$form_submission->SetDBField('FormId', $form_id);
$form_submission->SetDBField('MessageId', $fields_hash['MessageId']);
$form_submission->SetDBField('SubmissionTime_date', adodb_mktime());
$form_submission->SetDBField('SubmissionTime_time', adodb_mktime());
$form_submission->SetDBField('ReferrerURL', $this->Application->Phrase('la_Text_Email'));
return $form_submission->Create();
}
}
return false;
}
$sql = 'SELECT ' . $this->Application->getUnitOption('submission-log', 'IDField') . '
FROM ' . $this->Application->getUnitOption('submission-log', 'TableName') . '
WHERE MessageId = ' . $this->Conn->qstr($fields_hash['MessageId']);
$found = $this->Conn->GetOne($sql);
if ($found) {
// don't process same message twice
return false;
}
$reply_to =& $this->Application->recallObject('submission-log.-reply-to', null, Array ('skip_autoload' => true));
/* @var $reply_to kDBItem */
$reply_to->Load($regs[2], 'VerifyCode');
if (!$reply_to->isLoaded()) {
// fake verification code OR feedback, containing submission log was deleted
return false;
}
if ($params['bounce_mode']) {
// mark original message as bounced
$reply_to->SetDBField('BounceInfo', $fields_hash['Message']);
$reply_to->SetDBField('BounceDate_date', TIMENOW);
$reply_to->SetDBField('BounceDate_time', TIMENOW);
$reply_to->SetDBField('SentStatus', SUBMISSION_LOG_BOUNCE);
$reply_to->Update();
return true;
}
$reply =& $this->Application->recallObject('submission-log.-reply', null, Array ('skip_autoload' => true));
/* @var $reply kDBItem */
$reply->SetDBFieldsFromHash($fields_hash);
$reply->SetDBField('ReplyTo', $reply_to->GetID());
$reply->SetDBField('FormSubmissionId', $reply_to->GetDBField('FormSubmissionId'));
$reply->SetDBField('ToEmail', $params['recipient_email']);
$reply->SetDBField('Subject', $regs[1]); // save subject without verification code
$reply->SetDBField('SentStatus', SUBMISSION_LOG_SENT);
return $reply->Create();
}
}
\ No newline at end of file
Index: branches/5.2.x/core/units/user_profile/user_profile_eh.php
===================================================================
--- branches/5.2.x/core/units/user_profile/user_profile_eh.php (revision 14674)
+++ branches/5.2.x/core/units/user_profile/user_profile_eh.php (revision 14675)
@@ -1,87 +1,87 @@
<?php
/**
* @version $Id$
* @package In-Portal
* @copyright Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
* @license GNU/GPL
* In-Portal is Open Source software.
* This means that this software may have been modified pursuant
* the GNU General Public License, and as distributed it includes
* or is derivative of works licensed under the GNU General Public License
* or other free or open source software licenses.
* See http://www.in-portal.org/license for copyright notices and details.
*/
defined('FULL_PATH') or die('restricted access!');
class UserProfileEventHandler extends kDBEventHandler {
/**
- * Allows to override standart permission mapping
+ * Allows to override standard permission mapping
*
*/
function mapPermissions()
{
parent::mapPermissions();
$permissions = Array (
'OnItemBuild' => Array('subitem' => true),
'OnUpdate' => Array('subitem' => true),
);
$this->permMapping = array_merge($this->permMapping, $permissions);
}
/**
* Saves user profile to database
*
* @param kEvent $event
*/
function OnUpdate(&$event)
{
$items_info = $this->Application->GetVar($event->getPrefixSpecial(true));
list ($user_id, $field_values) = each($items_info);
if ($user_id != $this->Application->RecallVar('user_id')) {
// we are not updating own profile
return ;
}
$public_profile_add = Array ();
$public_profile_remove = Array ();
$profile_mapping = $this->Application->getUnitOption('u', 'UserProfileMapping');
foreach ($field_values as $variable_name => $variable_value) {
if (array_key_exists($variable_name, $profile_mapping)) {
// old style variable for displaying fields in public profile (named "pp_*")
if ($variable_value) {
$public_profile_add[] = $profile_mapping[$variable_name];
}
else {
$public_profile_remove[] = $profile_mapping[$variable_name];
}
}
else {
$this->Application->StorePersistentVar($variable_name, kUtil::unhtmlentities($variable_value));
}
}
if ($public_profile_add || $public_profile_remove) {
$user =& $this->Application->recallObject('u.current');
/* @var $user kDBItem */
// get current value
$display_to_public_old = $user->GetDBField('DisplayToPublic');
$display_to_public_new = $display_to_public_old ? explode('|', substr($display_to_public_old, 1, -1)) : Array ();
// update value
$display_to_public_new = array_diff(array_merge($display_to_public_new, $public_profile_add), $public_profile_remove);
$display_to_public_new = array_unique($display_to_public_new);
$display_to_public_new = $display_to_public_new ? '|' . implode('|', $display_to_public_new) . '|' : '';
if ($display_to_public_new != $display_to_public_old) {
$user->SetDBField('DisplayToPublic', $display_to_public_new);
$user->Update();
}
}
}
}
\ No newline at end of file
Index: branches/5.2.x/core/units/languages/languages_event_handler.php
===================================================================
--- branches/5.2.x/core/units/languages/languages_event_handler.php (revision 14674)
+++ branches/5.2.x/core/units/languages/languages_event_handler.php (revision 14675)
@@ -1,667 +1,667 @@
<?php
/**
* @version $Id$
* @package In-Portal
* @copyright Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
* @license GNU/GPL
* In-Portal is Open Source software.
* This means that this software may have been modified pursuant
* the GNU General Public License, and as distributed it includes
* or is derivative of works licensed under the GNU General Public License
* or other free or open source software licenses.
* See http://www.in-portal.org/license for copyright notices and details.
*/
defined('FULL_PATH') or die('restricted access!');
class LanguagesEventHandler extends kDBEventHandler
{
/**
- * Allows to override standart permission mapping
+ * Allows to override standard permission mapping
*
*/
function mapPermissions()
{
parent::mapPermissions();
$permissions = Array(
'OnChangeLanguage' => Array('self' => true),
'OnSetPrimary' => Array('self' => 'advanced:set_primary|add|edit'),
'OnImportLanguage' => Array('self' => 'advanced:import'),
'OnExportLanguage' => Array('self' => 'advanced:export'),
'OnExportProgress' => Array('self' => 'advanced:export'),
'OnReflectMultiLingualFields' => Array ('self' => 'view'),
'OnSynchronizeLanguages' => Array ('self' => 'edit'),
);
$this->permMapping = array_merge($this->permMapping, $permissions);
}
/**
* Checks user permission to execute given $event
*
* @param kEvent $event
* @return bool
* @access public
*/
public function CheckPermission(&$event)
{
if ($event->Name == 'OnItemBuild') {
// check permission without using $event->getSection(),
// so first cache rebuild won't lead to "ldefault_Name" field being used
return true;
}
return parent::CheckPermission($event);
}
/**
* Allows to get primary language object
*
* @param kEvent $event
*/
function getPassedID(&$event)
{
if ($event->Special == 'primary') {
return $this->Application->GetDefaultLanguageId();
}
return parent::getPassedID($event);
}
/**
* [HOOK] Updates table structure on new language adding/removing language
*
* @param kEvent $event
*/
function OnReflectMultiLingualFields(&$event)
{
if ($this->Application->GetVar('ajax') == 'yes') {
$event->status = kEvent::erSTOP;
}
if (is_object($event->MasterEvent)) {
if ($event->MasterEvent->status != kEvent::erSUCCESS) {
// only rebuild when all fields are validated
return ;
}
if (($event->MasterEvent->Name == 'OnSave') && !$this->Application->GetVar('new_language')) {
// only rebuild during new language adding
return ;
}
}
$ml_helper =& $this->Application->recallObject('kMultiLanguageHelper');
/* @var $ml_helper kMultiLanguageHelper */
$this->Application->UnitConfigReader->ReReadConfigs();
foreach ($this->Application->UnitConfigReader->configData as $prefix => $config_data) {
$ml_helper->createFields($prefix);
}
$event->SetRedirectParam('action_completed', 1);
}
/**
* Allows to set selected language as primary
*
* @param kEvent $event
*/
function OnSetPrimary(&$event)
{
if ($this->Application->CheckPermission('SYSTEM_ACCESS.READONLY', 1)) {
$event->status = kEvent::erFAIL;
return;
}
$this->StoreSelectedIDs($event);
$ids = $this->getSelectedIDs($event);
if ($ids) {
$id = array_shift($ids);
$object =& $event->getObject( Array('skip_autoload' => true) );
/* @var $object LanguagesItem */
$object->Load($id);
$object->copyMissingData( $object->setPrimary() );
}
}
/**
* [HOOK] Reset primary status of other languages if we are saving primary language
*
* @param kEvent $event
*/
function OnUpdatePrimary(&$event)
{
if ($event->MasterEvent->status != kEvent::erSUCCESS) {
return ;
}
$object =& $event->getObject( Array('skip_autoload' => true) );
/* @var $object LanguagesItem */
$object->SwitchToLive();
// set primary for each languages, that have this checkbox checked
$ids = explode(',', $event->MasterEvent->getEventParam('ids'));
foreach ($ids as $id) {
$object->Load($id);
if ($object->GetDBField('PrimaryLang')) {
$object->copyMissingData( $object->setPrimary(true, false) );
}
if ($object->GetDBField('AdminInterfaceLang')) {
$object->setPrimary(true, true);
}
}
// if no primary language left, then set primary last language (not to load again) from edited list
$sql = 'SELECT '.$object->IDField.'
FROM '.$object->TableName.'
WHERE PrimaryLang = 1';
$primary_language = $this->Conn->GetOne($sql);
if (!$primary_language) {
$object->setPrimary(false, false); // set primary language
}
$sql = 'SELECT '.$object->IDField.'
FROM '.$object->TableName.'
WHERE AdminInterfaceLang = 1';
$primary_language = $this->Conn->GetOne($sql);
if (!$primary_language) {
$object->setPrimary(false, true); // set admin interface language
}
}
/**
* Prefills options with dynamic values
*
* @param kEvent $event
*/
function OnAfterConfigRead(&$event)
{
parent::OnAfterConfigRead($event);
$fields = $this->Application->getUnitOption($event->Prefix, 'Fields');
// set dynamic hints for options in date format fields
$options = $fields['InputDateFormat']['options'];
if ($options) {
foreach ($options as $i => $v) {
$options[$i] = $v . ' (' . adodb_date($i) . ')';
}
$fields['InputDateFormat']['options'] = $options;
}
$options = $fields['InputTimeFormat']['options'];
if ($options) {
foreach ($options as $i => $v) {
$options[$i] = $v . ' (' . adodb_date($i) . ')';
}
$fields['InputTimeFormat']['options'] = $options;
}
$this->Application->setUnitOption($event->Prefix, 'Fields', $fields);
}
/**
* Occurs before updating item
*
* @param kEvent $event
* @return void
* @access protected
*/
protected function OnBeforeItemUpdate(&$event)
{
$object =& $event->getObject();
/* @var $object kDBItem */
$status_fields = $this->Application->getUnitOption($event->Prefix, 'StatusField');
$status_field = array_shift($status_fields);
if ( $object->GetDBField('PrimaryLang') == 1 && $object->GetDBField($status_field) == 0 ) {
$object->SetDBField($status_field, 1);
}
}
/**
* Shows only enabled languages on front
*
* @param kEvent $event
* @return void
* @access protected
* @see kDBEventHandler::OnListBuild()
*/
protected function SetCustomQuery(&$event)
{
$object =& $event->getObject();
/* @var $object kDBList */
if (in_array($event->Special, Array ('enabled', 'selected', 'available'))) {
$object->addFilter('enabled_filter', '%1$s.Enabled = ' . STATUS_ACTIVE);
}
// site domain language picker
if ($event->Special == 'selected' || $event->Special == 'available') {
$edit_picker_helper =& $this->Application->recallObject('EditPickerHelper');
/* @var $edit_picker_helper EditPickerHelper */
$edit_picker_helper->applyFilter($event, 'Languages');
}
// apply domain-based language filtering
$languages = $this->Application->siteDomainField('Languages');
if (strlen($languages)) {
$languages = explode('|', substr($languages, 1, -1));
$object->addFilter('domain_filter', '%1$s.LanguageId IN (' . implode(',', $languages) . ')');
}
}
/**
* Copy labels from another language
*
* @param kEvent $event
* @return void
* @access protected
*/
protected function OnAfterItemCreate(&$event)
{
parent::OnAfterItemCreate($event);
$object =& $event->getObject();
/* @var $object kDBItem */
$src_language = $object->GetDBField('CopyFromLanguage');
if ( $object->GetDBField('CopyLabels') && $src_language ) {
$dst_language = $object->GetID();
// 1. schedule data copy after OnSave event is executed
$var_name = $event->getPrefixSpecial() . '_copy_data' . $this->Application->GetVar('m_wid');
$pending_actions = $this->Application->RecallVar($var_name, Array ());
if ( $pending_actions ) {
$pending_actions = unserialize($pending_actions);
}
$pending_actions[$src_language] = $dst_language;
$this->Application->StoreVar($var_name, serialize($pending_actions));
$object->SetDBField('CopyLabels', 0);
}
}
/**
* Saves language from temp table to live
*
* @param kEvent $event
* @return void
* @access protected
*/
protected function OnSave(&$event)
{
parent::OnSave($event);
if ( $event->status != kEvent::erSUCCESS ) {
return;
}
$var_name = $event->getPrefixSpecial() . '_copy_data' . $this->Application->GetVar('m_wid');
$pending_actions = $this->Application->RecallVar($var_name, Array ());
if ( $pending_actions ) {
$pending_actions = unserialize($pending_actions);
}
// create multilingual columns for phrases & email events table first (actual for 6+ language)
$ml_helper =& $this->Application->recallObject('kMultiLanguageHelper');
/* @var $ml_helper kMultiLanguageHelper */
$ml_helper->createFields('phrases');
$ml_helper->createFields('emailevents');
foreach ($pending_actions as $src_language => $dst_language) {
// phrases import
$sql = 'UPDATE ' . $this->Application->getUnitOption('phrases', 'TableName') . '
SET l' . $dst_language . '_Translation = l' . $src_language . '_Translation';
$this->Conn->Query($sql);
// events import
$sql = 'UPDATE ' . $this->Application->getUnitOption('emailevents', 'TableName') . '
SET
l' . $dst_language . '_Subject = l' . $src_language . '_Subject,
l' . $dst_language . '_Body = l' . $src_language . '_Body';
$this->Conn->Query($sql);
}
$this->Application->RemoveVar($var_name);
$event->CallSubEvent('OnReflectMultiLingualFields');
$event->CallSubEvent('OnUpdatePrimary');
}
/**
* Prepare temp tables for creating new item
* but does not create it. Actual create is
* done in OnPreSaveCreated
*
* @param kEvent $event
* @return void
* @access protected
*/
protected function OnPreCreate(&$event)
{
parent::OnPreCreate($event);
$object =& $event->getObject();
/* @var $object kDBItem */
$object->SetDBField('CopyLabels', 1);
$sql = 'SELECT ' . $object->IDField . '
FROM ' . $this->Application->getUnitOption($event->Prefix, 'TableName') . '
WHERE PrimaryLang = 1';
$primary_lang_id = $this->Conn->GetOne($sql);
$object->SetDBField('CopyFromLanguage', $primary_lang_id);
$object->SetDBField('SynchronizationModes', Language::SYNCHRONIZE_DEFAULT);
}
/**
* Sets new language mark
*
* @param kEvent $event
* @return void
* @access protected
*/
protected function OnBeforeDeleteFromLive(&$event)
{
parent::OnBeforeDeleteFromLive($event);
$id_field = $this->Application->getUnitOption($event->Prefix, 'IDField');
$sql = 'SELECT ' . $id_field . '
FROM ' . $this->Application->getUnitOption($event->Prefix, 'TableName') . '
WHERE ' . $id_field . ' = ' . $event->getEventParam('id');
$id = $this->Conn->GetOne($sql);
if ( !$id ) {
$this->Application->SetVar('new_language', 1);
}
}
function OnChangeLanguage(&$event)
{
$language_id = $this->Application->GetVar('language');
if ($this->Application->isAdmin) {
// admin data only
$this->Application->SetVar('m_lang', $language_id);
// set new language for this session (admin interface only)
$this->Application->Session->SetField('Language', $language_id);
// remember last user language in administrative console
if ($this->Application->RecallVar('user_id') == USER_ROOT) {
$this->Application->StorePersistentVar('AdminLanguage', $language_id);
}
else {
$object =& $this->Application->recallObject('u.current');
/* @var $object kDBItem */
$object->SetDBField('AdminLanguage', $language_id);
$object->Update();
}
// without this language change in admin will cause erase of last remembered tree section
$this->Application->SetVar('skip_last_template', 1);
}
else {
// changing language on Front-End
$this->Application->SetVar('m_lang', $language_id);
if (MOD_REWRITE) {
$mod_rewrite_helper =& $this->Application->recallObject('ModRewriteHelper');
/* @var $mod_rewrite_helper kModRewriteHelper */
$mod_rewrite_helper->removePages();
}
}
}
/**
* Parse language XML file into temp tables and redirect to progress bar screen
*
* @param kEvent $event
*/
function OnImportLanguage(&$event)
{
if ($this->Application->CheckPermission('SYSTEM_ACCESS.READONLY', 1)) {
$event->status = kEvent::erFAIL;
return;
}
$items_info = $this->Application->GetVar('phrases_import');
if ($items_info) {
list ($id, $field_values) = each($items_info);
$object =& $this->Application->recallObject('phrases.import', 'phrases', Array('skip_autoload' => true));
/* @var $object kDBItem */
$object->setID($id);
$object->SetFieldsFromHash($field_values);
if (!$object->Validate()) {
$event->status = kEvent::erFAIL;
return ;
}
$filename = $object->GetField('LangFile', 'full_path');
if (!filesize($filename)) {
$object->SetError('LangFile', 'la_empty_file', 'la_EmptyFile');
$event->status = kEvent::erFAIL;
}
$language_import_helper =& $this->Application->recallObject('LanguageImportHelper');
/* @var $language_import_helper LanguageImportHelper */
$language_import_helper->performImport(
$filename,
$object->GetDBField('PhraseType'),
$object->GetDBField('Module'),
$object->GetDBField('ImportOverwrite') ? LANG_OVERWRITE_EXISTING : LANG_SKIP_EXISTING
);
// delete uploaded language pack after import is finished
unlink($filename);
$event->SetRedirectParam('opener', 'u');
}
}
/**
* Stores ids of selected languages and redirects to export language step 1
*
* @param kEvent $event
*/
function OnExportLanguage(&$event)
{
if ($this->Application->CheckPermission('SYSTEM_ACCESS.READONLY', 1)) {
$event->status = kEvent::erFAIL;
return;
}
$this->Application->setUnitOption('phrases','AutoLoad',false);
$this->StoreSelectedIDs($event);
$this->Application->StoreVar('export_language_ids', implode(',', $this->getSelectedIDs($event)) );
$event->setRedirectParams( Array('phrases.export_event' => 'OnNew', 'pass' => 'all,phrases.export') );
}
/**
* Saves selected languages to xml file passed
*
* @param kEvent $event
*/
function OnExportProgress(&$event)
{
$items_info = $this->Application->GetVar('phrases_export');
if ($items_info) {
list($id, $field_values) = each($items_info);
$object =& $this->Application->recallObject('phrases.export', null, Array('skip_autoload' => true));
/* @var $object kDBItem */
$object->setID($id);
$object->SetFieldsFromHash($field_values);
if (!$object->Validate()) {
$event->status = kEvent::erFAIL;
return ;
}
$file_helper =& $this->Application->recallObject('FileHelper');
/* @var $file_helper FileHelper */
$file_helper->CheckFolder(EXPORT_PATH);
if (!is_writable(EXPORT_PATH)) {
$event->status = kEvent::erFAIL;
$object->SetError('LangFile', 'write_error', 'la_ExportFolderNotWritable');
return ;
}
if ( substr($field_values['LangFile'], -5) != '.lang') {
$field_values['LangFile'] .= '.lang';
}
$filename = EXPORT_PATH . '/' . $field_values['LangFile'];
$language_import_helper =& $this->Application->recallObject('LanguageImportHelper');
/* @var $language_import_helper LanguageImportHelper */
if ($object->GetDBField('DoNotEncode')) {
$language_import_helper->setExportEncoding('plain');
}
$language_import_helper->setExportLimits($field_values['ExportPhrases'], $field_values['ExportEmailEvents']);
$lang_ids = explode(',', $this->Application->RecallVar('export_language_ids') );
$language_import_helper->performExport($filename, $field_values['PhraseType'], $lang_ids, $field_values['Module']);
}
$event->redirect = 'regional/languages_export_step2';
$event->SetRedirectParam('export_file', $field_values['LangFile']);
}
/**
* Returns to previous template in opener stack
*
* @param kEvent $event
*/
function OnGoBack(&$event)
{
$event->SetRedirectParam('opener', 'u');
}
function OnScheduleTopFrameReload(&$event)
{
$this->Application->StoreVar('RefreshTopFrame',1);
}
/**
* Do now allow deleting current language
*
* @param kEvent $event
*/
function OnBeforeItemDelete(&$event)
{
$object =& $event->getObject();
/* @var $object kDBItem */
if ( $object->GetDBField('PrimaryLang') || $object->GetDBField('AdminInterfaceLang') || $object->GetID() == $this->Application->GetVar('m_lang') ) {
$event->status = kEvent::erFAIL;
}
}
/**
* Deletes phrases and email events on given language
*
* @param kEvent $event
*/
function OnAfterItemDelete(&$event)
{
parent::OnAfterItemDelete($event);
$object =& $event->getObject();
/* @var $object kDBItem */
// clean Events table
$fields_hash = Array (
'l' . $object->GetID() . '_Subject' => NULL,
'l' . $object->GetID() . '_Body' => NULL,
);
$this->Conn->doUpdate($fields_hash, $this->Application->getUnitOption('emailevents', 'TableName'), 1);
// clean Phrases table
$fields_hash = Array (
'l' . $object->GetID() . '_Translation' => NULL,
);
$this->Conn->doUpdate($fields_hash, $this->Application->getUnitOption('phrases', 'TableName'), 1);
}
/**
* Copy missing phrases across all system languages (starting from primary)
*
* @param kEvent $event
* @return void
* @access protected
*/
protected function OnSynchronizeLanguages(&$event)
{
if ( $this->Application->CheckPermission('SYSTEM_ACCESS.READONLY', 1) ) {
$event->status = kEvent::erFAIL;
return;
}
$source_languages = $target_languages = Array ();
// get language list with primary language first
$sql = 'SELECT SynchronizationModes, LanguageId
FROM ' . TABLE_PREFIX . 'Language
WHERE SynchronizationModes <> ""
ORDER BY PrimaryLang DESC';
$languages = $this->Conn->GetCol($sql, 'LanguageId');
foreach ($languages as $language_id => $synchronization_modes) {
$synchronization_modes = explode('|', substr($synchronization_modes, 1, -1));
if ( in_array(Language::SYNCHRONIZE_TO_OTHERS, $synchronization_modes) ) {
$source_languages[] = $language_id;
}
if ( in_array(Language::SYNCHRONIZE_FROM_OTHERS, $synchronization_modes) ) {
$target_languages[] = $language_id;
}
}
foreach ($source_languages as $source_id) {
foreach ($target_languages as $target_id) {
if ( $source_id == $target_id ) {
continue;
}
$sql = 'UPDATE ' . TABLE_PREFIX . 'Phrase
SET l' . $target_id . '_Translation = l' . $source_id . '_Translation
WHERE COALESCE(l' . $target_id . '_Translation, "") = "" AND COALESCE(l' . $source_id . '_Translation, "") <> ""';
$this->Conn->Query($sql);
}
}
}
}
\ No newline at end of file
Index: branches/5.2.x/core/units/permissions/permissions_event_handler.php
===================================================================
--- branches/5.2.x/core/units/permissions/permissions_event_handler.php (revision 14674)
+++ branches/5.2.x/core/units/permissions/permissions_event_handler.php (revision 14675)
@@ -1,257 +1,257 @@
<?php
/**
* @version $Id$
* @package In-Portal
* @copyright Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
* @license GNU/GPL
* In-Portal is Open Source software.
* This means that this software may have been modified pursuant
* the GNU General Public License, and as distributed it includes
* or is derivative of works licensed under the GNU General Public License
* or other free or open source software licenses.
* See http://www.in-portal.org/license for copyright notices and details.
*/
defined('FULL_PATH') or die('restricted access!');
class PermissionsEventHandler extends kDBEventHandler {
/**
- * Allows to override standart permission mapping
+ * Allows to override standard permission mapping
*
*/
function mapPermissions()
{
parent::mapPermissions();
$permissions = Array(
'OnGroupSavePermissions' => Array('subitem' => 'advanced:manage_permissions'),
);
$this->permMapping = array_merge($this->permMapping, $permissions);
}
/**
* Save category permissions
*
* @param kEvent $event
*/
function OnCategorySavePermissions(&$event)
{
$group_id = $this->Application->GetVar('current_group_id');
$category_id = $this->Application->GetVar('c_id');
$permissions = $this->Application->GetVar($event->getPrefixSpecial(true));
if (isset($permissions[$group_id])) {
$permissions = $permissions[$group_id];
$object =& $event->getObject( Array('skip_autoload' => true) );
$permissions_helper =& $this->Application->recallObject('PermissionsHelper');
/* @var $permissions_helper kPermissionsHelper */
$permissions_helper->LoadPermissions($group_id, $category_id, 0, 'c');
// format: <perm_name>['inherited'] || <perm_name>['value']
$delete_ids = Array();
$create_sql = Array();
$update_sql = Array();
$create_mask = '(%s,%s,'.$group_id.',%s,0,'.$category_id.')';
$new_id = (int)$this->Conn->GetOne('SELECT MIN('.$object->IDField.') FROM '.$object->TableName);
if($new_id > 0) $new_id = 0;
--$new_id;
foreach ($permissions as $perm_name => $perm_data) {
$inherited = $perm_data['inherited'];
$perm_value = isset($perm_data['value']) ? $perm_data['value'] : false;
$perm_id = $permissions_helper->getPermissionID($perm_name);
if ($inherited && ($perm_id != 0)) {
// permission become inherited (+ direct value was set before) => DELETE
$delete_ids[] = $permissions_helper->getPermissionID($perm_name);
}
if (!$inherited) {
// not inherited
if (($perm_id != 0) && ($perm_value != $permissions_helper->getPermissionValue($perm_name))) {
// record was found in db & new value differs from old one => UPDATE
$update_sql[$perm_id] = ' UPDATE '.$object->TableName.'
SET PermissionValue = '.$perm_value.'
WHERE (PermissionId = '.$perm_id.')';
}
if ($perm_id == 0) {
// not found in db, but set directly => INSERT
$create_sql[] = sprintf($create_mask, $new_id--, $this->Conn->qstr($perm_name), $this->Conn->qstr($perm_value));
}
}
// permission state was not changed in all other cases
}
$this->UpdatePermissions($event, $create_sql, $update_sql, $delete_ids);
}
$event->MasterEvent->SetRedirectParam('item_prefix', $this->Application->GetVar('item_prefix'));
$event->MasterEvent->SetRedirectParam('group_id', $this->Application->GetVar('group_id'));
}
/**
* Saves permissions while editing group
*
* @param kEvent $event
*
* @return void
* @access protected
*/
protected function OnGroupSavePermissions(&$event)
{
if ( !$this->Application->CheckPermission('in-portal:user_groups.advanced:manage_permissions', 1) ) {
// no permission to save permissions
return ;
}
$permissions = $this->Application->GetVar($event->getPrefixSpecial(true));
if ( !$permissions ) {
return ;
}
$object =& $event->getObject( Array ('skip_autoload' => true) );
/* @var $object kDBItem */
$group_id = $this->Application->GetVar('g_id');
$permissions_helper =& $this->Application->recallObject('PermissionsHelper');
/* @var $permissions_helper kPermissionsHelper */
$permissions_helper->LoadPermissions($group_id, 0, 1, 'g');
$delete_ids = $create_sql = Array ();
$create_mask = '(%s,%s,' . $group_id . ',%s,1,0)';
$new_id = (int)$this->Conn->GetOne('SELECT MIN(' . $object->IDField . ') FROM ' . $object->TableName);
if ( $new_id > 0 ) {
$new_id = 0;
}
--$new_id;
$sections_helper =& $this->Application->recallObject('SectionsHelper');
/* @var $sections_helper kSectionsHelper */
foreach ($permissions as $section_name => $section_permissions) {
$section_data =& $sections_helper->getSectionData($section_name);
if ( $section_data && isset($section_data['perm_prefix']) ) {
// using permission from other prefix
$section_name = $this->Application->getUnitOption($section_data['perm_prefix'] . '.main', 'PermSection');
}
foreach ($section_permissions as $perm_name => $perm_value) {
if ( !$permissions_helper->isOldPermission($section_name, $perm_name) ) {
$perm_name = $section_name . '.' . $perm_name;
}
$db_perm_value = $permissions_helper->getPermissionValue($perm_name);
if ( $db_perm_value == 1 && $perm_value == 0 ) {
// permission was disabled => delete it's record
$delete_ids[] = $permissions_helper->getPermissionID($perm_name);
}
elseif ( $db_perm_value == 0 && $perm_value == 1 ) {
// permission was enabled => created it's record
$create_sql[$perm_name] = sprintf($create_mask, $new_id--, $this->Conn->qstr($perm_name), $this->Conn->qstr($perm_value));
}
// permission state was not changed in all other cases
}
}
$this->UpdatePermissions($event, $create_sql, Array (), $delete_ids);
if ( $this->Application->GetVar('advanced_save') == 1 ) {
// advanced permission popup [save button]
$this->finalizePopup($event);
// $event->redirect = 'incs/just_close';
}
elseif ( $this->Application->GetVar('section_name') != '' ) {
// save simple permissions before opening advanced permission popup
$event->redirect = false;
}
}
/**
* Apply modification sqls to permissions table
*
* @param kEvent $event
* @param Array $create_sql
* @param Array $update_sql
* @param Array $delete_ids
*/
function UpdatePermissions(&$event, $create_sql, $update_sql, $delete_ids)
{
$object =& $event->getObject();
/* @var $object kDBItem */
if ($delete_ids) {
$action = ChangeLog::DELETE;
$object->Load($delete_ids[count($delete_ids) - 1]);
$delete_sql = ' DELETE FROM '.$object->TableName.'
WHERE '.$object->IDField.' IN ('.implode(',', $delete_ids).')';
$this->Conn->Query($delete_sql);
}
if ($create_sql) {
$create_sql = ' INSERT INTO '.$object->TableName.'
VALUES '.implode(',', $create_sql);
$this->Conn->Query($create_sql);
$sql = 'SELECT MIN(' . $object->IDField . ')
FROM ' . $object->TableName;
$id = $this->Conn->GetOne($sql);
$action = ChangeLog::CREATE;
$object->Load($id);
}
if ($update_sql) {
foreach ($update_sql as $id => $sql) {
$this->Conn->Query($sql);
}
$action = ChangeLog::UPDATE;
$object->Load($id);
$object->SetDBField('PermissionValue', $object->GetDBField('PermissionValue') ? 0 : 1);
}
if ($delete_ids || $create_sql || $update_sql) {
$object->setModifiedFlag($action);
if ($event->Name == 'OnCategorySavePermissions') {
$this->Application->StoreVar('PermCache_UpdateRequired', 1);
}
}
}
/**
* Don't delete permissions from live table in case of new category creation.
* Called as much times as permission count for categories set, so don't
* perform any sql queries here!
*
* @param kEvent $event
*/
function OnBeforeDeleteFromLive(&$event)
{
if ( $event->Prefix == 'c-perm' ) {
// only when saving category permissions, not group permissions
$foreign_keys = $event->getEventParam('foreign_key');
if ( (count($foreign_keys) == 1) && ($foreign_keys[0] == 0) ) {
// parent item has zero id
$temp_object =& $this->Application->recallObject('c');
/* @var $temp_object CategoriesItem */
-
+
if ( $temp_object->isLoaded() ) {
// category with id = 0 found in temp table
$event->status = kEvent::erFAIL;
}
}
}
}
}
\ No newline at end of file
Index: branches/5.2.x/core/units/email_events/email_events_event_handler.php
===================================================================
--- branches/5.2.x/core/units/email_events/email_events_event_handler.php (revision 14674)
+++ branches/5.2.x/core/units/email_events/email_events_event_handler.php (revision 14675)
@@ -1,1136 +1,1136 @@
<?php
/**
* @version $Id$
* @package In-Portal
* @copyright Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
* @license GNU/GPL
* In-Portal is Open Source software.
* This means that this software may have been modified pursuant
* the GNU General Public License, and as distributed it includes
* or is derivative of works licensed under the GNU General Public License
* or other free or open source software licenses.
* See http://www.in-portal.org/license for copyright notices and details.
*/
defined('FULL_PATH') or die('restricted access!');
class EmailEventsEventsHandler extends kDBEventHandler
{
/**
- * Allows to override standart permission mapping
+ * Allows to override standard permission mapping
*
*/
function mapPermissions()
{
parent::mapPermissions();
$permissions = Array (
'OnFrontOnly' => Array ('self' => 'edit'),
'OnSaveSelected' => Array ('self' => 'view'),
'OnProcessEmailQueue' => Array ('self' => 'add|edit'),
'OnSuggestAddress' => Array ('self' => 'add|edit'),
// events only for developers
'OnPreCreate' => Array ('self' => 'debug'),
'OnDelete' => Array ('self' => 'debug'),
'OnDeleteAll' => Array ('self' => 'debug'),
'OnMassDelete' => Array ('self' => 'debug'),
'OnMassApprove' => Array ('self' => 'debug'),
'OnMassDecline' => Array ('self' => 'debug'),
);
$this->permMapping = array_merge($this->permMapping, $permissions);
}
/**
* Changes permission section to one from REQUEST, not from config
*
* @param kEvent $event
* @return bool
* @access public
*/
public function CheckPermission(&$event)
{
$module = $this->Application->GetVar('module');
if (strlen($module) > 0) {
// checking permission when lising module email events in separate section
$module = explode(':', $module, 2);
if (count($module) == 1) {
$main_prefix = $this->Application->findModule('Name', $module[0], 'Var');
}
else {
$exceptions = Array('Category' => 'c', 'Users' => 'u');
$main_prefix = $exceptions[ $module[1] ];
}
$section = $this->Application->getUnitOption($main_prefix.'.email', 'PermSection');
$event->setEventParam('PermSection', $section);
}
// checking permission when listing all email events when editing language
return parent::CheckPermission($event);
}
/**
* Apply any custom changes to list's sql query
*
* @param kEvent $event
* @return void
* @access protected
* @see kDBEventHandler::OnListBuild()
*/
protected function SetCustomQuery(&$event)
{
$object =& $event->getObject();
/* @var $object kDBList */
if ($event->Special == 'module') {
$module = $this->Application->GetVar('module');
$object->addFilter('module_filter', '%1$s.Module = '.$this->Conn->qstr($module));
}
if (!$event->Special && !$this->Application->isDebugMode()) {
// no special
$object->addFilter('enabled_filter', '%1$s.Enabled <> ' . STATUS_DISABLED);
}
}
/**
* Set default headers
*
* @param kEvent $event
* @return void
* @access protected
*/
protected function OnPreCreate(&$event)
{
parent::OnPreCreate($event);
$object =& $event->getObject();
/* @var $object kDBItem */
$object->SetDBField('Headers', $this->Application->ConfigValue('Smtp_DefaultHeaders'));
}
/**
* Sets status Front-End Only to selected email events
*
* @param kEvent $event
*/
function OnFrontOnly(&$event)
{
if ($this->Application->CheckPermission('SYSTEM_ACCESS.READONLY', 1)) {
$event->status = kEvent::erFAIL;
return ;
}
$ids = implode(',', $this->StoreSelectedIDs($event));
$table_name = $this->Application->getUnitOption($event->Prefix, 'TableName');
$sql = 'UPDATE '.$table_name.'
SET FrontEndOnly = 1
WHERE EventId IN ('.$ids.')';
$this->Conn->Query($sql);
$this->clearSelectedIDs($event);
}
/**
* Sets selected user to email events selected
*
* @param kEvent $event
*/
function OnSelectUser(&$event)
{
if ($event->Special != 'module') {
parent::OnSelectUser($event);
return ;
}
if ($this->Application->CheckPermission('SYSTEM_ACCESS.READONLY', 1)) {
$event->status = kEvent::erFAIL;
return ;
}
$items_info = $this->Application->GetVar('u');
if ($items_info) {
$user_id = array_shift( array_keys($items_info) );
$selected_ids = $this->getSelectedIDs($event, true);
$ids = $this->Application->RecallVar($event->getPrefixSpecial().'_selected_ids');
$id_field = $this->Application->getUnitOption($event->Prefix, 'IDField');
$table_name = $this->Application->getUnitOption($event->Prefix, 'TableName');
$sql = 'UPDATE '.$table_name.'
SET '.$this->Application->RecallVar('dst_field').' = '.$user_id.'
WHERE '.$id_field.' IN ('.$ids.')';
$this->Conn->Query($sql);
}
$this->finalizePopup($event);
}
/**
* Saves selected ids to session
*
* @param kEvent $event
*/
function OnSaveSelected(&$event)
{
$this->StoreSelectedIDs($event);
}
/**
* Returns email event object based on given kEvent object
*
* @param kEvent $event
* @return kDBItem
*/
function &_getEmailEvent(&$event)
{
$false = false;
$name = $event->getEventParam('EmailEventName');
$type = $event->getEventParam('EmailEventType');
$object =& $event->getObject( Array('skip_autoload' => true) );
/* @var $object kDBItem */
if (!$object->isLoaded() || ($object->GetDBField('Event') != $name || $object->GetDBField('Type') != $type)) {
// get event parameters by name & type
$load_keys = Array ('Event' => $name, 'Type' => $type);
$object->Load($load_keys);
if (!$object->isLoaded() || ($object->GetDBField('Enabled') == STATUS_DISABLED)) {
// event record not found OR is disabled
return $false;
}
if ($object->GetDBField('FrontEndOnly') && $this->Application->isAdmin) {
return $false;
}
}
return $object;
}
/**
* Processes email sender
*
* @param kEvent $event
* @param Array $direct_params
*/
function _processSender(&$event, $direct_params = Array ())
{
$this->Application->removeObject('u.email-from');
$object =& $this->_getEmailEvent($event);
/* @var $object kDBItem */
$email = $name = '';
// set defaults from event
if ($object->GetDBField('CustomSender')) {
$address = $object->GetDBField('SenderAddress');
$address_type = $object->GetDBField('SenderAddressType');
switch ($address_type) {
case EmailEvent::ADDRESS_TYPE_EMAIL:
$email = $address;
break;
case EmailEvent::ADDRESS_TYPE_USER:
$sql = 'SELECT FirstName, LastName, Email, PortalUserId
FROM ' . TABLE_PREFIX . 'PortalUser
WHERE Login = ' . $this->Conn->qstr($address);
$user_info = $this->Conn->GetRow($sql);
if ($user_info) {
// user still exists
$email = $user_info['Email'];
$name = trim($user_info['FirstName'] . ' ' . $user_info['LastName']);
$user =& $this->Application->recallObject('u.email-from', null, Array('skip_autoload' => true));
/* @var $user UsersItem */
$user->Load($user_info['PortalUserId']);
}
break;
}
if ($object->GetDBField('SenderName')) {
$name = $object->GetDBField('SenderName');
}
}
// update with custom data given during event execution
if (array_key_exists('from_email', $direct_params)) {
$email = $direct_params['from_email'];
}
if (array_key_exists('from_name', $direct_params)) {
$name = $direct_params['from_name'];
}
// still nothing, set defaults
if (!$email) {
$email = $this->Application->ConfigValue('Smtp_AdminMailFrom');
}
if (!$name) {
$name = strip_tags( $this->Application->ConfigValue('Site_Name') );
}
$esender =& $this->Application->recallObject('EmailSender');
/* @var $esender kEmailSendingHelper */
$esender->SetFrom($email, $name);
return Array ($email, $name);
}
/**
* Processes email recipients
*
* @param kEvent $event
* @param Array $direct_params
*/
function _processRecipients(&$event, $direct_params = Array ())
{
$this->Application->removeObject('u.email-to');
$object =& $this->_getEmailEvent($event);
/* @var $object kDBItem */
$to_email = $to_name = '';
$all_recipients = Array ();
$recipients_xml = $object->GetDBField('Recipients');
if ($recipients_xml) {
$minput_helper =& $this->Application->recallObject('MInputHelper');
/* @var $minput_helper MInputHelper */
// group recipients by type
$records = $minput_helper->parseMInputXML($recipients_xml);
foreach ($records as $record) {
$recipient_type = $record['RecipientType'];
if (!array_key_exists($recipient_type, $all_recipients)) {
$all_recipients[$recipient_type] = Array ();
}
$all_recipients[$recipient_type][] = $record;
}
}
if (!array_key_exists(EmailEvent::RECIPIENT_TYPE_TO, $all_recipients)) {
$all_recipients[EmailEvent::RECIPIENT_TYPE_TO] = Array ();
}
// remove all "To" recipients, when not allowed
$overwrite_to_email = array_key_exists('overwrite_to_email', $direct_params) ? $direct_params['overwrite_to_email'] : false;
if (!$object->GetDBField('CustomRecipient') || $overwrite_to_email) {
$all_recipients[EmailEvent::RECIPIENT_TYPE_TO] = Array ();
}
// update with custom data given during event execution (user_id)
$to_user_id = $event->getEventParam('EmailEventToUserId');
if ($to_user_id > 0) {
$sql = 'SELECT FirstName, LastName, Email
FROM ' . TABLE_PREFIX . 'PortalUser
WHERE PortalUserId = ' . $to_user_id;
$user_info = $this->Conn->GetRow($sql);
if ($user_info) {
$add_recipient = Array (
'RecipientAddressType' => EmailEvent::ADDRESS_TYPE_EMAIL,
'RecipientAddress' => $user_info['Email'],
'RecipientName' => trim($user_info['FirstName'] . ' ' . $user_info['LastName']),
);
array_unshift($all_recipients[EmailEvent::RECIPIENT_TYPE_TO], $add_recipient);
$user =& $this->Application->recallObject('u.email-to', null, Array('skip_autoload' => true));
/* @var $user UsersItem */
$user->Load($to_user_id);
}
}
elseif (is_numeric($to_user_id)) {
// recipient is system user with negative ID (root, guest, etc.) -> send to admin
array_unshift($all_recipients[EmailEvent::RECIPIENT_TYPE_TO], $this->_getDefaultRepipient());
}
// update with custom data given during event execution (email + name)
$add_recipient = Array ();
if (array_key_exists('to_email', $direct_params)) {
$add_recipient['RecipientName'] = '';
$add_recipient['RecipientAddressType'] = EmailEvent::ADDRESS_TYPE_EMAIL;
$add_recipient['RecipientAddress'] = $direct_params['to_email'];
}
if (array_key_exists('to_name', $direct_params)) {
$add_recipient['RecipientName'] = $direct_params['to_name'];
}
if ($add_recipient) {
array_unshift($all_recipients[EmailEvent::RECIPIENT_TYPE_TO], $add_recipient);
}
if (($object->GetDBField('Type') == EmailEvent::EVENT_TYPE_ADMIN) && !$all_recipients[EmailEvent::RECIPIENT_TYPE_TO]) {
// admin email event without direct recipient -> send to admin
array_unshift($all_recipients[EmailEvent::RECIPIENT_TYPE_TO], $this->_getDefaultRepipient());
}
$esender =& $this->Application->recallObject('EmailSender');
/* @var $esender kEmailSendingHelper */
$header_mapping = Array (
EmailEvent::RECIPIENT_TYPE_TO => 'To',
EmailEvent::RECIPIENT_TYPE_CC => 'Cc',
EmailEvent::RECIPIENT_TYPE_BCC => 'Bcc',
);
$default_email = $this->Application->ConfigValue('Smtp_AdminMailFrom');
foreach ($all_recipients as $recipient_type => $recipients) {
// add recipients to email
$pairs = Array ();
foreach ($recipients as $recipient) {
$address = $recipient['RecipientAddress'];
$address_type = $recipient['RecipientAddressType'];
$repipient_name = $recipient['RecipientName'];
switch ($address_type) {
case EmailEvent::ADDRESS_TYPE_EMAIL:
$pairs[] = Array ('email' => $address, 'name' => $repipient_name);
break;
case EmailEvent::ADDRESS_TYPE_USER:
$sql = 'SELECT FirstName, LastName, Email
FROM ' . TABLE_PREFIX . 'PortalUser
WHERE Login = ' . $this->Conn->qstr($address);
$user_info = $this->Conn->GetRow($sql);
if ($user_info) {
// user still exists
$name = trim($user_info['FirstName'] . ' ' . $user_info['LastName']);
$pairs[] = Array (
'email' => $user_info['Email'],
'name' => $name ? $name : $repipient_name,
);
}
break;
case EmailEvent::ADDRESS_TYPE_GROUP:
$sql = 'SELECT u.FirstName, u.LastName, u.Email
FROM ' . TABLE_PREFIX . 'PortalGroup g
JOIN ' . TABLE_PREFIX . 'UserGroup ug ON ug.GroupId = g.GroupId
JOIN ' . TABLE_PREFIX . 'PortalUser u ON u.PortalUserId = ug.PortalUserId
WHERE g.Name = ' . $this->Conn->qstr($address);
$users = $this->Conn->Query($sql);
foreach ($users as $user) {
$name = trim($user_info['FirstName'] . ' ' . $user_info['LastName']);
$pairs[] = Array (
'email' => $user_info['Email'],
'name' => $name ? $name : $repipient_name,
);
}
break;
}
}
if (!$pairs) {
continue;
}
if ($recipient_type == EmailEvent::RECIPIENT_TYPE_TO) {
$to_email = $pairs[0]['email'] ? $pairs[0]['email'] : $default_email;
$to_name = $pairs[0]['name'] ? $pairs[0]['name'] : $to_email;
}
$header_name = $header_mapping[$recipient_type];
foreach ($pairs as $pair) {
$email = $pair['email'] ? $pair['email'] : $default_email;
$name = $pair['name'] ? $pair['name'] : $email;
$esender->AddRecipient($header_name, $email, $name);
}
}
return Array ($to_email, $to_name);
}
/**
* This is default recipient, when we can't determine actual one
*
* @return Array
*/
function _getDefaultRepipient()
{
return Array (
'RecipientName' => $this->Application->ConfigValue('Smtp_AdminMailFrom'),
'RecipientAddressType' => EmailEvent::ADDRESS_TYPE_EMAIL,
'RecipientAddress' => $this->Application->ConfigValue('Smtp_AdminMailFrom'),
);
}
/**
* Returns email event message by ID (headers & body in one piece)
*
* @param kEvent $event
* @param int $language_id
*/
function _getMessageBody(&$event, $language_id = null)
{
if (!isset($language_id)) {
$language_id = $this->Application->GetVar('m_lang');
}
$object =& $this->_getEmailEvent($event);
// 1. get message body
$message_body = $this->_formMessageBody($object, $language_id, $object->GetDBField('MessageType'));
// 2. replace tags if needed
$default_replacement_tags = Array (
'<inp:touser _Field="password"' => '<inp2:u_Field name="Password_plain"',
'<inp:touser _Field="UserName"' => '<inp2:u_Field name="Login"',
'<inp:touser _Field' => '<inp2:u_Field name',
);
$replacement_tags = $object->GetDBField('ReplacementTags');
$replacement_tags = $replacement_tags ? unserialize($replacement_tags) : Array ();
$replacement_tags = array_merge($default_replacement_tags, $replacement_tags);
foreach ($replacement_tags as $replace_from => $replace_to) {
$message_body = str_replace($replace_from, $replace_to, $message_body);
}
return $message_body;
}
/**
* Prepare email message body
*
* @param kDBItem $object
* @param int $language_id
* @return string
*/
function _formMessageBody(&$object, $language_id)
{
$default_language_id = $this->Application->GetDefaultLanguageId();
$fields_hash = Array (
'Headers' => $object->GetDBField('Headers'),
);
// prepare subject
$subject = $object->GetDBField('l' . $language_id . '_Subject');
if (!$subject) {
$subject = $object->GetDBField('l' . $default_language_id . '_Subject');
}
$fields_hash['Subject'] = $subject;
// prepare body
$body = $object->GetDBField('l' . $language_id . '_Body');
if (!$body) {
$body = $object->GetDBField('l' . $default_language_id . '_Body');
}
$fields_hash['Body'] = $body;
$email_message_helper =& $this->Application->recallObject('EmailMessageHelper');
/* @var $email_message_helper EmailMessageHelper */
$ret = $email_message_helper->buildTemplate($fields_hash);
// add footer
$footer = $this->_getFooter($language_id, $object->GetDBField('MessageType'));
if ($ret && $footer) {
$ret .= "\r\n" . $footer;
}
return $ret;
}
/**
* Returns email footer
*
* @param int $language_id
* @param string $message_type
* @return string
*/
function _getFooter($language_id, $message_type)
{
static $footer = null;
if (!isset($footer)) {
$default_language_id = $this->Application->GetDefaultLanguageId();
$sql = 'SELECT l' . $language_id . '_Body, l' . $default_language_id . '_Body
FROM ' . $this->Application->getUnitOption('emailevents', 'TableName') . ' em
WHERE Event = "COMMON.FOOTER"';
$footer_data = $this->Conn->GetRow($sql);
$footer = $footer_data['l' . $language_id . '_Body'];
if (!$footer) {
$footer = $footer_data['l' . $default_language_id . '_Body'];
}
if ($message_type == 'text') {
$esender =& $this->Application->recallObject('EmailSender');
/* @var $esender kEmailSendingHelper */
$footer = $esender->ConvertToText($footer);
}
}
return $footer;
}
/**
* Parse message template and return headers (as array) and message body part
*
* @param string $message
* @param Array $direct_params
* @return Array
*/
function ParseMessageBody($message, $direct_params = Array ())
{
$message_language = $this->_getSendLanguage($direct_params);
$this->_changeLanguage($message_language);
$direct_params['message_text'] = isset($direct_params['message']) ? $direct_params['message'] : ''; // parameter alias
// 1. parse template
$this->Application->InitParser();
$parser_params = $this->Application->Parser->Params; // backup parser params
$this->Application->Parser->SetParams( array_merge($parser_params, $direct_params) );
$message = implode('&|&', explode("\n\n", $message, 2)); // preserves double \n in case when tag is located in subject field
$message = $this->Application->Parser->Parse($message, 'email_template', 0);
$this->Application->Parser->SetParams($parser_params); // restore parser params
// 2. replace line endings, that are send with data submitted via request
$message = str_replace("\r\n", "\n", $message); // possible case
$message = str_replace("\r", "\n", $message); // impossible case, but just in case replace this too
// 3. separate headers from body
$message_headers = Array ();
list($headers, $message_body) = explode('&|&', $message, 2);
$category_helper =& $this->Application->recallObject('CategoryHelper');
/* @var $category_helper CategoryHelper */
$message_body = $category_helper->replacePageIds($message_body);
$headers = explode("\n", $headers);
foreach ($headers as $header) {
$header = explode(':', $header, 2);
$message_headers[ trim($header[0]) ] = trim($header[1]);
}
$this->_changeLanguage();
return Array ($message_headers, $message_body);
}
/**
* Raised when email message should be sent
*
* @param kEvent $event
* @return void
* @access protected
*/
protected function OnEmailEvent(&$event)
{
$email_event_name = $event->getEventParam('EmailEventName');
if ( strpos($email_event_name, '_') !== false ) {
throw new Exception('<span class="debug_error">Invalid email event name</span> <strong>' . $email_event_name . '</strong>. Use only <strong>UPPERCASE characters</strong> and <strong>dots</strong> as email event names');
}
$object =& $this->_getEmailEvent($event);
if ( !is_object($object) ) {
// email event not found OR it's won't be send under given circumstances
return ;
}
// additional parameters from kApplication->EmailEvent
$send_params = $event->getEventParam('DirectSendParams');
// 1. get information about message sender and recipient
list ($from_email, $from_name) = $this->_processSender($event, $send_params);
list ($to_email, $to_name) = $this->_processRecipients($event, $send_params);
// 2. prepare message to be sent
$message_language = $this->_getSendLanguage($send_params);
$message_template = $this->_getMessageBody($event, $message_language);
if ( !trim($message_template) ) {
trigger_error('Message template is empty', E_USER_WARNING);
return ;
}
list ($message_headers, $message_body) = $this->ParseMessageBody($message_template, $send_params);
if ( !trim($message_body) ) {
trigger_error('Message template is empty after parsing', E_USER_WARNING);
return ;
}
// 3. set headers & send message
$esender =& $this->Application->recallObject('EmailSender');
/* @var $esender kEmailSendingHelper */
$message_subject = isset($message_headers['Subject']) ? $message_headers['Subject'] : 'Mail message';
$esender->SetSubject($message_subject);
if ( $this->Application->isDebugMode() ) {
// set special header with event name, so it will be easier to determine what's actually was received
$message_headers['X-Event-Name'] = $email_event_name . ' - ' . ($object->GetDBField('Type') == EmailEvent::EVENT_TYPE_ADMIN ? 'ADMIN' : 'USER');
}
foreach ($message_headers as $header_name => $header_value) {
$esender->SetEncodedHeader($header_name, $header_value);
}
$esender->CreateTextHtmlPart($message_body, $object->GetDBField('MessageType') == 'html');
$event->status = $esender->Deliver() ? kEvent::erSUCCESS : kEvent::erFAIL;
if ( $event->status == kEvent::erSUCCESS ) {
// all keys, that are not used in email sending are written to log record
$send_keys = Array ('from_email', 'from_name', 'to_email', 'to_name', 'message');
foreach ($send_keys as $send_key) {
unset($send_params[$send_key]);
}
$fields_hash = Array (
'fromuser' => $from_name . ' (' . $from_email . ')',
'addressto' => $to_name . ' (' . $to_email . ')',
'subject' => $message_subject,
'timestamp' => adodb_mktime(),
'event' => $email_event_name,
'EventParams' => serialize($send_params),
);
$this->Conn->doInsert($fields_hash, TABLE_PREFIX . 'EmailLog');
}
}
function _getSendLanguage($send_params)
{
if (array_key_exists('language_id', $send_params)) {
return $send_params['language_id'];
}
return $this->Application->GetVar('m_lang');
}
function _changeLanguage($language_id = null)
{
static $prev_language_id = null;
if ( !isset($language_id) ) {
// restore language
$language_id = $prev_language_id;
}
$this->Application->SetVar('m_lang', $language_id);
$language =& $this->Application->recallObject('lang.current');
/* @var $language LanguagesItem */
$language->Load($language_id);
$this->Application->Phrases->LanguageId = $language_id;
$this->Application->Phrases->Phrases = Array ();
$prev_language_id = $language_id; // for restoring it later
}
/**
* Process emails from queue
*
* @param kEvent $event
* @todo Move to MailingList
*/
function OnProcessEmailQueue(&$event)
{
$deliver_count = $event->getEventParam('deliver_count');
if ($deliver_count === false) {
$deliver_count = $this->Application->ConfigValue('MailingListSendPerStep');
if ($deliver_count === false) {
$deliver_count = 10; // 10 emails per script run (if not specified directly)
}
}
$processing_type = $this->Application->GetVar('type');
if ($processing_type = 'return_progress') {
$email_queue_progress = $this->Application->RecallVar('email_queue_progress');
if ($email_queue_progress === false) {
$emails_sent = 0;
$sql = 'SELECT COUNT(*)
FROM ' . TABLE_PREFIX . 'EmailQueue
WHERE (SendRetries < 5) AND (LastSendRetry < ' . strtotime('-2 hours') . ')';
$total_emails = $this->Conn->GetOne($sql);
$this->Application->StoreVar('email_queue_progress', $emails_sent.':'.$total_emails);
}
else {
list ($emails_sent, $total_emails) = explode(':', $email_queue_progress);
}
}
$sql = 'SELECT *
FROM '.TABLE_PREFIX.'EmailQueue
WHERE (SendRetries < 5) AND (LastSendRetry < ' . strtotime('-2 hours') . ')
LIMIT 0,' . $deliver_count;
$messages = $this->Conn->Query($sql);
$message_count = count($messages);
if (!$message_count) {
// no messages left to send in queue
if ($processing_type = 'return_progress') {
$this->Application->RemoveVar('email_queue_progress');
$this->Application->Redirect($this->Application->GetVar('finish_template'));
}
return ;
}
$mailing_list_helper =& $this->Application->recallObject('MailingListHelper');
/* @var $mailing_list_helper MailingListHelper */
$mailing_list_helper->processQueue($messages);
if ($processing_type = 'return_progress') {
$emails_sent += $message_count;
if ($emails_sent >= $total_emails) {
$this->Application->RemoveVar('email_queue_progress');
$this->Application->Redirect($this->Application->GetVar('finish_template'));
}
$this->Application->StoreVar('email_queue_progress', $emails_sent.':'.$total_emails);
$event->status = kEvent::erSTOP;
echo ($emails_sent / $total_emails) * 100;
}
}
/**
* Prefills module dropdown
*
* @param kEvent $event
*/
function OnAfterConfigRead(&$event)
{
parent::OnAfterConfigRead($event);
$options = Array ();
foreach ($this->Application->ModuleInfo as $module_name => $module_info) {
if ($module_name == 'In-Portal') {
continue;
}
$options[$module_name] = $module_name;
}
$fields = $this->Application->getUnitOption($event->Prefix, 'Fields');
$fields['Module']['options'] = $options;
$this->Application->setUnitOption($event->Prefix, 'Fields', $fields);
if ($this->Application->GetVar('regional')) {
$this->Application->setUnitOption($event->Prefix, 'PopulateMlFields', true);
}
}
/**
* Prepare temp tables and populate it
* with items selected in the grid
*
* @param kEvent $event
*/
function OnEdit(&$event)
{
parent::OnEdit($event);
// use language from grid, instead of primary language used by default
$event->SetRedirectParam('m_lang', $this->Application->GetVar('m_lang'));
}
/**
* Fixes default recipient type
*
* @param kEvent $event
* @return void
* @access protected
*/
protected function OnAfterItemLoad(&$event)
{
parent::OnAfterItemLoad($event);
$object =& $event->getObject();
/* @var $object kDBItem */
if (!$this->Application->isDebugMode(false)) {
if ($object->GetDBField('AllowChangingRecipient')) {
$object->SetDBField('RecipientType', EmailEvent::RECIPIENT_TYPE_TO);
}
else {
$object->SetDBField('RecipientType', EmailEvent::RECIPIENT_TYPE_CC);
}
}
// process replacement tags
$records = Array ();
$replacement_tags = $object->GetDBField('ReplacementTags');
$replacement_tags = $replacement_tags ? unserialize($replacement_tags) : Array ();
foreach ($replacement_tags as $tag => $replacement) {
$records[] = Array ('Tag' => $tag, 'Replacement' => $replacement);
}
$minput_helper =& $this->Application->recallObject('MInputHelper');
/* @var $minput_helper MInputHelper */
$xml = $minput_helper->prepareMInputXML($records, Array ('Tag', 'Replacement'));
$object->SetDBField('ReplacementTagsXML', $xml);
}
/**
* Performs custom validation + keep read-only fields
*
* @param kEvent $event
*/
function _itemChanged(&$event)
{
$object =& $event->getObject();
/* @var $object kDBItem */
// validate email subject and body for parsing errors
$this->_validateEmailTemplate($object);
// validate sender and recipient addresses
if ($object->GetDBField('CustomSender')) {
$this->_validateAddress($event, 'Sender');
}
$this->_validateAddress($event, 'Recipient');
if (!$this->Application->isDebugMode(false)) {
// only allow to enable/disable event while in debug mode
$to_restore = Array ('Enabled', 'AllowChangingSender', 'AllowChangingRecipient');
if (!$object->GetOriginalField('AllowChangingSender')) {
$to_restore = array_merge($to_restore, Array ('CustomSender', 'SenderName', 'SenderAddressType', 'SenderAddress'));
}
if (!$object->GetOriginalField('AllowChangingRecipient')) {
$to_restore = array_merge($to_restore, Array ('CustomRecipient'/*, 'Recipients'*/));
}
// prevent specific fields from editing
foreach ($to_restore as $restore_field) {
$original_value = $object->GetOriginalField($restore_field);
if ($object->GetDBField($restore_field) != $original_value) {
$object->SetDBField($restore_field, $original_value);
}
}
}
// process replacement tags
if ( $object->GetDBField('ReplacementTagsXML') ) {
$minput_helper =& $this->Application->recallObject('MInputHelper');
/* @var $minput_helper MInputHelper */
$replacement_tags = Array ();
$records = $minput_helper->parseMInputXML( $object->GetDBField('ReplacementTagsXML') );
foreach ($records as $record) {
$replacement_tags[ trim($record['Tag']) ] = trim($record['Replacement']);
}
$object->SetDBField('ReplacementTags', $replacement_tags ? serialize($replacement_tags) : NULL);
}
}
/**
* Validates address using given field prefix
*
* @param kEvent $event
* @param string $field_prefix
*/
function _validateAddress(&$event, $field_prefix)
{
$object =& $event->getObject();
/* @var $object kDBItem */
$address_type = $object->GetDBField($field_prefix . 'AddressType');
$object->setRequired($field_prefix . 'Address', $address_type > 0);
$address = $object->GetDBField($field_prefix . 'Address');
if (!$address) {
// don't validate against empty address
return ;
}
switch ($address_type) {
case EmailEvent::ADDRESS_TYPE_EMAIL:
if (!preg_match('/^(' . REGEX_EMAIL_USER . '@' . REGEX_EMAIL_DOMAIN . ')$/i', $address)) {
$object->SetError($field_prefix . 'Address', 'invalid_email');
}
break;
case EmailEvent::ADDRESS_TYPE_USER:
$sql = 'SELECT PortalUserId
FROM ' . TABLE_PREFIX . 'PortalUser
WHERE Login = ' . $this->Conn->qstr($address);
if (!$this->Conn->GetOne($sql)) {
$object->SetError($field_prefix . 'Address', 'invalid_user');
}
break;
case EmailEvent::ADDRESS_TYPE_GROUP:
$sql = 'SELECT GroupId
FROM ' . TABLE_PREFIX . 'PortalGroup
WHERE Name = ' . $this->Conn->qstr($address);
if (!$this->Conn->GetOne($sql)) {
$object->SetError($field_prefix . 'Address', 'invalid_group');
}
break;
}
}
/**
* Don't allow to enable/disable events in non-debug mode
*
* @param kEvent $event
* @return void
* @access protected
*/
protected function OnBeforeItemCreate(&$event)
{
parent::OnBeforeItemCreate($event);
$this->_itemChanged($event);
}
/**
* Don't allow to enable/disable events in non-debug mode
*
* @param kEvent $event
* @return void
* @access protected
*/
protected function OnBeforeItemUpdate(&$event)
{
parent::OnBeforeItemUpdate($event);
$this->_itemChanged($event);
}
/**
* Suggest address based on typed address and selected address type
*
* @param kEvent $event
*/
function OnSuggestAddress(&$event)
{
$event->status = kEvent::erSTOP;
$address_type = $this->Application->GetVar('type');
$address = $this->Application->GetVar('value');
$limit = $this->Application->GetVar('limit');
if (!$limit) {
$limit = 20;
}
switch ($address_type) {
case EmailEvent::ADDRESS_TYPE_EMAIL:
$field = 'Email';
$table_name = TABLE_PREFIX . 'PortalUser';
break;
case EmailEvent::ADDRESS_TYPE_USER:
$field = 'Login';
$table_name = TABLE_PREFIX . 'PortalUser';
break;
case EmailEvent::ADDRESS_TYPE_GROUP:
$field = 'Name';
$table_name = TABLE_PREFIX . 'PortalGroup';
break;
}
if (isset($field)) {
$sql = 'SELECT DISTINCT ' . $field . '
FROM ' . $table_name . '
WHERE ' . $field . ' LIKE ' . $this->Conn->qstr($address . '%') . '
ORDER BY ' . $field . ' ASC
LIMIT 0,' . $limit;
$data = $this->Conn->GetCol($sql);
}
else {
$data = Array ();
}
$this->Application->XMLHeader();
echo '<suggestions>';
foreach ($data as $item) {
echo '<item>' . htmlspecialchars($item) . '</item>';
}
echo '</suggestions>';
}
/**
* Validates subject and body fields of Email template
* @param kDBItem $object
*/
function _validateEmailTemplate(&$object)
{
$this->parseField($object, 'Subject');
$this->parseField($object, 'Body');
}
/**
* Parses contents of given object field and sets error, when invalid in-portal tags found
* @param kDBItem $object
* @param string $field
* @return void
*/
function parseField(&$object, $field)
{
$this->Application->InitParser();
-
+
try {
$this->Application->Parser->CompileRaw($object->GetField($field), 'email_template');
}
catch (ParserException $e) {
if ( $this->Application->isDebugMode() ) {
$this->Application->Debugger->appendHTML('<b style="color: red;">Error in Email Template:</b> ' . $e->getMessage() . ' (line: ' . $e->getLine() . ')');
}
$object->SetError($field, 'parsing_error');
}
}
}
\ No newline at end of file

Event Timeline