Page MenuHomeIn-Portal Phabricator

in-portal
No OneTemporary

File Metadata

Created
Wed, Jun 18, 8:51 AM

in-portal

This file is larger than 256 KB, so syntax highlighting was skipped.
Index: branches/5.2.x/core/kernel/session/session.php
===================================================================
--- branches/5.2.x/core/kernel/session/session.php (revision 15129)
+++ branches/5.2.x/core/kernel/session/session.php (revision 15130)
@@ -1,1101 +1,1100 @@
<?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!');
/*
The session works the following way:
1. When a visitor loads a page from the site the script checks if cookies_on varibale has been passed to it as a cookie.
2. If it has been passed, the script tries to get Session ID (SID) from the request:
3. Depending on session mode the script is getting SID differently.
The following modes are available:
- Session::smAUTO
Automatic mode: if cookies are on at the client side, the script relays only on cookies and
ignore all other methods of passing SID. If cookies are off at the client side, the script relays on SID
passed through query string and referal passed by the client. THIS METHOD IS NOT 100% SECURE, as long as
attacker may get SID and substitude referal to gain access to user' session. One of the faults of this method
is that the session is only created when the visitor clicks the first link on the site, so there
is NO session at the first load of the page. (Actually there is a session, but it gets lost after
the first click because we do not use SID in query string while we are not sure if we need it)
- Session::smCOOKIES_ONLY
Cookies only: in this mode the script relays solely on cookies passed from the browser and ignores
all other methods. In this mode there is no way to use sessions for clients without cookies support
or cookies support disabled. The cookies are stored with the full domain name and path to base-directory
of script installation.
- Session::smGET_ONLY
GET only: the script will not set any cookies and will use only SID passed in query string using GET,
it will also check referal. The script will set SID at the first load of the page
- Session::smCOOKIES_AND_GET
Combined mode: the script will use both cookies and GET right from the start. If client has cookies enabled,
the script will check SID stored in cookie and passed in query string, and will use this SID only if both
cookie and query string matches. However if cookies are disabled on the client side, the script will work
the same way as in GET_ONLY mode.
4. After the script has the SID it tries to load it from the Storage (default is database)
5. If such SID is found in the database, the script checks its expiration time. If session is not expired,
it updates its expiration, and resend the cookie (if applicable to session mode)
6. Then the script loads all the data (session variables) pertaining to the SID.
Usage:
$session = new Session(Session::smAUTO); //Session::smAUTO is default, you could just leave the brackets empty, or provide another mode
$session->SetCookieDomain('my.domain.com');
$session->SetCookiePath('/myscript');
$session->SetCookieName('my_sid_cookie');
$session->SetGETName('sid');
$session->InitSession();
...
//link output:
echo "<a href='index.php?'". ( $session->NeedQueryString() ? 'sid='.$session->SID : '' ) .">My Link</a>";
*/
class Session extends kBase {
const smAUTO = 1;
const smCOOKIES_ONLY = 2;
const smGET_ONLY = 3;
const smCOOKIES_AND_GET = 4;
var $Checkers;
var $Mode;
var $OriginalMode = null;
var $GETName = 'sid';
var $CookiesEnabled = true;
var $CookieName = 'sid';
var $CookieDomain;
var $CookiePath;
var $CookieSecure = 0;
var $SessionTimeout = 3600;
var $Expiration;
var $SID;
var $CachedSID;
var $SessionSet = false;
/**
* Session ID is used from GET
*
* @var bool
*/
var $_fromGet = false;
/**
* Enter description here...
*
* @var SessionStorage
* @access protected
*/
protected $Storage;
var $CachedNeedQueryString = null;
/**
* Session Data array
*
* @var Params
*/
var $Data;
/**
* Names of optional session keys with their optional values (which does not need to be always stored)
*
* @var Array
*/
var $OptionalData = Array ();
/**
* Session expiration mark
*
* @var bool
*/
var $expired = false;
/**
* Creates session
*
* @param int $mode
* @access public
*/
public function __construct($mode = self::smAUTO)
{
parent::__construct();
$this->SetMode($mode);
}
function SetMode($mode)
{
$this->Mode = $mode;
$this->CachedNeedQueryString = null;
$this->CachedSID = null;
}
function SetCookiePath($path)
{
$this->CookiePath = str_replace(' ', '%20', $path);
}
/**
* Setting cookie domain. Set false for local domains, because they don't contain dots in their names.
*
* @param string $domain
*/
function SetCookieDomain($domain)
{
// 1. localhost or other like it without "." in domain name
if (!substr_count($domain, '.')) {
// don't use cookie domain at all
$this->CookieDomain = false;
return ;
}
// 2. match using predefined cookie domains from configuration
$cookie_domains = $this->Application->ConfigValue('SessionCookieDomains');
if ($cookie_domains) {
$cookie_domains = array_map('trim', explode("\n", $cookie_domains));
foreach ($cookie_domains as $cookie_domain) {
if (ltrim($cookie_domain, '.') == $domain) {
$this->CookieDomain = $cookie_domain; // as defined in configuration
return ;
}
}
}
// 3. only will execute, when none of domains were matched at previous step
$this->CookieDomain = $this->_autoGuessDomain($domain);
}
/**
* Auto-guess cookie domain based on $_SERVER['HTTP_HOST']
*
* @param $domain
* @return string
*/
function _autoGuessDomain($domain)
{
static $cache = Array ();
if (!array_key_exists($domain, $cache)) {
switch ( substr_count($domain, '.') ) {
case 2:
// 3rd level domain (3 parts)
$cache[$domain] = substr($domain, strpos($domain, '.')); // with leading "."
break;
case 1:
// 2rd level domain (2 parts)
$cache[$domain] = '.' . $domain; // with leading "."
break;
default:
// more then 3rd level
$cache[$domain] = ltrim($domain, '.'); // without leading "."
break;
}
}
return $cache[$domain];
}
function SetGETName($get_name)
{
$this->GETName = $get_name;
}
function SetCookieName($cookie_name)
{
$this->CookieName = $cookie_name;
}
function InitStorage($special)
{
$this->Storage =& $this->Application->recallObject('SessionStorage.'.$special);
$this->Storage->setSession($this);
}
public function Init($prefix, $special)
{
parent::Init($prefix, $special);
$this->CheckIfCookiesAreOn();
if ($this->CookiesEnabled) $_COOKIE['cookies_on'] = 1;
$this->Checkers = Array();
$this->InitStorage($special);
$this->Data = new Params();
$tmp_sid = $this->GetPassedSIDValue();
$check = $this->Check();
if ($this->Application->isAdmin) {
// 1. Front-End session may not be created (SID is present, but no data in database).
// Check expiration LATER from kApplication::Init, because template, used in session
// expiration redirect should be retrieved from mod-rewrite url first.
// 2. Admin sessions are always created, so case when SID is present,
// but session in database isn't is 100% session expired. Check expiration
// HERE because Session::SetSession will create missing session in database
// and when Session::ValidateExpired will be called later from kApplication::Init
// it won't consider such session as expired !!!
$this->ValidateExpired();
}
if ($check) {
$this->SID = $this->GetPassedSIDValue();
$this->Refresh();
$this->LoadData();
}
else {
$this->SetSession();
}
if (!is_null($this->OriginalMode)) $this->SetMode($this->OriginalMode);
}
function ValidateExpired()
{
if (defined('IS_INSTALL') && IS_INSTALL) {
return ;
}
// $this->DeleteExpired(); // called from u:OnDeleteExpiredSessions scheduled task now
if ($this->expired || ($this->CachedSID && !$this->_fromGet && !$this->SessionSet)) {
$this->RemoveSessionCookie();
// true was here to force new session creation, but I (kostja) used
// RemoveCookie a line above, to avoid redirect loop with expired sid
// not being removed setSession with true was used before, to set NEW
// session cookie
$this->SetSession();
// case #1: I've OR other site visitor expired my session
// case #2: I have no session in database, but SID is present
$this->expired = false;
- $expire_event = new kEvent('u:OnSessionExpire');
- $this->Application->HandleEvent($expire_event);
+ $this->Application->HandleEvent(new kEvent('u:OnSessionExpire'));
}
}
/**
* Helper method for detecting cookie availability
*
* @return bool
*/
function _checkCookieReferer()
{
// removing /admin for compatability with in-portal (in-link/admin/add_link.php)
$path = preg_replace('/admin[\/]{0,1}$/', '', $this->CookiePath);
$reg = '#^'.preg_quote(PROTOCOL.ltrim($this->CookieDomain, '.').$path).'#';
return preg_match($reg, getArrayValue($_SERVER, 'HTTP_REFERER') );
}
function CheckIfCookiesAreOn()
{
if ( $this->Mode == self::smGET_ONLY ) {
//we don't need to bother checking if we would not use it
$this->CookiesEnabled = false;
return false;
}
$http_query =& $this->Application->recallObject('HTTPQuery');
/* @var $http_query kHTTPQuery */
$cookies_on = array_key_exists('cookies_on', $http_query->Cookie); // not good here
$get_sid = getArrayValue($http_query->Get, $this->GETName);
if ( ($this->Application->HttpQuery->IsHTTPSRedirect() && $get_sid) || $this->getFlashSID() ) { // Redirect from http to https on different domain OR flash uploader
$this->OriginalMode = $this->Mode;
$this->SetMode(self::smGET_ONLY);
}
if ( !$cookies_on || $this->Application->HttpQuery->IsHTTPSRedirect() || $this->getFlashSID() ) {
//If referer is our server, but we don't have our cookies_on, it's definetly off
$is_install = defined('IS_INSTALL') && IS_INSTALL;
if ( !$is_install && $this->_checkCookieReferer() && !$this->Application->GetVar('admin') && !$this->Application->HttpQuery->IsHTTPSRedirect() ) {
$this->CookiesEnabled = false;
}
else {
//Otherwise we still suppose cookies are on, because may be it's the first time user visits the site
//So we send cookies on to get it next time (when referal will tell us if they are realy off
$this->SetCookie('cookies_on', 1, adodb_mktime() + 31104000); //one year should be enough
}
}
else {
$this->CookiesEnabled = true;
}
return $this->CookiesEnabled;
}
/**
* Sets cookie for current site using path and domain
*
* @param string $name
* @param mixed $value
* @param int $expires
*/
function SetCookie($name, $value, $expires = null)
{
if (isset($expires) && $expires < adodb_mktime()) {
unset($this->Application->HttpQuery->Cookie[$name]);
}
else {
$this->Application->HttpQuery->Cookie[$name] = $value;
}
$old_style_domains = Array (
// domain like in pre 5.1.0 versions
'.' . SERVER_NAME,
// auto-guessed domain (when user specified other domain in configuration variable)
$this->_autoGuessDomain(SERVER_NAME)
);
foreach ($old_style_domains as $old_style_domain) {
if ($this->CookieDomain != $old_style_domain) {
// new style cookie domain -> delete old style cookie to prevent infinite redirect
setcookie($name, $value, adodb_mktime() - 3600, $this->CookiePath, $old_style_domain, $this->CookieSecure);
}
}
setcookie($name, $value, $expires, $this->CookiePath, $this->CookieDomain, $this->CookieSecure);
}
function Check()
{
// don't check referer here, because it doesn't provide any security option and can be easily falsified
$sid = $this->GetPassedSIDValue();
if (empty($sid)) {
return false;
}
//try to load session by sid, if everything is fine
$result = $this->LoadSession($sid);
$this->SessionSet = $result; // fake front-end session will given "false" here
return $result;
}
function LoadSession($sid)
{
if( $this->Storage->LocateSession($sid) ) {
// if we have session with such SID - get its expiration
$this->Expiration = $this->Storage->GetExpiration();
// If session has expired
if ($this->Expiration < adodb_mktime()) {
// when expired session is loaded, then SID is
// not assigned, but used in Destroy method
$this->SID = $sid;
$this->Destroy();
$this->expired = true;
// when Destory methods calls SetSession inside and new session get created
return $this->SessionSet;
}
// Otherwise it's ok
return true;
}
else {
// fake or deleted due to expiration SID
if (!$this->_fromGet) {
$this->expired = true;
}
return false;
}
}
function getFlashSID()
{
$http_query =& $this->Application->recallObject('HTTPQuery');
/* @var $http_query kHTTPQuery */
return getArrayValue($http_query->Post, 'flashsid');
}
function GetPassedSIDValue($use_cache = 1)
{
if (!empty($this->CachedSID) && $use_cache) {
return $this->CachedSID;
}
// flash sid overrides regular sid
$get_sid = $this->getFlashSID();
if (!$get_sid) {
$http_query =& $this->Application->recallObject('HTTPQuery');
/* @var $http_query kHTTPQuery */
$get_sid = getArrayValue($http_query->Get, $this->GETName);
}
$sid_from_get = $get_sid ? true : false;
if ($this->Application->GetVar('admin') == 1 && $get_sid) {
$sid = $get_sid;
}
else {
switch ($this->Mode) {
case self::smAUTO:
//Cookies has the priority - we ignore everything else
$sid = $this->CookiesEnabled ? $this->GetSessionCookie() : $get_sid;
if ($this->CookiesEnabled) {
$sid_from_get = false;
}
break;
case self::smCOOKIES_ONLY:
$sid = $this->GetSessionCookie();
break;
case self::smGET_ONLY:
$sid = $get_sid;
break;
case self::smCOOKIES_AND_GET:
$cookie_sid = $this->GetSessionCookie();
//both sids should match if cookies are enabled
if (!$this->CookiesEnabled || ($cookie_sid == $get_sid)) {
$sid = $get_sid; //we use get here just in case cookies are disabled
}
else {
$sid = '';
$sid_from_get = false;
}
break;
}
}
$this->CachedSID = $sid;
$this->_fromGet = $sid_from_get;
return $this->CachedSID;
}
/**
* Returns session id
*
* @return int
* @access public
*/
function GetID()
{
return $this->SID;
}
/**
* Generates new session id
*
* @return int
* @access private
*/
function GenerateSID()
{
list ($usec, $sec) = explode(' ', microtime());
$sid_part_1 = substr($usec, 4, 4);
$sid_part_2 = mt_rand(1, 9);
$sid_part_3 = substr($sec, 6, 4);
$digit_one = substr($sid_part_1, 0, 1);
if ($digit_one == 0) {
$digit_one = mt_rand(1, 9);
$sid_part_1 = preg_replace('/^0/', '', $sid_part_1);
$sid_part_1 = $digit_one . $sid_part_1;
}
$this->setSID($sid_part_1 . $sid_part_2 . $sid_part_3);
return $this->SID;
}
/**
* Set's new session id
*
* @param int $new_sid
* @access private
*/
function setSID($new_sid)
{
$this->SID /*= $this->CachedSID*/ = $new_sid; // don't set cached sid here
$this->Application->SetVar($this->GETName,$new_sid);
}
function NeedSession()
{
$data = $this->Data->GetParams();
$data_keys = array_keys($data);
$optional_keys = array_keys($this->OptionalData);
$real_keys = array_diff($data_keys, $optional_keys);
return $real_keys ? true : false;
}
function SetSession($force = false)
{
if ( $this->SessionSet && !$force ) {
return true;
}
$this->Expiration = adodb_mktime() + $this->SessionTimeout;
if ( !$force && /*!$this->Application->isAdmin &&*/ !$this->Application->GetVar('admin') && !$this->NeedSession() ) {
// don't create session (in db) on Front-End, when sid is present (GPC), but data in db isn't
if ( $this->_fromGet ) {
// set sid, that was given in GET
$this->setSID($this->GetPassedSIDValue());
}
else {
// re-generate sid only, when cookies are used
$this->GenerateSID();
}
$this->Storage->StoreSession(false);
return false;
}
if ( !$this->SID || $force ) {
$this->GenerateSID();
}
switch ( $this->Mode ) {
case self::smAUTO:
if ( $this->CookiesEnabled ) {
$this->SetSessionCookie();
}
break;
case self::smGET_ONLY:
break;
case self::smCOOKIES_ONLY:
case self::smCOOKIES_AND_GET:
$this->SetSessionCookie();
break;
}
$this->Storage->StoreSession();
if ( $this->Application->isAdmin || $this->Special == 'admin' ) {
$this->StoreVar('admin', 1);
}
$this->SessionSet = true; // should be called before SaveData, because SaveData will try to SetSession again
if ( $this->Special != '' ) {
// front-session called from admin or otherwise, then save it's data
$this->SaveData();
}
$this->Application->resetCounters('UserSessions');
return true;
}
/**
* Returns SID from cookie.
*
* Use 2 cookies to have 2 expiration:
* - 1. for normal expiration when browser is not closed (30 minutes by default), configurable
* - 2. for advanced expiration when browser is closed
*
* @return int
*/
function GetSessionCookie()
{
$keep_session_on_browser_close = $this->Application->ConfigValue('KeepSessionOnBrowserClose');
if (isset($this->Application->HttpQuery->Cookie[$this->CookieName]) &&
( $keep_session_on_browser_close ||
(
!$keep_session_on_browser_close &&
isset($this->Application->HttpQuery->Cookie[$this->CookieName.'_live'])
&&
$this->Application->HttpQuery->Cookie[$this->CookieName] == $this->Application->HttpQuery->Cookie[$this->CookieName.'_live']
)
)
) {
return $this->Application->HttpQuery->Cookie[$this->CookieName];
}
return false;
}
/**
* Updates SID in cookie with new value
*
*/
function SetSessionCookie()
{
$this->SetCookie($this->CookieName, $this->SID, $this->Expiration);
$this->SetCookie($this->CookieName.'_live', $this->SID);
$_COOKIE[$this->CookieName] = $this->SID; // for compatibility with in-portal
}
function RemoveSessionCookie()
{
$this->SetCookie($this->CookieName, '');
$this->SetCookie($this->CookieName.'_live', '');
$_COOKIE[$this->CookieName] = null; // for compatibility with in-portal
}
/**
* Refreshes session expiration time
*
* @access private
*/
function Refresh()
{
if ($this->Application->GetVar('skip_session_refresh')) {
return ;
}
if ($this->CookiesEnabled) {
// we need to refresh the cookie
$this->SetSessionCookie();
}
$this->Storage->UpdateSession();
}
function Destroy()
{
$this->Storage->DeleteSession();
$this->Data = new Params();
$this->SID = $this->CachedSID = '';
$this->SessionSet = false;
if ($this->CookiesEnabled) {
$this->SetSessionCookie(); //will remove the cookie due to value (sid) is empty
}
$this->SetSession(true); //will create a new session, true to force
}
function NeedQueryString($use_cache = 1)
{
if ($this->CachedNeedQueryString != null && $use_cache) {
return $this->CachedNeedQueryString;
}
$result = false;
switch ($this->Mode) {
case self::smAUTO:
if (!$this->CookiesEnabled) {
$result = true;
}
break;
/*case self::smCOOKIES_ONLY:
break;*/
case self::smGET_ONLY:
case self::smCOOKIES_AND_GET:
$result = true;
break;
}
$this->CachedNeedQueryString = $result;
return $result;
}
function LoadData()
{
$this->Data->AddParams( $this->Storage->LoadData() );
}
function PrintSession($comment = '')
{
if (defined('DEBUG_MODE') && $this->Application->isDebugMode() && kUtil::constOn('DBG_SHOW_SESSIONDATA')) {
// dump session data
$this->Application->Debugger->appendHTML('SessionStorage [' . ($this->RecallVar('admin') == 1 ? 'Admin' : 'Front-End') . '] ('.$comment.'):');
$session_data = $this->Data->GetParams();
ksort($session_data);
foreach ($session_data as $session_key => $session_value) {
if (kUtil::IsSerialized($session_value)) {
$session_data[$session_key] = unserialize($session_value);
}
}
$this->Application->Debugger->dumpVars($session_data);
if (!$this->RecallVar('admin')) {
// dump real keys (only for front-end)
$data_keys = array_keys($session_data);
$optional_keys = array_keys($this->OptionalData);
$real_keys = array_diff($data_keys, $optional_keys);
if ($real_keys) {
$ret = '';
foreach ($real_keys as $real_key) {
$ret .= '[' . $real_key . '] = [' . $session_data[$real_key] . ']<br/>';
}
$this->Application->Debugger->appendHTML('Real Keys:<br/> ' . $ret);
}
}
}
if (defined('DEBUG_MODE') && $this->Application->isDebugMode() && kUtil::constOn('DBG_SHOW_PERSISTENTDATA')) {
// dump persistent session data
if ($this->Storage->PersistentVars) {
$this->Application->Debugger->appendHTML('Persistant Session:');
$session_data = $this->Storage->PersistentVars;
ksort($session_data);
foreach ($session_data as $session_key => $session_value) {
if (kUtil::IsSerialized($session_value)) {
$session_data[$session_key] = unserialize($session_value);
}
}
$this->Application->Debugger->dumpVars($session_data);
}
}
}
function SaveData($params = Array ())
{
if (!$this->SetSession()) { // call it here - it may be not set before, because there was no need; if there is a need, it will be set here
return;
}
if (!$this->Application->GetVar('skip_last_template') && $this->Application->GetVar('ajax') != 'yes') {
$this->SaveLastTemplate( $this->Application->GetVar('t'), $params );
}
$this->PrintSession('after save');
$this->Storage->SaveData();
}
/**
* Save last template
*
* @param string $t
* @param Array $params
*/
function SaveLastTemplate($t, $params = Array ())
{
$wid = $this->Application->GetVar('m_wid');
$last_env = $this->getLastTemplateENV($t, Array ('m_opener' => 'u'));
$last_template = basename($_SERVER['PHP_SELF']) . '|' . $last_env;
$this->StoreVar(rtrim('last_template_' . $wid, '_'), $last_template);
// prepare last_template for opener stack, module & session could be added later
$last_env = $this->getLastTemplateENV($t, null, false);
$last_template = basename($_SERVER['PHP_SELF']) . '|' . $last_env;
// save last_template in persistent session
if (!$wid) {
if ($this->Application->isAdmin) {
// only for main window, not popups, not login template, not temp mode (used in adm:MainFrameLink tag)
$temp_mode = false;
$passed = explode(',', $this->Application->GetVar('passed'));
foreach ($passed as $passed_prefix) {
if ($this->Application->GetVar($passed_prefix.'_mode')) {
$temp_mode = true;
break;
}
}
if (!$temp_mode) {
if ( $this->Application->GetVarDirect('section', 'Get') !== false ) {
// check directly in GET, because LinkVar (session -> request) used on these vars
$last_template .= '&section='.$this->Application->GetVar('section').'&module='.$this->Application->GetVar('module');
}
$this->StorePersistentVar('last_template_popup', $last_template);
}
}
elseif ($this->Application->GetVar('admin')) {
// admin checking by session data to prevent recursive session save
static $admin_saved = null;
if (!$this->RecallVar('admin') && !isset($admin_saved)) {
// bug: we get recursion in this place, when cookies are disabled in browser and we are browsing
// front-end in admin's frame (front-end session is initialized using admin's sid and they are
// mixed together)
$admin_saved = true;
$admin_session =& $this->Application->recallObject('Session.admin');
/* @var $admin_session Session */
// save to admin last_template too, because when F5 is pressed in frameset Front-End frame should reload as well
$admin_session->StoreVar('last_template_popup', '../' . $last_template);
$admin_session->StorePersistentVar('last_template_popup', '../' . $last_template);
$admin_session->SaveData( Array ('save_last_template' => false) );
}
else {
// don't allow admin=1 & editing_mode=* to get in admin last_template
$last_template = preg_replace('/&(admin|editing_mode)=[\d]/', '', $last_template);
}
}
}
// save other last... variables for mystical purposes (customizations may be)
$this->StoreVar('last_url', $_SERVER['REQUEST_URI']); // needed by ord:StoreContinueShoppingLink
$this->StoreVar('last_env', $last_env);
$save_last_template = array_key_exists('save_last_template', $params) ? $params['save_last_template'] : true;
if ($save_last_template) {
// save last template here, because section & module could be added before
$this->StoreVar(rtrim('last_template_popup_'.$wid, '_'), $last_template);
}
}
function getLastTemplateENV($t, $params = null, $encode = true)
{
if (!isset($params)) {
$params = Array ();
}
$params['__URLENCODE__'] = 1; // uses "&" instead of "&amp;" for url part concatenation + replaces "\" to "%5C" (works in HTML)
if ($this->Application->GetVar('admin') && !array_key_exists('admin', $params) && !defined('EDITING_MODE')) {
$params['editing_mode'] = ''; // used in kApplication::Run
}
$params = array_merge($this->Application->getPassThroughVariables($params), $params);
$ret = $this->Application->BuildEnv($t, $params, 'all', false, false);
if (!$encode) {
// cancels 2nd part of replacements, that URLENCODE does
$ret = str_replace('%5C', '\\', $ret);
}
return $ret;
}
/**
* Stores variable $val in session under name $var
*
* Use this method to store variable in session. Later this variable could be recalled.
*
* @param string $name Variable name
* @param mixed $value Variable value
* @param bool $optional
* @return void
* @access public
* @see Session::RecallVar()
*/
public function StoreVar($name, $value, $optional = false)
{
$this->Data->Set($name, $value);
if ( $optional ) {
// make variable optional, also remember optional value
$this->OptionalData[$name] = $value;
}
elseif ( !$optional && array_key_exists($name, $this->OptionalData) ) {
if ( $this->OptionalData[$name] == $value ) {
// same value as optional -> don't remove optional mark
return;
}
// make variable non-optional
unset($this->OptionalData[$name]);
}
}
/**
* Stores variable to persistent session
*
* @param string $name
* @param mixed $value
* @param bool $optional
* @return void
* @access public
*/
public function StorePersistentVar($name, $value, $optional = false)
{
$this->Storage->StorePersistentVar($name, $value, $optional);
}
function LoadPersistentVars()
{
$this->Storage->LoadPersistentVars();
}
/**
* Stores default value for session variable
*
* @param string $name
* @param string $value
* @param bool $optional
* @return void
* @access public
* @see Session::RecallVar()
* @see Session::StoreVar()
*/
public function StoreVarDefault($name, $value, $optional = false)
{
$tmp = $this->RecallVar($name);
if ( $tmp === false || $tmp == '' ) {
$this->StoreVar($name, $value, $optional);
}
}
/**
* Returns session variable value
*
* Return value of $var variable stored in Session. An optional default value could be passed as second parameter.
*
* @param string $name Variable name
* @param mixed $default Default value to return if no $var variable found in session
* @return mixed
* @access public
*/
public function RecallVar($name, $default = false)
{
$ret = $this->Data->Get($name);
return ($ret === false) ? $default : $ret;
}
/**
* Returns variable value from persistent session
*
* @param string $name
* @param mixed $default
* @return mixed
* @access public
*/
public function RecallPersistentVar($name, $default = false)
{
return $this->Storage->RecallPersistentVar($name, $default);
}
/**
* Deletes Session variable
*
* @param string $var
* @return void
* @access public
*/
public function RemoveVar($name)
{
$this->Storage->RemoveFromData($name);
$this->Data->Remove($name);
}
/**
* Removes variable from persistent session
*
* @param string $name
* @return void
* @access public
*/
public function RemovePersistentVar($name)
{
$this->Storage->RemovePersistentVar($name);
}
/**
* Ignores session variable value set before
*
* @param string $name
* @return void
* @access public
*/
public function RestoreVar($name)
{
$value = $this->Storage->GetFromData($name, '__missing__');
if ( $value === '__missing__' ) {
// there is nothing to restore (maybe session was not saved), look in optional variable values
$value = array_key_exists($name, $this->OptionalData) ? $this->OptionalData[$name] : false;
}
$this->StoreVar($name, $value);
}
function GetField($var_name, $default = false)
{
return $this->Storage->GetField($var_name, $default);
}
function SetField($var_name, $value)
{
$this->Storage->SetField($var_name, $value);
}
/**
* Deletes expired sessions
*
* @return Array expired sids if any
* @access private
*/
function DeleteExpired()
{
return $this->Storage->DeleteExpired();
}
/**
* Deletes given sessions
*
* @param $session_ids
* @param int $delete_reason
* @return void
*/
function DeleteSessions($session_ids, $delete_reason = SESSION_LOG_EXPIRED)
{
$this->Storage->DeleteSessions($session_ids, $delete_reason);
}
/**
* Allows to check if user in this session is logged in or not
*
* @return bool
*/
function LoggedIn()
{
$user_id = $this->RecallVar('user_id');
$ret = $user_id > 0;
if (($this->RecallVar('admin') == 1 || defined('ADMIN')) && ($user_id == USER_ROOT)) {
$ret = true;
}
return $ret;
}
}
\ No newline at end of file
Index: branches/5.2.x/core/kernel/db/dblist.php
===================================================================
--- branches/5.2.x/core/kernel/db/dblist.php (revision 15129)
+++ branches/5.2.x/core/kernel/db/dblist.php (revision 15130)
@@ -1,1688 +1,1687 @@
<?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!');
/**
* DBList
*
*/
class kDBList extends kDBBase {
// kDBList filter types (then, types are divided into classes)
/**
* Having filter [step1]
*
*/
const HAVING_FILTER = 1;
/**
* Where filter [step1]
*
*/
const WHERE_FILTER = 2;
/**
* Aggregated filter [step1]
*
*/
const AGGREGATE_FILTER = 3;
/**
* System filter [step2, AND]
*
*/
const FLT_SYSTEM = 1;
/**
* User filter [step2, OR]
* @deprecated
*
*/
const FLT_NORMAL = 2;
/**
* User "Search" filter [step2, OR]
*
*/
const FLT_SEARCH = 3;
/**
* User "View Menu" filter [step2, AND]
*
*/
const FLT_VIEW = 4;
/**
* User "Custom" (above grid columns) filter [step2, AND]
*
*/
const FLT_CUSTOM = 5;
/**
* kMultipleFilter AND filter [step3]
*
*/
const FLT_TYPE_AND = 'AND';
/**
* kMultipleFilter OR filter [step3]
*
*/
const FLT_TYPE_OR = 'OR';
/**
* Totals for fields specified in config
*
* @var Array
* @access protected
*/
protected $Totals = Array ();
/**
* Remembers if totals were calculated
*
* @var bool
* @access protected
*/
protected $TotalsCalculated = false;
/**
* List of "ORDER BY" fields
*
* @var Array
* @access protected
*/
protected $OrderFields = Array ();
/**
* Counted total number of records in the query - without pagination (system+user filters)
*
* @var int
* @access protected
*/
protected $RecordsCount = 0;
/**
* Record count with only system filters applied
*
* @var int
* @access protected
*/
protected $NoFilterCount = 0;
/**
* Record count selected to be showed on current page
*
* @var int
* @access protected
*/
protected $SelectedCount = 0;
/**
* Array of selected records
*
* @var Array
* @access public
*/
public $Records;
/**
* Current record index
*
* @var int
* @access protected
*/
protected $CurrentIndex = 0;
/**
* List items per-page
*
* @var int
* @access protected
*/
protected $PerPage;
/**
* Page count in list based on PerPage & RecordsCount attributes
*
* @var int
* @access protected
*/
protected $TotalPages;
/**
* Current page number - used when forming LIMIT clause of SELECT statement
*
* @var int
* @access protected
*/
protected $Page;
/**
* Offset for LIMIT clause, calculated in {@link kDBList::PerPage()}
*
* @var int
* @access protected
*/
protected $Offset;
/**
* WHERE filter objects
*
* @var Array
* @access protected
*/
protected $WhereFilter = Array ();
/**
* HAVING filter objects
*
* @var Array
* @access protected
*/
protected $HavingFilter = Array ();
/**
* AGGREGATED filter objects
*
* @var Array
* @access protected
*/
protected $AggregateFilter = Array ();
/**
* List of "GROUP BY" fields
*
* @var Array
* @access protected
*/
protected $GroupByFields = Array ();
/**
* Remembers if list was queried
*
* @var bool
* @access protected
*/
protected $Queried = false;
/**
* Remembers if list was counted
*
* @var bool
* @access protected
*/
protected $Counted = false;
/**
* Name of the grid, used to display the list
*
* @var string
*/
var $gridName = '';
/**
* Identifies this list as main on the page, that allows to react on "page", "per_page" and "sort_by" parameters from url
*
* @var bool
* @access protected
*/
protected $mainList = false;
/**
* Holds field errors
*
* @var Array
* @access protected
*/
protected $FieldErrors = Array ();
/**
* Creates kDBList
*
* @return kDBList
* @access public
*/
public function __construct()
{
parent::__construct();
$this->OrderFields = Array();
$filters = $this->getFilterStructure();
foreach ($filters as $filter_params) {
$filter =& $this->$filter_params['type'];
$filter[ $filter_params['class'] ] =& $this->Application->makeClass('kMultipleFilter', Array ($filter_params['join_using']));
}
$this->PerPage = -1;
}
function setGridName($grid_name)
{
$this->gridName = $grid_name;
}
/**
* Returns information about all possible filter types
*
* @return Array
* @access protected
*/
protected function getFilterStructure()
{
$filters = Array (
Array ('type' => 'WhereFilter', 'class' => self::FLT_SYSTEM, 'join_using' => self::FLT_TYPE_AND),
Array ('type' => 'WhereFilter', 'class' => self::FLT_NORMAL, 'join_using' => self::FLT_TYPE_OR),
Array ('type' => 'WhereFilter', 'class' => self::FLT_SEARCH, 'join_using' => self::FLT_TYPE_OR),
Array ('type' => 'WhereFilter', 'class' => self::FLT_VIEW, 'join_using' => self::FLT_TYPE_AND),
Array ('type' => 'WhereFilter', 'class' => self::FLT_CUSTOM, 'join_using' => self::FLT_TYPE_AND),
Array ('type' => 'HavingFilter', 'class' => self::FLT_SYSTEM, 'join_using' => self::FLT_TYPE_AND),
Array ('type' => 'HavingFilter', 'class' => self::FLT_NORMAL, 'join_using' => self::FLT_TYPE_OR),
Array ('type' => 'HavingFilter', 'class' => self::FLT_SEARCH, 'join_using' => self::FLT_TYPE_OR),
Array ('type' => 'HavingFilter', 'class' => self::FLT_VIEW, 'join_using' => self::FLT_TYPE_AND),
Array ('type' => 'HavingFilter', 'class' => self::FLT_CUSTOM, 'join_using' => self::FLT_TYPE_AND),
Array ('type' => 'AggregateFilter', 'class' => self::FLT_SYSTEM, 'join_using' => self::FLT_TYPE_AND),
Array ('type' => 'AggregateFilter', 'class' => self::FLT_NORMAL, 'join_using' => self::FLT_TYPE_OR),
Array ('type' => 'AggregateFilter', 'class' => self::FLT_VIEW, 'join_using' => self::FLT_TYPE_AND),
);
return $filters;
}
/**
* Adds new or replaces old filter with same name
*
* @param string $name filter name (for internal use)
* @param string $clause where/having clause part (no OR/AND allowed)
* @param int $filter_type is filter having filter or where filter
* @param int $filter_scope filter subtype: FLT_NORMAL,FLT_SYSTEM,FLT_SEARCH,FLT_VIEW,FLT_CUSTOM
* @access public
*/
public function addFilter($name, $clause, $filter_type = self::WHERE_FILTER, $filter_scope = self::FLT_SYSTEM)
{
$filter_source = Array (
self::WHERE_FILTER => 'WhereFilter',
self::HAVING_FILTER => 'HavingFilter',
self::AGGREGATE_FILTER => 'AggregateFilter'
);
$filter_name = $filter_source[$filter_type];
$filter =& $this->$filter_name;
$filter =& $filter[$filter_scope];
/* @var $filter kMultipleFilter */
$filter->addFilter($name, $clause);
}
/**
* Reads filter content
*
* @param string $name filter name (for internal use)
* @param int $filter_type is filter having filter or where filter
* @param int $filter_scope filter subtype: FLT_NORMAL,FLT_SYSTEM,FLT_SEARCH,FLT_VIEW,FLT_CUSTOM
* @return string
* @access public
*/
public function getFilter($name, $filter_type = self::WHERE_FILTER, $filter_scope = self::FLT_SYSTEM)
{
$filter_source = Array (
self::WHERE_FILTER => 'WhereFilter',
self::HAVING_FILTER => 'HavingFilter',
self::AGGREGATE_FILTER => 'AggregateFilter'
);
$filter_name = $filter_source[$filter_type];
$filter =& $this->$filter_name;
$filter =& $filter[$filter_scope];
/* @var $filter kMultipleFilter */
return $filter->getFilter($name);
}
/**
* Removes specified filter from filters list
*
* @param string $name filter name (for internal use)
* @param int $filter_type is filter having filter or where filter
* @param int $filter_scope filter subtype: FLT_NORMAL,FLT_SYSTEM,FLT_SEARCH,FLT_VIEW,FLT_CUSTOM
* @access public
*/
public function removeFilter($name, $filter_type = self::WHERE_FILTER, $filter_scope = self::FLT_SYSTEM)
{
$filter_source = Array (
self::WHERE_FILTER => 'WhereFilter',
self::HAVING_FILTER => 'HavingFilter',
self::AGGREGATE_FILTER => 'AggregateFilter'
);
$filter_name = $filter_source[$filter_type];
$filter =& $this->$filter_name;
$filter =& $filter[$filter_scope];
/* @var $filter kMultipleFilter */
$filter->removeFilter($name);
}
/**
* Clear all filters
*
* @access public
*/
public function clearFilters()
{
$filters = $this->getFilterStructure();
foreach ($filters as $filter_params) {
$filter =& $this->$filter_params['type'];
$filter[ $filter_params['class'] ]->clearFilters();
}
}
/**
* Counts the total number of records base on the query resulted from {@link kDBList::GetSelectSQL()}
*
* The method modifies the query to substitude SELECT part (fields listing) with COUNT(*).
* Special care should be applied when working with lists based on grouped queries, all aggregate function fields
* like SUM(), AVERAGE() etc. should be added to CountedSQL by using {@link kDBList::SetCountedSQL()}
*
* @access protected
*/
protected function CountRecs()
{
$all_sql = $this->GetSelectSQL(true,false);
$sql = $this->getCountSQL($all_sql);
$this->Counted = true;
if( $this->GetGroupClause() )
{
$this->RecordsCount = count( $this->Conn->GetCol($sql) );
}
else
{
$this->RecordsCount = (int)$this->Conn->GetOne($sql);
}
$system_sql = $this->GetSelectSQL(true,true);
if($system_sql == $all_sql) //no need to query the same again
{
$this->NoFilterCount = $this->RecordsCount;
return;
}
$sql = $this->getCountSQL($system_sql);
if( $this->GetGroupClause() )
{
$this->NoFilterCount = count( $this->Conn->GetCol($sql) );
}
else
{
$this->NoFilterCount = (int)$this->Conn->GetOne($sql);
}
}
/**
* Returns record count in list with/without user filters applied
*
* @param bool $with_filters
* @return int
* @access public
*/
public function GetRecordsCount($with_filters = true)
{
if (!$this->Counted) {
$this->CountRecs();
}
return $with_filters ? $this->RecordsCount : $this->NoFilterCount;
}
/**
* Returns record count, that were actually selected
*
* @return int
* @access public
*/
public function GetSelectedCount()
{
return $this->SelectedCount;
}
/**
* Transforms given query into count query (DISTINCT is also processed)
*
* @param string $sql
* @return string
* @access public
*/
public function getCountSQL($sql)
{
if ( preg_match("/^\s*SELECT\s+DISTINCT(.*?\s)FROM(?!_)/is",$sql,$regs ) )
{
return preg_replace("/^\s*SELECT\s+DISTINCT(.*?\s)FROM(?!_)/is", "SELECT COUNT(DISTINCT ".$regs[1].") AS count FROM", $sql);
}
else
{
return preg_replace("/^\s*SELECT(.*?\s)FROM(?!_)/is", "SELECT COUNT(*) AS count FROM ", $sql);
}
}
/**
* Queries the database with SQL resulted from {@link kDBList::GetSelectSQL()} and stores result in {@link kDBList::SelectRS}
*
* All the sorting, pagination, filtration of the list should be set prior to calling Query().
*
* @param bool $force force re-query, when already queried
* @return bool
* @access public
*/
public function Query($force=false)
{
if (!$force && $this->Queried) return true;
$q = $this->GetSelectSQL();
//$rs = $this->Conn->SelectLimit($q, $this->PerPage, $this->Offset);
//in case we have not counted records try to select one more item to find out if we have something more than perpage
$limit = $this->Counted ? $this->PerPage : $this->PerPage+1;
$sql = $q.' '.$this->Conn->getLimitClause($this->Offset,$limit);
$this->Records = $this->Conn->Query($sql);
if (!$this->Records && ($this->Page > 1)) {
// no records & page > 1, try to reset to 1st page (works only when list in not counted before)
$this->Application->StoreVar($this->getPrefixSpecial() . '_Page', 1, true);
$this->SetPage(1);
$this->Query($force);
}
$this->SelectedCount = count($this->Records);
if (!$this->Counted) $this->RecordsCount = $this->SelectedCount;
if (!$this->Counted && $this->SelectedCount > $this->PerPage && $this->PerPage != -1) $this->SelectedCount--;
if ($this->Records === false) {
//handle errors here
return false;
}
$this->Queried = true;
- $query_event = new kEvent($this->getPrefixSpecial() . ':OnAfterListQuery');
- $this->Application->HandleEvent($query_event);
+ $this->Application->HandleEvent(new kEvent($this->getPrefixSpecial() . ':OnAfterListQuery'));
return true;
}
/**
* Adds one more record to list virtually and updates all counters
*
* @param Array $record
* @access public
*/
public function addRecord($record)
{
$this->Records[] = $record;
$this->SelectedCount++;
$this->RecordsCount++;
}
/**
* Calculates totals based on config
*
* @access protected
*/
protected function CalculateTotals()
{
$fields = Array();
$this->Totals = Array();
if ($this->gridName) {
$grids = $this->Application->getUnitOption($this->Prefix, 'Grids');
$grid_fields = $grids[$this->gridName]['Fields'];
}
else {
$grid_fields = $this->Fields;
}
foreach ($grid_fields as $field_name => $field_options) {
if ($this->gridName && array_key_exists('totals', $field_options) && $field_options['totals']) {
$totals = $field_options['totals'];
}
elseif (array_key_exists('totals', $this->Fields[$field_name]) && $this->Fields[$field_name]['totals']) {
$totals = $this->Fields[$field_name]['totals'];
}
else {
continue;
}
$calculated_field = array_key_exists($field_name, $this->CalculatedFields) && array_key_exists($field_name, $this->VirtualFields);
$db_field = !array_key_exists($field_name, $this->VirtualFields);
if ($calculated_field || $db_field) {
$field_expression = $calculated_field ? $this->CalculatedFields[$field_name] : '`'.$this->TableName.'`.`'.$field_name.'`';
$fields[$field_name] = $totals.'('.$field_expression.') AS '.$field_name.'_'.$totals;
}
}
if (!$fields) {
return ;
}
$sql = $this->GetSelectSQL(true, false);
$fields = str_replace('%1$s', $this->TableName, implode(', ', $fields));
if ( preg_match("/DISTINCT(.*?\s)FROM(?!_)/is",$sql,$regs ) )
{
$sql = preg_replace("/^\s*SELECT DISTINCT(.*?\s)FROM(?!_)/is", 'SELECT '.$fields.' FROM', $sql);
}
else
{
$sql = preg_replace("/^\s*SELECT(.*?\s)FROM(?!_)/is", 'SELECT '.$fields.' FROM ', $sql);
}
$totals = $this->Conn->Query($sql);
foreach($totals as $totals_row)
{
foreach($totals_row as $total_field => $field_value)
{
if(!isset($this->Totals[$total_field])) $this->Totals[$total_field] = 0;
$this->Totals[$total_field] += $field_value;
}
}
$this->TotalsCalculated = true;
}
/**
* Returns previously calculated total (not formatted)
*
* @param string $field
* @param string $total_function
* @return float
* @access public
*/
public function getTotal($field, $total_function)
{
if (!$this->TotalsCalculated) {
$this->CalculateTotals();
}
return $this->Totals[$field . '_' . $total_function];
}
function setTotal($field, $total_function, $value)
{
$this->Totals[$field . '_' . $total_function] = $value;
}
function getTotalFunction($field)
{
if ($this->gridName) {
$grids = $this->Application->getUnitOption($this->Prefix, 'Grids');
$field_options = $grids[$this->gridName]['Fields'][$field];
}
else {
$field_options = $this->Fields[$field];
}
if ($this->gridName && array_key_exists('totals', $field_options) && $field_options['totals']) {
return $field_options['totals'];
}
elseif (array_key_exists('totals', $this->Fields[$field]) && $this->Fields[$field]['totals']) {
return $this->Fields[$field]['totals'];
}
return false;
}
/**
* Returns previously calculated total (formatted)
*
* @param string $field
* @param string $total_function
* @return float
* @access public
*/
function GetFormattedTotal($field, $total_function)
{
$res = $this->getTotal($field, $total_function);
$formatter_class = $this->GetFieldOption($field, 'formatter');
if ( $formatter_class ) {
$formatter =& $this->Application->recallObject($formatter_class);
/* @var $formatter kFormatter */
$res = $formatter->Format($res, $field, $this);
}
return $res;
}
/**
* Builds full select query except for LIMIT clause
*
* @param bool $for_counting
* @param bool $system_filters_only
* @param string $keep_clause
* @return string
* @access public
*/
public function GetSelectSQL($for_counting = false, $system_filters_only = false, $keep_clause = '')
{
$q = parent::GetSelectSQL($this->SelectClause);
$q = !$for_counting ? $this->addCalculatedFields($q, 0) : str_replace('%2$s', '', $q);
$where = $this->GetWhereClause($for_counting,$system_filters_only);
$having = $this->GetHavingClause($for_counting,$system_filters_only);
$order = $this->GetOrderClause();
$group = $this->GetGroupClause();
if ( $for_counting ) {
$optimizer = new LeftJoinOptimizer($q, $where . '|' . $having . '|' . $order . '|' . $group . '|' . $keep_clause);
$q = $optimizer->simplify();
}
if (!empty($where)) $q .= ' WHERE ' . $where;
if (!empty($group)) $q .= ' GROUP BY ' . $group;
if (!empty($having)) $q .= ' HAVING ' . $having;
if ( !$for_counting && !empty($order) ) $q .= ' ORDER BY ' . $order;
return $this->replaceModePrefix( str_replace('%1$s', $this->TableName, $q) );
}
/**
* Replaces all calculated field occurrences with their associated expressions
*
* @param string $clause where clause to extract calculated fields from
* @param int $aggregated 0 - having + aggregated, 1 - having only, 2 - aggregated only
* @param bool $replace_table
* @return string
* @access public
*/
public function extractCalculatedFields($clause, $aggregated = 1, $replace_table = false)
{
$fields = $this->getCalculatedFields($aggregated);
if ( is_array($fields) && count($fields) > 0 ) {
foreach ($fields as $field_name => $field_expression) {
$clause = preg_replace('/(\\(+)[(,` ]*' . $field_name . '[` ]{1}/', '\1 (' . $field_expression . ') ', $clause);
$clause = preg_replace('/[,` ]{1}' . $field_name . '[` ]{1}/', ' (' . $field_expression . ') ', $clause);
}
}
return $replace_table ? str_replace('%1$s', $this->TableName, $clause) : $clause;
}
/**
* Returns WHERE clause of the query
*
* @param bool $for_counting merge where filters with having filters + replace field names for having fields with their values
* @param bool $system_filters_only
* @return string
* @access private
*/
private function GetWhereClause($for_counting=false,$system_filters_only=false)
{
$where =& $this->Application->makeClass('kMultipleFilter');
/* @var $where kMultipleFilter */
$where->addFilter('system_where', $this->WhereFilter[self::FLT_SYSTEM] );
if (!$system_filters_only) {
$where->addFilter('view_where', $this->WhereFilter[self::FLT_VIEW] );
$search_w = $this->WhereFilter[self::FLT_SEARCH]->getSQL();
if ($search_w || $for_counting) { // move search_having to search_where in case search_where isset or we are counting
$search_h = $this->extractCalculatedFields( $this->HavingFilter[self::FLT_SEARCH]->getSQL() );
$search_w = ($search_w && $search_h) ? $search_w.' OR '.$search_h : $search_w.$search_h;
$where->addFilter('search_where', $search_w );
}
// CUSTOM
$search_w = $this->WhereFilter[self::FLT_CUSTOM]->getSQL();
if ($search_w || $for_counting) { // move search_having to search_where in case search_where isset or we are counting
$search_h = $this->extractCalculatedFields( $this->HavingFilter[self::FLT_CUSTOM]->getSQL() );
$search_w = ($search_w && $search_h) ? $search_w.' AND '.$search_h : $search_w.$search_h;
$where->addFilter('custom_where', $search_w );
}
// CUSTOM
}
if( $for_counting ) // add system_having and view_having to where
{
$where->addFilter('system_having', $this->extractCalculatedFields($this->HavingFilter[kDBList::FLT_SYSTEM]->getSQL()) );
if (!$system_filters_only) $where->addFilter('view_having', $this->extractCalculatedFields( $this->HavingFilter[kDBList::FLT_VIEW]->getSQL() ) );
}
return $where->getSQL();
}
/**
* Returns HAVING clause of the query
*
* @param bool $for_counting don't return having filter in case if this is counting sql
* @param bool $system_filters_only return only system having filters
* @param int $aggregated 0 - aggregated and having, 1 - having only, 2 - aggregated only
* @return string
* @access private
*/
private function GetHavingClause($for_counting=false, $system_filters_only=false, $aggregated = 0)
{
if ($for_counting) {
$aggregate_filter =& $this->Application->makeClass('kMultipleFilter');
/* @var $aggregate_filter kMultipleFilter */
$aggregate_filter->addFilter('aggregate_system', $this->AggregateFilter[kDBList::FLT_SYSTEM]);
if (!$system_filters_only) {
$aggregate_filter->addFilter('aggregate_view', $this->AggregateFilter[kDBList::FLT_VIEW]);
}
return $this->extractCalculatedFields($aggregate_filter->getSQL(), 2);
}
$having =& $this->Application->makeClass('kMultipleFilter');
/* @var $having kMultipleFilter */
$having->addFilter('system_having', $this->HavingFilter[kDBList::FLT_SYSTEM] );
if ($aggregated == 0) {
if (!$system_filters_only) {
$having->addFilter('view_aggregated', $this->AggregateFilter[kDBList::FLT_VIEW] );
}
$having->addFilter('system_aggregated', $this->AggregateFilter[kDBList::FLT_SYSTEM]);
}
if (!$system_filters_only) {
$having->addFilter('view_having', $this->HavingFilter[kDBList::FLT_VIEW] );
$having->addFilter('custom_having', $this->HavingFilter[kDBList::FLT_CUSTOM] );
$search_w = $this->WhereFilter[kDBList::FLT_SEARCH]->getSQL();
if (!$search_w) {
$having->addFilter('search_having', $this->HavingFilter[kDBList::FLT_SEARCH] );
}
}
return $having->getSQL();
}
/**
* Returns GROUP BY clause of the query
*
* @return string
* @access protected
*/
protected function GetGroupClause()
{
return $this->GroupByFields ? implode(',', $this->GroupByFields) : '';
}
/**
* Adds new group by field
*
* @param string $field
* @access public
*/
public function AddGroupByField($field)
{
$this->GroupByFields[$field] = $field;
}
/**
* Removes group by field added before
*
* @param string $field
* @access public
*/
public function RemoveGroupByField($field)
{
unset($this->GroupByFields[$field]);
}
/**
* Adds order field to ORDER BY clause
*
* @param string $field Field name
* @param string $direction Direction of ordering (asc|desc)
* @param bool $is_expression this is expression, that should not be escapted by "`" symbols
* @return int
* @access public
*/
public function AddOrderField($field, $direction = 'asc', $is_expression = false)
{
// original multilanguage field - convert to current lang field
$formatter = isset($this->Fields[$field]['formatter']) ? $this->Fields[$field]['formatter'] : false;
if ($formatter == 'kMultiLanguage' && !isset($this->Fields[$field]['master_field'])) {
// for now kMultiLanguage formatter is only supported for real (non-virtual) fields
$is_expression = true;
$field = $this->getMLSortField($field);
}
if (!isset($this->Fields[$field]) && $field != 'RAND()' && !$is_expression) {
trigger_error('<span class="debug_error">Incorrect sorting</span> defined (field = <b>'.$field.'</b>; direction = <b>'.$direction.'</b>) in config for prefix <b>'.$this->Prefix.'</b>', E_USER_NOTICE);
}
$this->OrderFields[] = Array($field, $direction, $is_expression);
return count($this->OrderFields) - 1;
}
/**
* Sets new order fields, replacing existing ones
*
* @param Array $order_fields
* @return void
* @access public
*/
public function setOrderFields($order_fields)
{
$this->OrderFields = $order_fields;
}
/**
* Changes sorting direction for a given sorting field index
*
* @param int $field_index
* @param string $direction
* @return void
* @access public
*/
public function changeOrderDirection($field_index, $direction)
{
if ( !isset($this->OrderFields[$field_index]) ) {
return;
}
$this->OrderFields[$field_index][1] = $direction;
}
/**
* Returns expression, used to sort given multilingual field
*
* @param string $field
* @return string
*/
function getMLSortField($field)
{
$table_name = '`' . $this->TableName . '`';
$lang = $this->Application->GetVar('m_lang');
$primary_lang = $this->Application->GetDefaultLanguageId();
$ret = 'IF(COALESCE(%1$s.l' . $lang . '_' . $field . ', ""), %1$s.l' . $lang . '_' . $field . ', %1$s.l' . $primary_lang . '_' . $field . ')';
return sprintf($ret, $table_name);
}
/**
* Removes all order fields
*
* @access public
*/
public function ClearOrderFields()
{
$this->OrderFields = Array();
}
/**
* Returns ORDER BY Clause of the query
*
* The method builds order by clause by iterating {@link kDBList::OrderFields} array and concatenating it.
*
* @return string
* @access private
*/
private function GetOrderClause()
{
$ret = '';
foreach ($this->OrderFields as $field) {
$name = $field[0];
$ret .= isset($this->Fields[$name]) && !isset($this->VirtualFields[$name]) ? '`'.$this->TableName.'`.' : '';
if ($field[0] == 'RAND()' || $field[2]) {
$ret .= $field[0].' '.$field[1].',';
}
else {
$ret .= (strpos($field[0], '.') === false ? '`'.$field[0] . '`' : $field[0]) . ' ' . $field[1] . ',';
}
}
$ret = rtrim($ret, ',');
return $ret;
}
/**
* Returns order field name in given position
*
* @param int $pos
* @param bool $no_default
* @return string
* @access public
*/
public function GetOrderField($pos = NULL, $no_default = false)
{
if ( !(isset($this->OrderFields[$pos]) && $this->OrderFields[$pos]) && !$no_default ) {
$pos = 0;
}
if ( isset($this->OrderFields[$pos][0]) ) {
$field = $this->OrderFields[$pos][0];
$lang = $this->Application->GetVar('m_lang');
if ( preg_match('/^IF\(COALESCE\(.*?\.(l' . $lang . '_.*?), ""\),/', $field, $regs) ) {
// undo result of kDBList::getMLSortField method
return $regs[1];
}
return $field;
}
return '';
}
/**
* Returns list order fields
*
* @return Array
* @access public
*/
public function getOrderFields()
{
return $this->OrderFields;
}
/**
* Returns order field direction in given position
*
* @param int $pos
* @param bool $no_default
* @return string
* @access public
*/
public function GetOrderDirection($pos = NULL, $no_default = false)
{
if ( !(isset($this->OrderFields[$pos]) && $this->OrderFields[$pos]) && !$no_default ) {
$pos = 0;
}
return isset($this->OrderFields[$pos][1]) ? $this->OrderFields[$pos][1] : '';
}
/**
* Returns ID of currently processed record
*
* @return int
* @access public
*/
public function GetID()
{
return $this->Queried ? $this->GetDBField($this->IDField) : null;
}
/**
* Allows kDBTagProcessor.SectionTitle to detect if it's editing or new item creation
*
* @return bool
* @access public
*/
public function IsNewItem()
{
// no such thing as NewItem for lists :)
return false;
}
/**
* Return unformatted field value
*
* @param string $name
* @return string
* @access public
*/
public function GetDBField($name)
{
$row =& $this->getCurrentRecord();
if (defined('DEBUG_MODE') && DEBUG_MODE && $this->Queried && !array_key_exists($name, $row)) {
if ( $this->Application->isDebugMode() ) {
$this->Application->Debugger->appendTrace();
}
trigger_error('Field "<strong>' . $name . '</strong>" doesn\'t exist in prefix <strong>' . $this->getPrefixSpecial() . '</strong>', E_USER_WARNING);
return 'NO SUCH FIELD';
}
// return "null" for missing fields, because formatter require such behaviour !
return array_key_exists($name, $row) ? $row[$name] : null;
}
/**
* Checks if requested field is present after database query
*
* @param string $name
* @return bool
* @access public
*/
public function HasField($name)
{
$row =& $this->getCurrentRecord();
return isset($row[$name]);
}
/**
* Returns current record fields
*
* @return Array
* @access public
*/
public function GetFieldValues()
{
$record =& $this->getCurrentRecord();
return $record;
}
/**
* Returns current record from list
*
* @param int $offset Offset relative to current record index
* @return Array
* @access public
*/
public function &getCurrentRecord($offset = 0)
{
$record_index = $this->CurrentIndex + $offset;
if ($record_index >=0 && $record_index < $this->SelectedCount) {
return $this->Records[$record_index];
}
$false = false;
return $false;
}
/**
* Goes to record with given index
*
* @param int $index
* @access public
*/
public function GoIndex($index)
{
$this->CurrentIndex = $index;
}
/**
* Goes to first record
*
* @access public
*/
public function GoFirst()
{
$this->CurrentIndex = 0;
}
/**
* Goes to next record
*
* @access public
*/
public function GoNext()
{
$this->CurrentIndex++;
}
/**
* Goes to previous record
*
* @access public
*/
public function GoPrev()
{
if ($this->CurrentIndex>0) {
$this->CurrentIndex--;
}
}
/**
* Checks if there is no end of list
*
* @return bool
* @access public
*/
public function EOL()
{
return ($this->CurrentIndex >= $this->SelectedCount);
}
/**
* Returns total page count based on list per-page
*
* @return int
* @access public
*/
public function GetTotalPages()
{
if ( !$this->Counted ) {
$this->CountRecs();
}
if ( $this->PerPage == -1 ) {
return 1;
}
$integer_part = ($this->RecordsCount - ($this->RecordsCount % $this->PerPage)) / $this->PerPage;
$reminder = ($this->RecordsCount % $this->PerPage) != 0; // adds 1 if there is a reminder
$this->TotalPages = $integer_part + $reminder;
return $this->TotalPages;
}
/**
* Sets number of records to query per page
*
* @param int $per_page Number of records to display per page
* @access public
*/
public function SetPerPage($per_page)
{
$this->PerPage = $per_page;
}
/**
* Returns records per page count
*
* @param bool $in_fact
* @return int
* @access public
*/
public function GetPerPage($in_fact = false)
{
if ($in_fact) {
return $this->PerPage;
}
return $this->PerPage == -1 ? $this->RecordsCount : $this->PerPage;
}
/**
* Sets current page in list
*
* @param int $page
* @access public
*/
public function SetPage($page)
{
if ($this->PerPage == -1) {
$this->Page = 1;
return;
}
if ($page < 1) $page = 1;
$this->Offset = ($page-1)*$this->PerPage;
if ($this->Counted && $this->Offset > $this->RecordsCount) {
$this->SetPage(1);
}
else {
$this->Page = $page;
}
//$this->GoFirst();
}
/**
* Returns current list page
*
* @return int
* @access public
*/
public function GetPage()
{
return $this->Page;
}
/**
* Sets list query offset
*
* @param int $offset
* @access public
*/
public function SetOffset($offset)
{
$this->Offset = $offset;
}
/**
* Gets list query offset
*
* @return int
* @access public
*/
public function GetOffset()
{
return $this->Offset;
}
/**
* Sets current item field value (doesn't apply formatting)
*
* @param string $name Name of the field
* @param mixed $value Value to set the field to
* @access public
*/
public function SetDBField($name,$value)
{
$this->Records[$this->CurrentIndex][$name] = $value;
}
/**
* Apply where clause, that links this object to it's parent item
*
* @param string $special
* @access public
*/
public function linkToParent($special)
{
$parent_prefix = $this->Application->getUnitOption($this->Prefix, 'ParentPrefix');
if ($parent_prefix) {
$parent_table_key = $this->Application->getUnitOption($this->Prefix, 'ParentTableKey');
if (is_array($parent_table_key)) $parent_table_key = getArrayValue($parent_table_key, $parent_prefix);
$foreign_key_field = $this->Application->getUnitOption($this->Prefix, 'ForeignKey');
if (is_array($foreign_key_field)) $foreign_key_field = getArrayValue($foreign_key_field, $parent_prefix);
if (!$parent_table_key || !$foreign_key_field) {
return ;
}
$parent_object =& $this->Application->recallObject($parent_prefix.'.'.$special);
/* @var $parent_object kDBItem */
if (!$parent_object->isLoaded()) {
$this->addFilter('parent_filter', 'FALSE');
trigger_error('Parent ID not found (prefix: "<strong>' . rtrim($parent_prefix.'.'.$special, '.') . '</strong>"; sub-prefix: "<strong>' . $this->getPrefixSpecial() . '</strong>")', E_USER_NOTICE);
return ;
}
// only for list in this case
$parent_id = $parent_object->GetDBField($parent_table_key);
$this->addFilter('parent_filter', '`' . $this->TableName . '`.`' . $foreign_key_field . '` = ' . $this->Conn->qstr($parent_id));
}
}
/**
* Returns true if list was queried (same name as for kDBItem for easy usage)
*
* @return bool
* @access public
*/
public function isLoaded()
{
return $this->Queried && !$this->EOL();
}
/**
* Returns specified field value from all selected rows.
* Don't affect current record index
*
* @param string $field
* @param bool $formatted
* @param string $format
* @return Array
* @access public
*/
public function GetCol($field, $formatted = false, $format = null)
{
$i = 0;
$ret = Array ();
if ($formatted && array_key_exists('formatter', $this->Fields[$field])) {
$formatter =& $this->Application->recallObject($this->Fields[$field]['formatter']);
/* @var $formatter kFormatter */
while ($i < $this->SelectedCount) {
$ret[] = $formatter->Format($this->Records[$i][$field], $field, $this, $format);
$i++;
}
}
else {
while ($i < $this->SelectedCount) {
$ret[] = $this->Records[$i][$field];
$i++;
}
}
return $ret;
}
/**
* Set's field error, if pseudo passed not found then create it with message text supplied.
* Don't overwrite existing pseudo translation.
*
* @param string $field
* @param string $pseudo
* @param string $error_label
* @param Array $error_params
* @return bool
* @access public
* @see kSearchHelper::processRangeField()
* @see kDateFormatter::Parse()
*/
public function SetError($field, $pseudo, $error_label = null, $error_params = null)
{
$error_field = isset($this->Fields[$field]['error_field']) ? $this->Fields[$field]['error_field'] : $field;
$this->FieldErrors[$error_field]['pseudo'] = $pseudo;
$var_name = $this->getPrefixSpecial() . '_' . $field . '_error';
$previous_pseudo = $this->Application->RecallVar($var_name);
if ( $previous_pseudo ) {
// don't set more then one error on field
return false;
}
$this->Application->StoreVar($var_name, $pseudo);
return true;
}
/**
* Returns error pseudo
*
* @param string $field
* @return string
* @access public
* @see kSearchHelper::processRangeField()
*/
public function GetErrorPseudo($field)
{
if ( !isset($this->FieldErrors[$field]) ) {
return '';
}
return isset($this->FieldErrors[$field]['pseudo']) ? $this->FieldErrors[$field]['pseudo'] : '';
}
/**
* Removes error on field
*
* @param string $field
* @access public
*/
public function RemoveError($field)
{
unset( $this->FieldErrors[$field] );
}
/**
* Group list records by header, saves internal order in group
*
* @param string $heading_field
* @access public
*/
public function groupRecords($heading_field)
{
$i = 0;
$sorted = Array ();
while ($i < $this->SelectedCount) {
$sorted[ $this->Records[$i][$heading_field] ][] = $this->Records[$i];
$i++;
}
$this->Records = Array ();
foreach ($sorted as $heading => $heading_records) {
$this->Records = array_merge_recursive($this->Records, $heading_records);
}
}
/**
* Reset list (use for requering purposes)
*
* @access public
*/
public function reset()
{
$this->Counted = false;
$this->clearFilters();
$this->ClearOrderFields();
}
/**
* Checks if list was counted
*
* @return bool
* @access public
*/
public function isCounted()
{
return $this->Counted;
}
/**
* Tells, that given list is main
*
* @return bool
* @access public
*/
public function isMainList()
{
return $this->mainList;
}
/**
* Makes given list as main
*
* @access public
*/
public function becameMain()
{
$this->mainList = true;
}
}
class LeftJoinOptimizer {
/**
* Input sql for optimization
*
* @var string
* @access private
*/
private $sql = '';
/**
* All sql parts, where LEFT JOINed table aliases could be used
*
* @var string
* @access private
*/
private $usageString = '';
/**
* List of discovered LEFT JOINs
*
* @var Array
* @access private
*/
private $joins = Array ();
/**
* LEFT JOIN relations
*
* @var Array
* @access private
*/
private $joinRelations = Array ();
/**
* LEFT JOIN table aliases scheduled for removal
*
* @var Array
* @access private
*/
private $aliasesToRemove = Array ();
/**
* Creates new instance of the class
*
* @param string $sql
* @param string $usage_string
*/
public function __construct($sql, $usage_string)
{
$this->sql = $sql;
$this->usageString = $usage_string;
$this->parseJoins();
}
/**
* Tries to remove unused LEFT JOINs
*
* @return string
* @access public
*/
public function simplify()
{
if ( !$this->joins ) {
// no LEFT JOIN used, return unchanged sql
return $this->sql;
}
$this->updateRelations();
$this->removeAliases();
return $this->sql;
}
/**
* Discovers LEFT JOINs based on given sql
*
* @return void
* @access private
*/
private function parseJoins()
{
if ( !preg_match_all('/LEFT\s+JOIN\s+(.*?|.*?\s+AS\s+.*?|.*?\s+.*?)\s+ON\s+(.*?\n|.*?$)/i', $this->sql, $regs) ) {
$this->joins = Array ();
}
// get all LEFT JOIN clause info from sql (without filters)
foreach ($regs[1] as $index => $match) {
$match_parts = preg_split('/\s+AS\s+|\s+/i', $match, 2);
$table_alias = count($match_parts) == 1 ? $match : $match_parts[1];
$this->joins[$table_alias] = Array (
'table' => $match_parts[0],
'join_clause' => $regs[0][$index],
);
}
}
/**
* Detects relations between LEFT JOINs
*
* @return void
* @access private
*/
private function updateRelations()
{
foreach ($this->joins as $table_alias => $left_join_info) {
$escaped_alias = preg_quote($table_alias, '/');
foreach ($this->joins as $sub_table_alias => $sub_left_join_info) {
if ($table_alias == $sub_table_alias) {
continue;
}
if ( $this->matchAlias($escaped_alias, $sub_left_join_info['join_clause']) ) {
$this->joinRelations[] = $sub_table_alias . ':' . $table_alias;
}
}
}
}
/**
* Removes scheduled LEFT JOINs, but only if they are not protected
*
* @return void
* @access private
*/
private function removeAliases()
{
$this->prepareAliasesRemoval();
foreach ($this->aliasesToRemove as $to_remove_alias) {
if ( !$this->aliasProtected($to_remove_alias) ) {
$this->sql = str_replace($this->joins[$to_remove_alias]['join_clause'], '', $this->sql);
}
}
}
/**
* Schedules unused LEFT JOINs to for removal
*
* @return void
* @access private
*/
private function prepareAliasesRemoval()
{
foreach ($this->joins as $table_alias => $left_join_info) {
$escaped_alias = preg_quote($table_alias, '/');
if ( !$this->matchAlias($escaped_alias, $this->usageString) ) {
$this->aliasesToRemove[] = $table_alias;
}
}
}
/**
* Checks if someone wants to remove LEFT JOIN, but it's used by some other LEFT JOIN, that stays
*
* @param string $table_alias
* @return bool
* @access private
*/
private function aliasProtected($table_alias)
{
foreach ($this->joinRelations as $relation) {
list ($main_alias, $used_alias) = explode(':', $relation);
if ( ($used_alias == $table_alias) && !in_array($main_alias, $this->aliasesToRemove) ) {
return true;
}
}
return false;
}
/**
* Matches given escaped alias to a string
*
* @param string $escaped_alias
* @param string $string
* @return bool
* @access private
*/
private function matchAlias($escaped_alias, $string)
{
return preg_match('/(`' . $escaped_alias . '`|' . $escaped_alias . ')\./', $string);
}
}
\ No newline at end of file
Index: branches/5.2.x/core/kernel/db/db_event_handler.php
===================================================================
--- branches/5.2.x/core/kernel/db/db_event_handler.php (revision 15129)
+++ branches/5.2.x/core/kernel/db/db_event_handler.php (revision 15130)
@@ -1,3419 +1,3419 @@
<?php
/**
* @version $Id$
* @package In-Portal
* @copyright Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
* @license GNU/GPL
* In-Portal is Open Source software.
* This means that this software may have been modified pursuant
* the GNU General Public License, and as distributed it includes
* or is derivative of works licensed under the GNU General Public License
* or other free or open source software licenses.
* See http://www.in-portal.org/license for copyright notices and details.
*/
defined('FULL_PATH') or die('restricted access!');
define('EH_CUSTOM_PROCESSING_BEFORE',1);
define('EH_CUSTOM_PROCESSING_AFTER',2);
/**
* Note:
* 1. When addressing 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 current Prefix_Special
* for variables being 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 form which contain $Prefix_Special then note 1st item. Example:
* LinkVar($event->getPrefixSpecial(true).'_varname',$event->getPrefixSpecial().'_varname')
*
*/
/**
* EventHandler that is used to process
* any database related events
*
*/
class kDBEventHandler extends kEventHandler {
/**
* Checks permissions of user
*
* @param kEvent $event
* @return bool
* @access public
*/
- public function CheckPermission(kEvent &$event)
+ public function CheckPermission(kEvent $event)
{
$section = $event->getSection();
if ( !$this->Application->isAdmin ) {
$allow_events = Array ('OnSearch', 'OnSearchReset', 'OnNew');
if ( in_array($event->Name, $allow_events) ) {
// allow search on front
return true;
}
}
elseif ( ($event->Name == 'OnPreSaveAndChangeLanguage') && !$this->UseTempTables($event) ) {
// allow changing language in grids, when not in editing mode
return $this->Application->CheckPermission($section . '.view', 1);
}
if ( !preg_match('/^CATEGORY:(.*)/', $section) ) {
// only if not category item events
if ( (substr($event->Name, 0, 9) == 'OnPreSave') || ($event->Name == 'OnSave') ) {
if ( $this->isNewItemCreate($event) ) {
return $this->Application->CheckPermission($section . '.add', 1);
}
else {
return $this->Application->CheckPermission($section . '.add', 1) || $this->Application->CheckPermission($section . '.edit', 1);
}
}
}
if ( $event->Name == 'OnPreCreate' ) {
// save category_id before item create (for item category selector not to destroy permission checking category)
$this->Application->LinkVar('m_cat_id');
}
if ( $event->Name == 'OnSaveWidths' ) {
return $this->Application->isAdminUser;
}
return parent::CheckPermission($event);
}
/**
* Allows to override standard permission mapping
*
* @return void
* @access protected
* @see kEventHandler::$permMapping
*/
protected function mapPermissions()
{
parent::mapPermissions();
$permissions = Array (
'OnLoad' => Array ('self' => 'view', 'subitem' => 'view'),
'OnItemBuild' => Array ('self' => 'view', 'subitem' => 'view'),
'OnSuggestValues' => Array ('self' => 'view', 'subitem' => 'view'),
'OnBuild' => Array ('self' => true),
'OnNew' => Array ('self' => 'add', 'subitem' => 'add|edit'),
'OnCreate' => Array ('self' => 'add', 'subitem' => 'add|edit'),
'OnUpdate' => Array ('self' => 'edit', 'subitem' => 'add|edit'),
'OnSetPrimary' => Array ('self' => 'add|edit', 'subitem' => 'add|edit'),
'OnDelete' => Array ('self' => 'delete', 'subitem' => 'add|edit'),
'OnDeleteAll' => Array ('self' => 'delete', 'subitem' => 'add|edit'),
'OnMassDelete' => Array ('self' => 'delete', 'subitem' => 'add|edit'),
'OnMassClone' => Array ('self' => 'add', 'subitem' => 'add|edit'),
'OnCut' => Array ('self'=>'edit', 'subitem' => 'edit'),
'OnCopy' => Array ('self'=>'edit', 'subitem' => 'edit'),
'OnPaste' => Array ('self'=>'edit', 'subitem' => 'edit'),
'OnSelectItems' => Array ('self' => 'add|edit', 'subitem' => 'add|edit'),
'OnProcessSelected' => Array ('self' => 'add|edit', 'subitem' => 'add|edit'),
'OnStoreSelected' => Array ('self' => 'add|edit', 'subitem' => 'add|edit'),
'OnSelectUser' => Array ('self' => 'add|edit', 'subitem' => 'add|edit'),
'OnMassApprove' => Array ('self' => 'advanced:approve|edit', 'subitem' => 'advanced:approve|add|edit'),
'OnMassDecline' => Array ('self' => 'advanced:decline|edit', 'subitem' => 'advanced:decline|add|edit'),
'OnMassMoveUp' => Array ('self' => 'advanced:move_up|edit', 'subitem' => 'advanced:move_up|add|edit'),
'OnMassMoveDown' => Array ('self' => 'advanced:move_down|edit', 'subitem' => 'advanced:move_down|add|edit'),
'OnPreCreate' => Array ('self' => 'add|add.pending', 'subitem' => 'edit|edit.pending'),
'OnEdit' => Array ('self' => 'edit|edit.pending', 'subitem' => 'edit|edit.pending'),
'OnExport' => Array ('self' => 'view|advanced:export'),
'OnExportBegin' => Array ('self' => 'view|advanced:export'),
'OnExportProgress' => Array ('self' => 'view|advanced:export'),
'OnSetAutoRefreshInterval' => Array ('self' => true, 'subitem' => true),
'OnAutoRefreshToggle' => Array ('self' => true, 'subitem' => true),
// theese event do not harm, but just in case check them too :)
'OnCancelEdit' => Array ('self' => true, 'subitem' => true),
'OnCancel' => Array ('self' => true, 'subitem' => true),
'OnReset' => Array ('self' => true, 'subitem' => true),
'OnSetSorting' => Array ('self' => true, 'subitem' => true),
'OnSetSortingDirect' => Array ('self' => true, 'subitem' => true),
'OnResetSorting' => Array ('self' => true, 'subitem' => true),
'OnSetFilter' => Array ('self' => true, 'subitem' => true),
'OnApplyFilters' => Array ('self' => true, 'subitem' => true),
'OnRemoveFilters' => Array ('self' => true, 'subitem' => true),
'OnSetFilterPattern' => Array ('self' => true, 'subitem' => true),
'OnSetPerPage' => Array ('self' => true, 'subitem' => true),
'OnSetPage' => Array ('self' => true, 'subitem' => true),
'OnSearch' => Array ('self' => true, 'subitem' => true),
'OnSearchReset' => Array ('self' => true, 'subitem' => true),
'OnGoBack' => Array ('self' => true, 'subitem' => true),
// it checks permission itself since flash uploader does not send cookies
'OnUploadFile' => Array ('self' => true, 'subitem' => true),
'OnDeleteFile' => Array ('self' => true, 'subitem' => true),
'OnViewFile' => Array ('self' => true, 'subitem' => true),
'OnSaveWidths' => Array ('self' => true, 'subitem' => true),
'OnValidateMInputFields' => Array ('self' => 'view'),
'OnValidateField' => Array ('self' => true, 'subitem' => true),
);
$this->permMapping = array_merge($this->permMapping, $permissions);
}
/**
* Define alternative event processing method names
*
* @return void
* @see kEventHandler::$eventMethods
* @access protected
*/
protected function mapEvents()
{
$events_map = Array (
'OnRemoveFilters' => 'FilterAction',
'OnApplyFilters' => 'FilterAction',
'OnMassApprove' => 'iterateItems',
'OnMassDecline' => 'iterateItems',
'OnMassMoveUp' => 'iterateItems',
'OnMassMoveDown' => 'iterateItems',
);
$this->eventMethods = array_merge($this->eventMethods, $events_map);
}
/**
* Returns ID of current item to be edited
* by checking ID passed in get/post as prefix_id
* or by looking at first from selected ids, stored.
* Returned id is also stored in Session in case
* it was explicitly passed as get/post
*
* @param kEvent $event
* @return int
* @access public
*/
- public function getPassedID(kEvent &$event)
+ public function getPassedID(kEvent $event)
{
if ( $event->getEventParam('raise_warnings') === false ) {
$event->setEventParam('raise_warnings', 1);
}
if ( $event->Special == 'previous' || $event->Special == 'next' ) {
$object =& $this->Application->recallObject($event->getEventParam('item'));
/* @var $object kDBItem */
$list_helper =& $this->Application->recallObject('ListHelper');
/* @var $list_helper ListHelper */
$select_clause = $this->Application->getUnitOption($object->Prefix, 'NavigationSelectClause', null);
return $list_helper->getNavigationResource($object, $event->getEventParam('list'), $event->Special == 'next', $select_clause);
}
elseif ( $event->Special == 'filter' ) {
// temporary object, used to print filter options only
return 0;
}
if ( preg_match('/^auto-(.*)/', $event->Special, $regs) && $this->Application->prefixRegistred($regs[1]) ) {
// <inp2:lang.auto-phrase_Field name="DateFormat"/> - returns field DateFormat value from language (LanguageId is extracted from current phrase object)
$main_object =& $this->Application->recallObject($regs[1]);
/* @var $main_object kDBItem */
$id_field = $this->Application->getUnitOption($event->Prefix, 'IDField');
return $main_object->GetDBField($id_field);
}
// 1. get id from post (used in admin)
$ret = $this->Application->GetVar($event->getPrefixSpecial(true) . '_id');
if ( ($ret !== false) && ($ret != '') ) {
return $ret;
}
// 2. get id from env (used in front)
$ret = $this->Application->GetVar($event->getPrefixSpecial() . '_id');
if ( ($ret !== false) && ($ret != '') ) {
return $ret;
}
// recall selected ids array and use the first one
$ids = $this->Application->GetVar($event->getPrefixSpecial() . '_selected_ids');
if ( $ids != '' ) {
$ids = explode(',', $ids);
if ( $ids ) {
$ret = array_shift($ids);
}
}
else { // if selected ids are not yet stored
$this->StoreSelectedIDs($event);
return $this->Application->GetVar($event->getPrefixSpecial() . '_id'); // StoreSelectedIDs sets this variable
}
return $ret;
}
/**
* Prepares and stores selected_ids string
* in Session and Application Variables
* by getting all checked ids from grid plus
* id passed in get/post as prefix_id
*
* @param kEvent $event
* @param Array $direct_ids
* @return Array
* @access protected
*/
- protected function StoreSelectedIDs(kEvent &$event, $direct_ids = null)
+ protected function StoreSelectedIDs(kEvent $event, $direct_ids = null)
{
$wid = $this->Application->GetTopmostWid($event->Prefix);
$session_name = rtrim($event->getPrefixSpecial() . '_selected_ids_' . $wid, '_');
$ids = $event->getEventParam('ids');
if ( isset($direct_ids) || ($ids !== false) ) {
// save ids directly if they given + reset array indexes
$resulting_ids = $direct_ids ? array_values($direct_ids) : ($ids ? array_values($ids) : false);
if ( $resulting_ids ) {
$this->Application->SetVar($event->getPrefixSpecial() . '_selected_ids', implode(',', $resulting_ids));
$this->Application->LinkVar($event->getPrefixSpecial() . '_selected_ids', $session_name, '', true);
$this->Application->SetVar($event->getPrefixSpecial() . '_id', $resulting_ids[0]);
return $resulting_ids;
}
return Array ();
}
$ret = Array ();
// May be we don't need this part: ?
$passed = $this->Application->GetVar($event->getPrefixSpecial(true) . '_id');
if ( $passed !== false && $passed != '' ) {
array_push($ret, $passed);
}
$ids = Array ();
// get selected ids from post & save them to session
$items_info = $this->Application->GetVar($event->getPrefixSpecial(true));
if ( $items_info ) {
$id_field = $this->Application->getUnitOption($event->Prefix, 'IDField');
foreach ($items_info as $id => $field_values) {
if ( getArrayValue($field_values, $id_field) ) {
array_push($ids, $id);
}
}
//$ids = array_keys($items_info);
}
$ret = array_unique(array_merge($ret, $ids));
$this->Application->SetVar($event->getPrefixSpecial() . '_selected_ids', implode(',', $ret));
$this->Application->LinkVar($event->getPrefixSpecial() . '_selected_ids', $session_name, '', !$ret); // optional when IDs are missing
// This is critical - otherwise getPassedID will return last ID stored in session! (not exactly true)
// this smells... needs to be refactored
$first_id = getArrayValue($ret, 0);
if ( ($first_id === false) && ($event->getEventParam('raise_warnings') == 1) ) {
if ( $this->Application->isDebugMode() ) {
$this->Application->Debugger->appendTrace();
}
trigger_error('Requested ID for prefix <strong>' . $event->getPrefixSpecial() . '</strong> <span class="debug_error">not passed</span>', E_USER_NOTICE);
}
$this->Application->SetVar($event->getPrefixSpecial() . '_id', $first_id);
return $ret;
}
/**
* Returns stored selected ids as an array
*
* @param kEvent $event
* @param bool $from_session return ids from session (written, when editing was started)
* @return Array
* @access protected
*/
- protected function getSelectedIDs(kEvent &$event, $from_session = false)
+ protected function getSelectedIDs(kEvent $event, $from_session = false)
{
if ( $from_session ) {
$wid = $this->Application->GetTopmostWid($event->Prefix);
$var_name = rtrim($event->getPrefixSpecial() . '_selected_ids_' . $wid, '_');
$ret = $this->Application->RecallVar($var_name);
}
else {
$ret = $this->Application->GetVar($event->getPrefixSpecial() . '_selected_ids');
}
return explode(',', $ret);
}
/**
* Stores IDs, selected in grid in session
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnStoreSelected(kEvent &$event)
+ protected function OnStoreSelected(kEvent $event)
{
$this->StoreSelectedIDs($event);
$id = $this->Application->GetVar($event->getPrefixSpecial() . '_id');
if ( $id !== false ) {
$event->SetRedirectParam($event->getPrefixSpecial() . '_id', $id);
$event->SetRedirectParam('pass', 'all,' . $event->getPrefixSpecial());
}
}
/**
* Returns associative array of submitted fields for current item
* Could be used while creating/editing single item -
* meaning on any edit form, except grid edit
*
* @param kEvent $event
* @return Array
* @access protected
*/
- protected function getSubmittedFields(kEvent &$event)
+ protected function getSubmittedFields(kEvent $event)
{
$items_info = $this->Application->GetVar($event->getPrefixSpecial(true));
$field_values = $items_info ? array_shift($items_info) : Array ();
return $field_values;
}
/**
* Returns fields, that are not allowed to be changed from request
*
* @param Array $hash
* @return Array
* @access protected
*/
protected function getRequestProtectedFields($hash)
{
// by default don't allow changing ID or foreign key from request
$fields = Array ();
$fields[] = $this->Application->getUnitOption($this->Prefix, 'IDField');
$parent_prefix = $this->Application->getUnitOption($this->Prefix, 'ParentPrefix');
if ( $parent_prefix && !$this->Application->isAdmin ) {
$foreign_key = $this->Application->getUnitOption($this->Prefix, 'ForeignKey');
$fields[] = is_array($foreign_key) ? $foreign_key[$parent_prefix] : $foreign_key;
}
return $fields;
}
/**
* Removes any information about current/selected ids
* from Application variables and Session
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function clearSelectedIDs(kEvent &$event)
+ protected function clearSelectedIDs(kEvent $event)
{
$prefix_special = $event->getPrefixSpecial();
$ids = implode(',', $this->getSelectedIDs($event, true));
$event->setEventParam('ids', $ids);
$wid = $this->Application->GetTopmostWid($event->Prefix);
$session_name = rtrim($prefix_special . '_selected_ids_' . $wid, '_');
$this->Application->RemoveVar($session_name);
$this->Application->SetVar($prefix_special . '_selected_ids', '');
$this->Application->SetVar($prefix_special . '_id', ''); // $event->getPrefixSpecial(true) . '_id' too may be
}
/**
* Common builder part for Item & List
*
* @param kDBBase|kDBItem|kDBList $object
* @param kEvent $event
* @return void
* @access protected
*/
- protected function dbBuild(&$object, kEvent &$event)
+ protected function dbBuild(&$object, kEvent $event)
{
// for permission checking inside item/list build events
$event->setEventParam('top_prefix', $this->Application->GetTopmostPrefix($event->Prefix, true));
if ( $event->getEventParam('form_name') !== false ) {
$form_name = $event->getEventParam('form_name');
}
else {
$request_forms = $this->Application->GetVar('forms', Array ());
$form_name = (string)getArrayValue($request_forms, $object->getPrefixSpecial());
}
$object->Configure($event->getEventParam('populate_ml_fields') || $this->Application->getUnitOption($event->Prefix, 'PopulateMlFields'), $form_name);
$this->PrepareObject($object, $event);
$parent_event = $event->getEventParam('parent_event');
if ( is_object($parent_event) ) {
$object->setParentEvent($parent_event);
}
// force live table if specified or is original item
$live_table = $event->getEventParam('live_table') || $event->Special == 'original';
if ( $this->UseTempTables($event) && !$live_table ) {
$object->SwitchToTemp();
}
$this->Application->setEvent($event->getPrefixSpecial(), '');
$save_event = $this->UseTempTables($event) && $this->Application->GetTopmostPrefix($event->Prefix) == $event->Prefix ? 'OnSave' : 'OnUpdate';
$this->Application->SetVar($event->getPrefixSpecial() . '_SaveEvent', $save_event);
}
/**
* Checks, that currently loaded item is allowed for viewing (non permission-based)
*
* @param kEvent $event
* @return bool
* @access protected
*/
- protected function checkItemStatus(kEvent &$event)
+ protected function checkItemStatus(kEvent $event)
{
$status_fields = $this->Application->getUnitOption($event->Prefix, 'StatusField');
if ( !$status_fields ) {
return true;
}
$status_field = array_shift($status_fields);
if ( $status_field == 'Status' || $status_field == 'Enabled' ) {
$object =& $event->getObject();
/* @var $object kDBItem */
if ( !$object->isLoaded() ) {
return true;
}
return $object->GetDBField($status_field) == STATUS_ACTIVE;
}
return true;
}
/**
* Shows not found template content
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function _errorNotFound(kEvent &$event)
+ protected function _errorNotFound(kEvent $event)
{
if ( $event->getEventParam('raise_warnings') === 0 ) {
// when it's possible, that autoload fails do nothing
return;
}
if ( $this->Application->isDebugMode() ) {
$this->Application->Debugger->appendTrace();
}
trigger_error('ItemLoad Permission Failed for prefix [' . $event->getPrefixSpecial() . '] in <strong>checkItemStatus</strong>, leading to "404 Not Found"', E_USER_NOTICE);
$vars = $this->Application->UrlManager->prepare404();
foreach ($vars as $var_name => $var_value) {
$this->Application->SetVar($var_name, $var_value);
}
// in case if missing item is recalled first from event (not from template)
$this->Application->QuickRun();
$this->Application->Done();
exit;
}
/**
* Builds item (loads if needed)
*
* Pattern: Prototype Manager
*
* @param kEvent $event
* @access protected
*/
- protected function OnItemBuild(kEvent &$event)
+ protected function OnItemBuild(kEvent $event)
{
$object =& $event->getObject();
/* @var $object kDBItem */
$this->dbBuild($object, $event);
$sql = $this->ItemPrepareQuery($event);
$sql = $this->Application->ReplaceLanguageTags($sql);
$object->setSelectSQL($sql);
// 2. loads if allowed
$auto_load = $this->Application->getUnitOption($event->Prefix,'AutoLoad');
$skip_autoload = $event->getEventParam('skip_autoload');
if ( $auto_load && !$skip_autoload ) {
$perm_status = true;
$user_id = $this->Application->InitDone ? $this->Application->RecallVar('user_id') : USER_ROOT;
$event->setEventParam('top_prefix', $this->Application->GetTopmostPrefix($event->Prefix, true));
$status_checked = false;
if ( $user_id == USER_ROOT || $this->CheckPermission($event) ) {
// don't autoload item, when user doesn't have view permission
$this->LoadItem($event);
$status_checked = true;
$editing_mode = defined('EDITING_MODE') ? EDITING_MODE : false;
if ( $user_id != USER_ROOT && !$this->Application->isAdmin && !($editing_mode || $this->checkItemStatus($event)) ) {
// non-root user AND on front-end AND (not editing mode || incorrect status)
$perm_status = false;
}
}
else {
$perm_status = false;
}
if ( !$perm_status ) {
// when no permission to view item -> redirect to no permission template
if ( $this->Application->isDebugMode() ) {
$this->Application->Debugger->appendTrace();
}
trigger_error('ItemLoad Permission Failed for prefix [' . $event->getPrefixSpecial() . '] in <strong>' . ($status_checked ? 'checkItemStatus' : 'CheckPermission') . '</strong>', E_USER_NOTICE);
$template = $this->Application->isAdmin ? 'no_permission' : $this->Application->ConfigValue('NoPermissionTemplate');
if ( $this->Application->GetVar('t') != $template ) {
// don't perform "no_permission" redirect if already on a "no_permission" template
if ( MOD_REWRITE ) {
$redirect_params = Array (
'm_cat_id' => 0,
'next_template' => urlencode('external:' . $_SERVER['REQUEST_URI']),
);
}
else {
$redirect_params = Array (
'next_template' => $this->Application->GetVar('t'),
);
}
$this->Application->Redirect($template, $redirect_params);
}
}
}
$actions =& $this->Application->recallObject('kActions');
/* @var $actions Params */
$actions->Set($event->getPrefixSpecial() . '_GoTab', '');
$actions->Set($event->getPrefixSpecial() . '_GoId', '');
$actions->Set('forms[' . $event->getPrefixSpecial() . ']', $object->getFormName());
}
/**
* Build sub-tables array from configs
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnTempHandlerBuild(kEvent &$event)
+ protected function OnTempHandlerBuild(kEvent $event)
{
$object =& $this->Application->recallObject($event->getPrefixSpecial() . '_TempHandler', 'kTempTablesHandler');
/* @var $object kTempTablesHandler */
$parent_event = $event->getEventParam('parent_event');
if ( is_object($parent_event) ) {
$object->setParentEvent($parent_event);
}
$object->BuildTables($event->Prefix, $this->getSelectedIDs($event));
}
/**
* Checks, that object used in event should use temp tables
*
* @param kEvent $event
* @return bool
* @access protected
*/
- protected function UseTempTables(kEvent &$event)
+ protected function UseTempTables(kEvent $event)
{
$top_prefix = $this->Application->GetTopmostPrefix($event->Prefix); // passed parent, not always actual
$special = ($top_prefix == $event->Prefix) ? $event->Special : $this->getMainSpecial($event);
return $this->Application->IsTempMode($event->Prefix, $special);
}
/**
* Load item if id is available
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function LoadItem(kEvent &$event)
+ protected function LoadItem(kEvent $event)
{
$object =& $event->getObject();
/* @var $object kDBItem */
$id = $this->getPassedID($event);
if ( $object->isLoaded() && !is_array($id) && ($object->GetID() == $id) ) {
// object is already loaded by same id
return ;
}
if ( $object->Load($id) ) {
$actions =& $this->Application->recallObject('kActions');
/* @var $actions Params */
$actions->Set($event->getPrefixSpecial() . '_id', $object->GetID());
}
else {
$object->setID( is_array($id) ? false : $id );
}
}
/**
* Builds list
*
* Pattern: Prototype Manager
*
* @param kEvent $event
* @access protected
*/
- protected function OnListBuild(kEvent &$event)
+ protected function OnListBuild(kEvent $event)
{
$object =& $event->getObject();
/* @var $object kDBList */
/*if ( $this->Application->isDebugMode() ) {
$event_params = http_build_query($event->getEventParams());
$this->Application->Debugger->appendHTML('InitList "<strong>' . $event->getPrefixSpecial() . '</strong>" (' . $event_params . ')');
}*/
$this->dbBuild($object, $event);
if ( !$object->isMainList() && $event->getEventParam('main_list') ) {
// once list is set to main, then even "requery" parameter can't remove that
/*$passed = $this->Application->GetVar('passed');
$this->Application->SetVar('passed', $passed . ',' . $event->Prefix);*/
$object->becameMain();
}
$object->setGridName($event->getEventParam('grid'));
$sql = $this->ListPrepareQuery($event);
$sql = $this->Application->ReplaceLanguageTags($sql);
$object->setSelectSQL($sql);
$object->reset();
if ( $event->getEventParam('skip_parent_filter') === false ) {
$object->linkToParent($this->getMainSpecial($event));
}
$this->AddFilters($event);
$this->SetCustomQuery($event); // new!, use this for dynamic queries based on specials for ex.
$this->SetPagination($event);
$this->SetSorting($event);
$actions =& $this->Application->recallObject('kActions');
/* @var $actions Params */
$actions->Set('remove_specials[' . $event->getPrefixSpecial() . ']', '0');
$actions->Set($event->getPrefixSpecial() . '_GoTab', '');
}
/**
* Returns special of main item for linking with sub-item
*
* @param kEvent $event
* @return string
* @access protected
*/
- protected function getMainSpecial(kEvent &$event)
+ protected function getMainSpecial(kEvent $event)
{
$main_special = $event->getEventParam('main_special');
if ( $main_special === false ) {
// main item's special not passed
if ( substr($event->Special, -5) == '-item' ) {
// temp handler added "-item" to given special -> process that here
return substr($event->Special, 0, -5);
}
// by default subitem's special is used for main item searching
return $event->Special;
}
return $main_special;
}
/**
* Apply any custom changes to list's sql query
*
* @param kEvent $event
* @return void
* @access protected
* @see kDBEventHandler::OnListBuild()
*/
- protected function SetCustomQuery(kEvent &$event)
+ protected function SetCustomQuery(kEvent $event)
{
}
/**
* Set's new per-page for grid
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnSetPerPage(kEvent &$event)
+ protected function OnSetPerPage(kEvent $event)
{
$per_page = $this->Application->GetVar($event->getPrefixSpecial(true) . '_PerPage');
$event->SetRedirectParam($event->getPrefixSpecial() . '_PerPage', $per_page);
$event->SetRedirectParam('pass', 'all,' . $event->getPrefixSpecial());
if ( !$this->Application->isAdminUser ) {
$list_helper =& $this->Application->recallObject('ListHelper');
/* @var $list_helper ListHelper */
$this->_passListParams($event, 'per_page');
}
}
/**
* Occurs when page is changed (only for hooking)
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnSetPage(kEvent &$event)
+ protected function OnSetPage(kEvent $event)
{
$page = $this->Application->GetVar($event->getPrefixSpecial(true) . '_Page');
$event->SetRedirectParam($event->getPrefixSpecial() . '_Page', $page);
$event->SetRedirectParam('pass', 'all,' . $event->getPrefixSpecial());
if ( !$this->Application->isAdminUser ) {
$this->_passListParams($event, 'page');
}
}
/**
* Passes through main list pagination and sorting
*
* @param kEvent $event
* @param string $skip_var
* @return void
* @access protected
*/
- protected function _passListParams(&$event, $skip_var)
+ protected function _passListParams($event, $skip_var)
{
$param_names = array_diff(Array ('page', 'per_page', 'sort_by'), Array ($skip_var));
$list_helper =& $this->Application->recallObject('ListHelper');
/* @var $list_helper ListHelper */
foreach ($param_names as $param_name) {
$value = $this->Application->GetVar($param_name);
switch ($param_name) {
case 'page':
if ( $value > 1 ) {
$event->SetRedirectParam('page', $value);
}
break;
case 'per_page':
if ( $value > 0 ) {
if ( $value != $list_helper->getDefaultPerPage($event->Prefix) ) {
$event->SetRedirectParam('per_page', $value);
}
}
break;
case 'sort_by':
$event->setPseudoClass('_List');
$object =& $event->getObject(Array ('main_list' => 1));
/* @var $object kDBList */
if ( $list_helper->hasUserSorting($object) ) {
$event->SetRedirectParam('sort_by', $value);
}
break;
}
}
}
/**
* Set's correct page for list based on data provided with event
*
* @param kEvent $event
* @return void
* @access protected
* @see kDBEventHandler::OnListBuild()
*/
- protected function SetPagination(kEvent &$event)
+ protected function SetPagination(kEvent $event)
{
$object =& $event->getObject();
/* @var $object kDBList */
// get PerPage (forced -> session -> config -> 10)
$object->SetPerPage($this->getPerPage($event));
// main lists on Front-End have special get parameter for page
$page = $object->isMainList() ? $this->Application->GetVar('page') : false;
if ( !$page ) {
// page is given in "env" variable for given prefix
$page = $this->Application->GetVar($event->getPrefixSpecial() . '_Page');
}
if ( !$page && $event->Special ) {
// when not part of env, then variables like "prefix.special_Page" are
// replaced (by PHP) with "prefix_special_Page", so check for that too
$page = $this->Application->GetVar($event->getPrefixSpecial(true) . '_Page');
}
if ( !$object->isMainList() ) {
// main lists doesn't use session for page storing
$this->Application->StoreVarDefault($event->getPrefixSpecial() . '_Page', 1, true); // true for optional
if ( $page ) {
// page found in request -> store in session
$this->Application->StoreVar($event->getPrefixSpecial() . '_Page', $page, true); //true for optional
}
else {
// page not found in request -> get from session
$page = $this->Application->RecallVar($event->getPrefixSpecial() . '_Page');
}
if ( !$event->getEventParam('skip_counting') ) {
// when stored page is larger, then maximal list page number
// (such case is also processed in kDBList::Query method)
$pages = $object->GetTotalPages();
if ( $page > $pages ) {
$page = 1;
$this->Application->StoreVar($event->getPrefixSpecial() . '_Page', 1, true);
}
}
}
$object->SetPage($page);
}
/**
* Returns current per-page setting for list
*
* @param kEvent $event
* @return int
* @access protected
*/
- protected function getPerPage(kEvent &$event)
+ protected function getPerPage(kEvent $event)
{
$object =& $event->getObject();
/* @var $object kDBList */
$per_page = $event->getEventParam('per_page');
if ( $per_page ) {
// per-page is passed as tag parameter to PrintList, InitList, etc.
$config_mapping = $this->Application->getUnitOption($event->Prefix, 'ConfigMapping');
// 2. per-page setting is stored in configuration variable
if ( $config_mapping ) {
// such pseudo per-pages are only defined in templates directly
switch ($per_page) {
case 'short_list':
$per_page = $this->Application->ConfigValue($config_mapping['ShortListPerPage']);
break;
case 'default':
$per_page = $this->Application->ConfigValue($config_mapping['PerPage']);
break;
}
}
return $per_page;
}
if ( !$per_page && $object->isMainList() ) {
// main lists on Front-End have special get parameter for per-page
$per_page = $this->Application->GetVar('per_page');
}
if ( !$per_page ) {
// per-page is given in "env" variable for given prefix
$per_page = $this->Application->GetVar($event->getPrefixSpecial() . '_PerPage');
}
if ( !$per_page && $event->Special ) {
// when not part of env, then variables like "prefix.special_PerPage" are
// replaced (by PHP) with "prefix_special_PerPage", so check for that too
$per_page = $this->Application->GetVar($event->getPrefixSpecial(true) . '_PerPage');
}
if ( !$object->isMainList() ) {
// per-page given in env and not in main list
$view_name = $this->Application->RecallVar($event->getPrefixSpecial() . '_current_view');
if ( $per_page ) {
// per-page found in request -> store in session and persistent session
$this->setListSetting($event, 'PerPage', $per_page);
}
else {
// per-page not found in request -> get from pesistent session (or session)
$per_page = $this->getListSetting($event, 'PerPage');
}
}
if ( !$per_page ) {
// per page wan't found in request/session/persistent session
$list_helper =& $this->Application->recallObject('ListHelper');
/* @var $list_helper ListHelper */
// allow to override default per-page value from tag
$default_per_page = $event->getEventParam('default_per_page');
if ( !is_numeric($default_per_page) ) {
$default_per_page = $this->Application->ConfigValue('DefaultGridPerPage');
}
$per_page = $list_helper->getDefaultPerPage($event->Prefix, $default_per_page);
}
return $per_page;
}
/**
* Set's correct sorting for list based on data provided with event
*
* @param kEvent $event
* @return void
* @access protected
* @see kDBEventHandler::OnListBuild()
*/
- protected function SetSorting(kEvent &$event)
+ protected function SetSorting(kEvent $event)
{
$event->setPseudoClass('_List');
$object =& $event->getObject();
/* @var $object kDBList */
if ( $object->isMainList() ) {
$sort_by = $this->Application->GetVar('sort_by');
$cur_sort1 = $cur_sort1_dir = $cur_sort2 = $cur_sort2_dir = false;
if ( $sort_by ) {
list ($cur_sort1, $cur_sort1_dir) = explode(',', $sort_by);
}
}
else {
$sorting_settings = $this->getListSetting($event, 'Sortings');
$cur_sort1 = getArrayValue($sorting_settings, 'Sort1');
$cur_sort1_dir = getArrayValue($sorting_settings, 'Sort1_Dir');
$cur_sort2 = getArrayValue($sorting_settings, 'Sort2');
$cur_sort2_dir = getArrayValue($sorting_settings, 'Sort2_Dir');
}
$tag_sort_by = $event->getEventParam('sort_by');
if ( $tag_sort_by ) {
if ( $tag_sort_by == 'random' ) {
$object->AddOrderField('RAND()', '');
}
else {
// multiple sortings could be specified at once
$tag_sort_by = explode('|', $tag_sort_by);
foreach ($tag_sort_by as $sorting_element) {
list ($by, $dir) = explode(',', $sorting_element);
$object->AddOrderField($by, $dir);
}
}
}
$list_sortings = $this->Application->getUnitOption($event->Prefix, 'ListSortings', Array ());
$sorting_prefix = array_key_exists($event->Special, $list_sortings) ? $event->Special : '';
$sorting_configs = $this->Application->getUnitOption($event->Prefix, 'ConfigMapping');
if ( $sorting_configs && array_key_exists('DefaultSorting1Field', $sorting_configs) ) {
// sorting defined in configuration variables overrides one from unit config
$list_sortings[$sorting_prefix]['Sorting'] = Array (
$this->Application->ConfigValue($sorting_configs['DefaultSorting1Field']) => $this->Application->ConfigValue($sorting_configs['DefaultSorting1Dir']),
$this->Application->ConfigValue($sorting_configs['DefaultSorting2Field']) => $this->Application->ConfigValue($sorting_configs['DefaultSorting2Dir']),
);
// TODO: lowercase configuration variable values in db, instead of here
$list_sortings[$sorting_prefix]['Sorting'] = array_map('strtolower', $list_sortings[$sorting_prefix]['Sorting']);
}
// use default if not specified in session
if ( !$cur_sort1 || !$cur_sort1_dir ) {
$sorting = getArrayValue($list_sortings, $sorting_prefix, 'Sorting');
if ( $sorting ) {
reset($sorting);
$cur_sort1 = key($sorting);
$cur_sort1_dir = current($sorting);
if ( next($sorting) ) {
$cur_sort2 = key($sorting);
$cur_sort2_dir = current($sorting);
}
}
}
// always add forced sorting before any user sorting fields
$forced_sorting = getArrayValue($list_sortings, $sorting_prefix, 'ForcedSorting');
/* @var $forced_sorting Array */
if ( $forced_sorting ) {
foreach ($forced_sorting as $field => $dir) {
$object->AddOrderField($field, $dir);
}
}
// add user sorting fields
if ( $cur_sort1 != '' && $cur_sort1_dir != '' ) {
$object->AddOrderField($cur_sort1, $cur_sort1_dir);
}
if ( $cur_sort2 != '' && $cur_sort2_dir != '' ) {
$object->AddOrderField($cur_sort2, $cur_sort2_dir);
}
}
/**
* Gets list setting by name (persistent or real session)
*
* @param kEvent $event
* @param string $variable_name
* @return string|Array
* @access protected
*/
- protected function getListSetting(kEvent &$event, $variable_name)
+ protected function getListSetting(kEvent $event, $variable_name)
{
$view_name = $this->Application->RecallVar($event->getPrefixSpecial() . '_current_view');
$storage_prefix = $event->getEventParam('same_special') ? $event->Prefix : $event->getPrefixSpecial();
// get sorting from persistent session
$variable_value = $this->Application->RecallPersistentVar($storage_prefix . '_' . $variable_name . '.' . $view_name, ALLOW_DEFAULT_SETTINGS);
/*if ( !$variable_value ) {
// get sorting from session
$variable_value = $this->Application->RecallVar($storage_prefix . '_' . $variable_name);
}*/
if ( kUtil::IsSerialized($variable_value) ) {
$variable_value = unserialize($variable_value);
}
return $variable_value;
}
/**
* Sets list setting by name (persistent and real session)
*
* @param kEvent $event
* @param string $variable_name
* @param string|Array $variable_value
* @return void
* @access protected
*/
- protected function setListSetting(kEvent &$event, $variable_name, $variable_value = null)
+ protected function setListSetting(kEvent $event, $variable_name, $variable_value = null)
{
$view_name = $this->Application->RecallVar($event->getPrefixSpecial() . '_current_view');
// $this->Application->StoreVar($event->getPrefixSpecial() . '_' . $variable_name, $variable_value, true); //true for optional
if ( isset($variable_value) ) {
if ( is_array($variable_value) ) {
$variable_value = serialize($variable_value);
}
$this->Application->StorePersistentVar($event->getPrefixSpecial() . '_' . $variable_name . '.' . $view_name, $variable_value, true); //true for optional
}
else {
$this->Application->RemovePersistentVar($event->getPrefixSpecial() . '_' . $variable_name . '.' . $view_name);
}
}
/**
* Add filters found in session
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function AddFilters(kEvent &$event)
+ protected function AddFilters(kEvent $event)
{
$object =& $event->getObject();
/* @var $object kDBList */
$edit_mark = rtrim($this->Application->GetSID() . '_' . $this->Application->GetTopmostWid($event->Prefix), '_');
// add search filter
$filter_data = $this->Application->RecallVar($event->getPrefixSpecial() . '_search_filter');
if ( $filter_data ) {
$filter_data = unserialize($filter_data);
foreach ($filter_data as $filter_field => $filter_params) {
$filter_type = ($filter_params['type'] == 'having') ? kDBList::HAVING_FILTER : kDBList::WHERE_FILTER;
$filter_value = str_replace(EDIT_MARK, $edit_mark, $filter_params['value']);
$object->addFilter($filter_field, $filter_value, $filter_type, kDBList::FLT_SEARCH);
}
}
// add custom filter
$view_name = $this->Application->RecallVar($event->getPrefixSpecial() . '_current_view');
$custom_filters = $this->Application->RecallPersistentVar($event->getPrefixSpecial() . '_custom_filter.' . $view_name);
if ( $custom_filters ) {
$grid_name = $event->getEventParam('grid');
$custom_filters = unserialize($custom_filters);
if ( isset($custom_filters[$grid_name]) ) {
foreach ($custom_filters[$grid_name] as $field_name => $field_options) {
list ($filter_type, $field_options) = each($field_options);
if ( isset($field_options['value']) && $field_options['value'] ) {
$filter_type = ($field_options['sql_filter_type'] == 'having') ? kDBList::HAVING_FILTER : kDBList::WHERE_FILTER;
$filter_value = str_replace(EDIT_MARK, $edit_mark, $field_options['value']);
$object->addFilter($field_name, $filter_value, $filter_type, kDBList::FLT_CUSTOM);
}
}
}
}
// add view filter
$view_filter = $this->Application->RecallVar($event->getPrefixSpecial() . '_view_filter');
if ( $view_filter ) {
$view_filter = unserialize($view_filter);
$temp_filter =& $this->Application->makeClass('kMultipleFilter');
/* @var $temp_filter kMultipleFilter */
$filter_menu = $this->Application->getUnitOption($event->Prefix, 'FilterMenu');
$group_key = 0;
$group_count = count($filter_menu['Groups']);
while ($group_key < $group_count) {
$group_info = $filter_menu['Groups'][$group_key];
$temp_filter->setType(constant('kDBList::FLT_TYPE_' . $group_info['mode']));
$temp_filter->clearFilters();
foreach ($group_info['filters'] as $flt_id) {
$sql_key = getArrayValue($view_filter, $flt_id) ? 'on_sql' : 'off_sql';
if ( $filter_menu['Filters'][$flt_id][$sql_key] != '' ) {
$temp_filter->addFilter('view_filter_' . $flt_id, $filter_menu['Filters'][$flt_id][$sql_key]);
}
}
$object->addFilter('view_group_' . $group_key, $temp_filter, $group_info['type'], kDBList::FLT_VIEW);
$group_key++;
}
}
// add item filter
if ( $object->isMainList() ) {
$this->applyItemFilters($event);
}
}
/**
* Applies item filters
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function applyItemFilters(&$event)
+ protected function applyItemFilters($event)
{
$filter_values = $this->Application->GetVar('filters', Array ());
if ( !$filter_values ) {
return;
}
$object =& $event->getObject();
/* @var $object kDBList */
$where_clause = Array (
'ItemPrefix = ' . $this->Conn->qstr($object->Prefix),
'FilterField IN (' . implode(',', $this->Conn->qstrArray(array_keys($filter_values))) . ')',
'Enabled = 1',
);
$sql = 'SELECT *
FROM ' . $this->Application->getUnitOption('item-filter', 'TableName') . '
WHERE (' . implode(') AND (', $where_clause) . ')';
$filters = $this->Conn->Query($sql, 'FilterField');
foreach ($filters as $filter_field => $filter_data) {
$filter_value = $filter_values[$filter_field];
if ( "$filter_value" === '' ) {
// ListManager don't pass empty values, but check here just in case
continue;
}
$table_name = $object->isVirtualField($filter_field) ? '' : '%1$s.';
switch ($filter_data['FilterType']) {
case 'radio':
$filter_value = $table_name . '`' . $filter_field . '` = ' . $this->Conn->qstr($filter_value);
break;
case 'checkbox':
$filter_value = explode('|', substr($filter_value, 1, -1));
$filter_value = $this->Conn->qstrArray($filter_value, 'escape');
if ( $object->GetFieldOption($filter_field, 'multiple') ) {
$filter_value = $table_name . '`' . $filter_field . '` LIKE "%|' . implode('|%" OR ' . $table_name . '`' . $filter_field . '` LIKE "%|', $filter_value) . '|%"';
}
else {
$filter_value = $table_name . '`' . $filter_field . '` IN (' . implode(',', $filter_value) . ')';
}
break;
case 'range':
$filter_value = $this->Conn->qstrArray(explode('-', $filter_value));
$filter_value = $table_name . '`' . $filter_field . '` BETWEEN ' . $filter_value[0] . ' AND ' . $filter_value[1];
break;
}
$object->addFilter('item_filter_' . $filter_field, $filter_value, $object->isVirtualField($filter_field) ? kDBList::HAVING_FILTER : kDBList::WHERE_FILTER);
}
}
/**
* Set's new sorting for list
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnSetSorting(kEvent &$event)
+ protected function OnSetSorting(kEvent $event)
{
$sorting_settings = $this->getListSetting($event, 'Sortings');
$cur_sort1 = getArrayValue($sorting_settings, 'Sort1');
$cur_sort1_dir = getArrayValue($sorting_settings, 'Sort1_Dir');
$use_double_sorting = $this->Application->ConfigValue('UseDoubleSorting');
if ( $use_double_sorting ) {
$cur_sort2 = getArrayValue($sorting_settings, 'Sort2');
$cur_sort2_dir = getArrayValue($sorting_settings, 'Sort2_Dir');
}
$passed_sort1 = $this->Application->GetVar($event->getPrefixSpecial(true) . '_Sort1');
if ( $cur_sort1 == $passed_sort1 ) {
$cur_sort1_dir = $cur_sort1_dir == 'asc' ? 'desc' : 'asc';
}
else {
if ( $use_double_sorting ) {
$cur_sort2 = $cur_sort1;
$cur_sort2_dir = $cur_sort1_dir;
}
$cur_sort1 = $passed_sort1;
$cur_sort1_dir = 'asc';
}
$sorting_settings = Array ('Sort1' => $cur_sort1, 'Sort1_Dir' => $cur_sort1_dir);
if ( $use_double_sorting ) {
$sorting_settings['Sort2'] = $cur_sort2;
$sorting_settings['Sort2_Dir'] = $cur_sort2_dir;
}
$this->setListSetting($event, 'Sortings', $sorting_settings);
}
/**
* Set sorting directly to session (used for category item sorting (front-end), grid sorting (admin, view menu)
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnSetSortingDirect(kEvent &$event)
+ protected function OnSetSortingDirect(kEvent $event)
{
// used on Front-End in category item lists
$prefix_special = $event->getPrefixSpecial();
$combined = $this->Application->GetVar($event->getPrefixSpecial(true) . '_CombinedSorting');
if ( $combined ) {
list ($field, $dir) = explode('|', $combined);
if ( $this->Application->isAdmin || !$this->Application->GetVar('main_list') ) {
$this->setListSetting($event, 'Sortings', Array ('Sort1' => $field, 'Sort1_Dir' => $dir));
}
else {
$event->setPseudoClass('_List');
$this->Application->SetVar('sort_by', $field . ',' . $dir);
$object =& $event->getObject(Array ('main_list' => 1));
/* @var $object kDBList */
$list_helper =& $this->Application->recallObject('ListHelper');
/* @var $list_helper ListHelper */
$this->_passListParams($event, 'sort_by');
if ( $list_helper->hasUserSorting($object) ) {
$event->SetRedirectParam('sort_by', $field . ',' . strtolower($dir));
}
$event->SetRedirectParam('pass', 'm');
}
return;
}
// used in "View Menu -> Sort" menu in administrative console
$field_pos = $this->Application->GetVar($event->getPrefixSpecial(true) . '_SortPos');
$this->Application->LinkVar($event->getPrefixSpecial(true) . '_Sort' . $field_pos, $prefix_special . '_Sort' . $field_pos);
$this->Application->LinkVar($event->getPrefixSpecial(true) . '_Sort' . $field_pos . '_Dir', $prefix_special . '_Sort' . $field_pos . '_Dir');
}
/**
* Reset grid sorting to default (from config)
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnResetSorting(kEvent &$event)
+ protected function OnResetSorting(kEvent $event)
{
$this->setListSetting($event, 'Sortings');
}
/**
* Sets grid refresh interval
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnSetAutoRefreshInterval(kEvent &$event)
+ protected function OnSetAutoRefreshInterval(kEvent $event)
{
$refresh_interval = $this->Application->GetVar('refresh_interval');
$view_name = $this->Application->RecallVar($event->getPrefixSpecial() . '_current_view');
$this->Application->StorePersistentVar($event->getPrefixSpecial() . '_refresh_interval.' . $view_name, $refresh_interval);
}
/**
* Changes auto-refresh state for grid
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnAutoRefreshToggle(kEvent &$event)
+ protected function OnAutoRefreshToggle(kEvent $event)
{
$refresh_intervals = $this->Application->ConfigValue('AutoRefreshIntervals');
if ( !$refresh_intervals ) {
return;
}
$view_name = $this->Application->RecallVar($event->getPrefixSpecial() . '_current_view');
$auto_refresh = $this->Application->RecallPersistentVar($event->getPrefixSpecial() . '_auto_refresh.' . $view_name);
if ( $auto_refresh === false ) {
$refresh_intervals = explode(',', $refresh_intervals);
$this->Application->StorePersistentVar($event->getPrefixSpecial() . '_refresh_interval.' . $view_name, $refresh_intervals[0]);
}
$this->Application->StorePersistentVar($event->getPrefixSpecial() . '_auto_refresh.' . $view_name, $auto_refresh ? 0 : 1);
}
/**
* Creates needed sql query to load item,
* if no query is defined in config for
* special requested, then use list query
*
* @param kEvent $event
* @return string
* @access protected
*/
- protected function ItemPrepareQuery(kEvent &$event)
+ protected function ItemPrepareQuery(kEvent $event)
{
$object =& $event->getObject();
/* @var $object kDBItem */
$sqls = $object->getFormOption('ItemSQLs', Array ());
$special = isset($sqls[$event->Special]) ? $event->Special : '';
// preferred special not found in ItemSQLs -> use analog from ListSQLs
return isset($sqls[$special]) ? $sqls[$special] : $this->ListPrepareQuery($event);
}
/**
* Creates needed sql query to load list,
* if no query is defined in config for
* special requested, then use default
* query
*
* @param kEvent $event
* @return string
* @access protected
*/
- protected function ListPrepareQuery(kEvent &$event)
+ protected function ListPrepareQuery(kEvent $event)
{
$object =& $event->getObject();
/* @var $object kDBItem */
$sqls = $object->getFormOption('ListSQLs', Array ());
return $sqls[array_key_exists($event->Special, $sqls) ? $event->Special : ''];
}
/**
* Apply custom processing to item
*
* @param kEvent $event
* @param string $type
* @return void
* @access protected
*/
- protected function customProcessing(kEvent &$event, $type)
+ protected function customProcessing(kEvent $event, $type)
{
}
/* Edit Events mostly used in Admin */
/**
* Creates new kDBItem
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnCreate(kEvent &$event)
+ protected function OnCreate(kEvent $event)
{
$object =& $event->getObject(Array ('skip_autoload' => true));
/* @var $object kDBItem */
$items_info = $this->Application->GetVar($event->getPrefixSpecial(true));
if ( !$items_info ) {
return;
}
list($id, $field_values) = each($items_info);
$object->SetFieldsFromHash($field_values, $this->getRequestProtectedFields($field_values));
$this->customProcessing($event, 'before');
// look at kDBItem' Create for ForceCreateId description, it's rarely used and is NOT set by default
if ( $object->Create($event->getEventParam('ForceCreateId')) ) {
$this->customProcessing($event, 'after');
$event->SetRedirectParam('opener', 'u');
return;
}
$event->redirect = false;
$event->status = kEvent::erFAIL;
$this->Application->SetVar($event->getPrefixSpecial() . '_SaveEvent', 'OnCreate');
$object->setID($id);
}
/**
* Updates kDBItem
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnUpdate(kEvent &$event)
+ protected function OnUpdate(kEvent $event)
{
if ( $this->Application->CheckPermission('SYSTEM_ACCESS.READONLY', 1) ) {
$event->status = kEvent::erFAIL;
return;
}
$this->_update($event);
$event->SetRedirectParam('opener', 'u');
}
/**
* Updates data in database based on request
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function _update(kEvent &$event)
+ protected function _update(kEvent $event)
{
$object =& $event->getObject(Array ('skip_autoload' => true));
/* @var $object kDBItem */
$items_info = $this->Application->GetVar( $event->getPrefixSpecial(true) );
if ( $items_info ) {
foreach ($items_info as $id => $field_values) {
$object->Load($id);
$object->SetFieldsFromHash($field_values, $this->getRequestProtectedFields($field_values));
$this->customProcessing($event, 'before');
if ( $object->Update($id) ) {
$this->customProcessing($event, 'after');
$event->status = kEvent::erSUCCESS;
}
else {
$event->status = kEvent::erFAIL;
$event->redirect = false;
break;
}
}
}
}
/**
* Delete's kDBItem object
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnDelete(kEvent &$event)
+ protected function OnDelete(kEvent $event)
{
if ( $this->Application->CheckPermission('SYSTEM_ACCESS.READONLY', 1) ) {
$event->status = kEvent::erFAIL;
return;
}
- $temp_handler =& $this->Application->recallObject($event->getPrefixSpecial() . '_TempHandler', 'kTempTablesHandler', Array ('parent_event' => &$event));
+ $temp_handler =& $this->Application->recallObject($event->getPrefixSpecial() . '_TempHandler', 'kTempTablesHandler', Array ('parent_event' => $event));
/* @var $temp_handler kTempTablesHandler */
$temp_handler->DeleteItems($event->Prefix, $event->Special, Array ($this->getPassedID($event)));
}
/**
* Deletes all records from table
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnDeleteAll(kEvent &$event)
+ protected function OnDeleteAll(kEvent $event)
{
$sql = 'SELECT ' . $this->Application->getUnitOption($event->Prefix, 'IDField') . '
FROM ' . $this->Application->getUnitOption($event->Prefix, 'TableName');
$ids = $this->Conn->GetCol($sql);
if ( $ids ) {
- $temp_handler =& $this->Application->recallObject($event->getPrefixSpecial() . '_TempHandler', 'kTempTablesHandler', Array ('parent_event' => &$event));
+ $temp_handler =& $this->Application->recallObject($event->getPrefixSpecial() . '_TempHandler', 'kTempTablesHandler', Array ('parent_event' => $event));
/* @var $temp_handler kTempTablesHandler */
$temp_handler->DeleteItems($event->Prefix, $event->Special, $ids);
}
}
/**
* Prepares new kDBItem object
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnNew(kEvent &$event)
+ protected function OnNew(kEvent $event)
{
$object =& $event->getObject(Array ('skip_autoload' => true));
/* @var $object kDBItem */
$object->Clear(0);
$this->Application->SetVar($event->getPrefixSpecial() . '_SaveEvent', 'OnCreate');
if ( $event->getEventParam('top_prefix') != $event->Prefix ) {
// this is subitem prefix, so use main item special
$table_info = $object->getLinkedInfo($this->getMainSpecial($event));
}
else {
$table_info = $object->getLinkedInfo();
}
$object->SetDBField($table_info['ForeignKey'], $table_info['ParentId']);
$event->redirect = false;
}
/**
* Cancels kDBItem Editing/Creation
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnCancel(kEvent &$event)
+ protected function OnCancel(kEvent $event)
{
$object =& $event->getObject(Array ('skip_autoload' => true));
/* @var $object kDBItem */
$items_info = $this->Application->GetVar($event->getPrefixSpecial(true));
if ( $items_info ) {
$delete_ids = Array ();
- $temp_handler =& $this->Application->recallObject($event->getPrefixSpecial() . '_TempHandler', 'kTempTablesHandler', Array ('parent_event' => &$event));
+ $temp_handler =& $this->Application->recallObject($event->getPrefixSpecial() . '_TempHandler', 'kTempTablesHandler', Array ('parent_event' => $event));
/* @var $temp_handler kTempTablesHandler */
foreach ($items_info as $id => $field_values) {
$object->Load($id);
// record created for using with selector (e.g. Reviews->Select User), and not validated => Delete it
if ( $object->isLoaded() && !$object->Validate() && ($id <= 0) ) {
$delete_ids[] = $id;
}
}
if ( $delete_ids ) {
$temp_handler->DeleteItems($event->Prefix, $event->Special, $delete_ids);
}
}
$event->SetRedirectParam('opener', 'u');
}
/**
* 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(kEvent &$event)
+ protected function OnMassDelete(kEvent $event)
{
if ( $this->Application->CheckPermission('SYSTEM_ACCESS.READONLY', 1) ) {
$event->status = kEvent::erFAIL;
return ;
}
- $temp_handler =& $this->Application->recallObject($event->getPrefixSpecial() . '_TempHandler', 'kTempTablesHandler', Array ('parent_event' => &$event));
+ $temp_handler =& $this->Application->recallObject($event->getPrefixSpecial() . '_TempHandler', 'kTempTablesHandler', Array ('parent_event' => $event));
/* @var $temp_handler kTempTablesHandler */
$ids = $this->StoreSelectedIDs($event);
$event->setEventParam('ids', $ids);
$this->customProcessing($event, 'before');
$ids = $event->getEventParam('ids');
if ( $ids ) {
$temp_handler->DeleteItems($event->Prefix, $event->Special, $ids);
}
$this->clearSelectedIDs($event);
}
/**
* Sets window id (of first opened edit window) to temp mark in uls
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function setTempWindowID(kEvent &$event)
+ protected function setTempWindowID(kEvent $event)
{
$prefixes = Array ($event->Prefix, $event->getPrefixSpecial(true));
foreach ($prefixes as $prefix) {
$mode = $this->Application->GetVar($prefix . '_mode');
if ($mode == 't') {
$wid = $this->Application->GetVar('m_wid');
$this->Application->SetVar(str_replace('_', '.', $prefix) . '_mode', 't' . $wid);
break;
}
}
}
/**
* Prepare temp tables and populate it
* with items selected in the grid
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnEdit(kEvent &$event)
+ protected function OnEdit(kEvent $event)
{
$this->setTempWindowID($event);
$ids = $this->StoreSelectedIDs($event);
$this->Application->RemoveVar($this->_getPendingActionVariableName($event));
$changes_var_name = $this->Prefix . '_changes_' . $this->Application->GetTopmostWid($this->Prefix);
$this->Application->RemoveVar($changes_var_name);
- $temp_handler =& $this->Application->recallObject($event->getPrefixSpecial() . '_TempHandler', 'kTempTablesHandler', Array ('parent_event' => &$event));
+ $temp_handler =& $this->Application->recallObject($event->getPrefixSpecial() . '_TempHandler', 'kTempTablesHandler', Array ('parent_event' => $event));
/* @var $temp_handler kTempTablesHandler */
$temp_handler->PrepareEdit();
$event->SetRedirectParam('m_lang', $this->Application->GetDefaultLanguageId());
$event->SetRedirectParam($event->getPrefixSpecial() . '_id', array_shift($ids));
$event->SetRedirectParam('pass', 'all,' . $event->getPrefixSpecial());
}
/**
* 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(kEvent &$event)
+ protected function OnSave(kEvent $event)
{
$event->CallSubEvent('OnPreSave');
if ( $event->status != kEvent::erSUCCESS ) {
return;
}
$skip_master = false;
- $temp_handler =& $this->Application->recallObject($event->getPrefixSpecial() . '_TempHandler', 'kTempTablesHandler', Array ('parent_event' => &$event));
+ $temp_handler =& $this->Application->recallObject($event->getPrefixSpecial() . '_TempHandler', 'kTempTablesHandler', Array ('parent_event' => $event));
/* @var $temp_handler kTempTablesHandler */
$changes_var_name = $this->Prefix . '_changes_' . $this->Application->GetTopmostWid($this->Prefix);
if ( !$this->Application->CheckPermission('SYSTEM_ACCESS.READONLY', 1) ) {
$live_ids = $temp_handler->SaveEdit($event->getEventParam('master_ids') ? $event->getEventParam('master_ids') : Array ());
if ( $live_ids === false ) {
// coping from table failed, because we have another coping process to same table, that wasn't finished
$event->status = kEvent::erFAIL;
return;
}
if ( $live_ids ) {
// ensure, that newly created item ids are available as if they were selected from grid
// NOTE: only works if main item has sub-items !!!
$this->StoreSelectedIDs($event, $live_ids);
}
$object =& $event->getObject();
/* @var $object kDBItem */
$this->SaveLoggedChanges($changes_var_name, $object->ShouldLogChanges());
}
else {
$event->status = kEvent::erFAIL;
}
$this->clearSelectedIDs($event);
$event->SetRedirectParam('opener', 'u');
$this->Application->RemoveVar($event->getPrefixSpecial() . '_modified');
// all temp tables are deleted here => all after hooks should think, that it's live mode now
$this->Application->SetVar($event->Prefix . '_mode', '');
}
/**
* Saves changes made in temporary table to log
*
* @param string $changes_var_name
* @param bool $save
* @return void
* @access public
*/
public function SaveLoggedChanges($changes_var_name, $save = true)
{
// 1. get changes, that were made
$changes = $this->Application->RecallVar($changes_var_name);
$changes = $changes ? unserialize($changes) : Array ();
$this->Application->RemoveVar($changes_var_name);
if (!$changes) {
// no changes, skip processing
return ;
}
// TODO: 2. optimize change log records (replace multiple changes to same record with one change record)
$to_increment = Array ();
// 3. collect serials to reset based on foreign keys
foreach ($changes as $index => $rec) {
if (array_key_exists('DependentFields', $rec)) {
foreach ($rec['DependentFields'] as $field_name => $field_value) {
// will be "ci|ItemResourceId:345"
$to_increment[] = $rec['Prefix'] . '|' . $field_name . ':' . $field_value;
// also reset sub-item prefix general serial
$to_increment[] = $rec['Prefix'];
}
unset($changes[$index]['DependentFields']);
}
unset($changes[$index]['ParentId'], $changes[$index]['ParentPrefix']);
}
// 4. collect serials to reset based on changed ids
foreach ($changes as $change) {
$to_increment[] = $change['MasterPrefix'] . '|' . $change['MasterId'];
if ($change['MasterPrefix'] != $change['Prefix']) {
// also reset sub-item prefix general serial
$to_increment[] = $change['Prefix'];
// will be "ci|ItemResourceId"
$to_increment[] = $change['Prefix'] . '|' . $change['ItemId'];
}
}
// 5. reset serials collected before
$to_increment = array_unique($to_increment);
$this->Application->incrementCacheSerial($this->Prefix);
foreach ($to_increment as $to_increment_mixed) {
if (strpos($to_increment_mixed, '|') !== false) {
list ($to_increment_prefix, $to_increment_id) = explode('|', $to_increment_mixed, 2);
$this->Application->incrementCacheSerial($to_increment_prefix, $to_increment_id);
}
else {
$this->Application->incrementCacheSerial($to_increment_mixed);
}
}
// save changes to database
$sesion_log_id = $this->Application->RecallVar('_SessionLogId_');
if (!$save || !$sesion_log_id) {
// saving changes to database disabled OR related session log missing
return ;
}
$add_fields = Array (
'PortalUserId' => $this->Application->RecallVar('user_id'),
'SessionLogId' => $sesion_log_id,
);
$change_log_table = $this->Application->getUnitOption('change-log', 'TableName');
foreach ($changes as $rec) {
$this->Conn->doInsert(array_merge($rec, $add_fields), $change_log_table);
}
$this->Application->incrementCacheSerial('change-log');
$sql = 'UPDATE ' . $this->Application->getUnitOption('session-log', 'TableName') . '
SET AffectedItems = AffectedItems + ' . count($changes) . '
WHERE SessionLogId = ' . $sesion_log_id;
$this->Conn->Query($sql);
$this->Application->incrementCacheSerial('session-log');
}
/**
* Cancels edit
* Removes all temp tables and clears selected ids
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnCancelEdit(kEvent &$event)
+ protected function OnCancelEdit(kEvent $event)
{
- $temp_handler =& $this->Application->recallObject($event->getPrefixSpecial() . '_TempHandler', 'kTempTablesHandler', Array ('parent_event' => &$event));
+ $temp_handler =& $this->Application->recallObject($event->getPrefixSpecial() . '_TempHandler', 'kTempTablesHandler', Array ('parent_event' => $event));
/* @var $temp_handler kTempTablesHandler */
$temp_handler->CancelEdit();
$this->clearSelectedIDs($event);
$this->Application->RemoveVar($event->getPrefixSpecial() . '_modified');
$changes_var_name = $this->Prefix . '_changes_' . $this->Application->GetTopmostWid($this->Prefix);
$this->Application->RemoveVar($changes_var_name);
$event->SetRedirectParam('opener', 'u');
}
/**
* Allows to determine if we are creating new item or editing already created item
*
* @param kEvent $event
* @return bool
* @access public
*/
- public function isNewItemCreate(kEvent &$event)
+ public function isNewItemCreate(kEvent $event)
{
$object =& $event->getObject( Array ('raise_warnings' => 0) );
/* @var $object kDBItem */
return !$object->isLoaded();
}
/**
* 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(kEvent &$event)
+ protected function OnPreSave(kEvent $event)
{
// if there is no id - it means we need to create an item
if ( is_object($event->MasterEvent) ) {
$event->MasterEvent->setEventParam('IsNew', false);
}
if ( $this->isNewItemCreate($event) ) {
$event->CallSubEvent('OnPreSaveCreated');
if ( is_object($event->MasterEvent) ) {
$event->MasterEvent->setEventParam('IsNew', true);
}
return ;
}
// don't just call OnUpdate event here, since it maybe overwritten to Front-End specific behavior
$this->_update($event);
}
/**
* [HOOK] Saves sub-item
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnPreSaveSubItem(kEvent &$event)
+ protected function OnPreSaveSubItem(kEvent $event)
{
$not_created = $this->isNewItemCreate($event);
$event->CallSubEvent($not_created ? 'OnCreate' : 'OnUpdate');
if ( $event->status == kEvent::erSUCCESS ) {
$object =& $event->getObject();
/* @var $object kDBItem */
$this->Application->SetVar($event->getPrefixSpecial() . '_id', $object->GetID());
}
else {
$event->MasterEvent->status = $event->status;
}
$event->SetRedirectParam('opener', 's');
}
/**
* Saves edited item in temp table and loads
* item with passed id in current template
* Used in Prev/Next buttons
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnPreSaveAndGo(kEvent &$event)
+ protected function OnPreSaveAndGo(kEvent $event)
{
$event->CallSubEvent('OnPreSave');
if ( $event->status == kEvent::erSUCCESS ) {
$id = $this->Application->GetVar($event->getPrefixSpecial(true) . '_GoId');
$event->SetRedirectParam($event->getPrefixSpecial() . '_id', $id);
}
}
/**
* Saves edited item in temp table and goes
* to passed tabs, by redirecting to it with OnPreSave event
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnPreSaveAndGoToTab(kEvent &$event)
+ protected function OnPreSaveAndGoToTab(kEvent $event)
{
$event->CallSubEvent('OnPreSave');
if ( $event->status == kEvent::erSUCCESS ) {
$event->redirect = $this->Application->GetVar($event->getPrefixSpecial(true) . '_GoTab');
}
}
/**
* Saves editable list and goes to passed tab,
* by redirecting to it with empty event
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnUpdateAndGoToTab(kEvent &$event)
+ protected function OnUpdateAndGoToTab(kEvent $event)
{
$event->setPseudoClass('_List');
$event->CallSubEvent('OnUpdate');
if ( $event->status == kEvent::erSUCCESS ) {
$event->redirect = $this->Application->GetVar($event->getPrefixSpecial(true) . '_GoTab');
}
}
/**
* 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(kEvent &$event)
+ protected function OnPreCreate(kEvent $event)
{
$this->setTempWindowID($event);
$this->clearSelectedIDs($event);
$this->Application->SetVar('m_lang', $this->Application->GetDefaultLanguageId());
$object =& $event->getObject(Array ('skip_autoload' => true));
/* @var $object kDBItem */
- $temp_handler =& $this->Application->recallObject($event->Prefix . '_TempHandler', 'kTempTablesHandler', Array ('parent_event' => &$event));
+ $temp_handler =& $this->Application->recallObject($event->Prefix . '_TempHandler', 'kTempTablesHandler', Array ('parent_event' => $event));
/* @var $temp_handler kTempTablesHandler */
$temp_handler->PrepareEdit();
$object->setID(0);
$this->Application->SetVar($event->getPrefixSpecial() . '_id', 0);
$this->Application->SetVar($event->getPrefixSpecial() . '_PreCreate', 1);
$changes_var_name = $this->Prefix . '_changes_' . $this->Application->GetTopmostWid($this->Prefix);
$this->Application->RemoveVar($changes_var_name);
$event->redirect = false;
}
/**
* Creates a new item in temp table and
* stores item id in App vars and Session on success
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnPreSaveCreated(kEvent &$event)
+ protected function OnPreSaveCreated(kEvent $event)
{
$object =& $event->getObject( Array('skip_autoload' => true) );
/* @var $object kDBItem */
$field_values = $this->getSubmittedFields($event);
$object->SetFieldsFromHash($field_values, $this->getRequestProtectedFields($field_values));
$this->customProcessing($event, 'before');
if ( $object->Create() ) {
$this->customProcessing($event, 'after');
$event->SetRedirectParam($event->getPrefixSpecial(true) . '_id', $object->GetID());
}
else {
$event->status = kEvent::erFAIL;
$event->redirect = false;
$object->setID(0);
}
}
/**
* Reloads form to loose all changes made during item editing
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnReset(kEvent &$event)
+ protected function OnReset(kEvent $event)
{
//do nothing - should reset :)
if ( $this->isNewItemCreate($event) ) {
// just reset id to 0 in case it was create
$object =& $event->getObject( Array ('skip_autoload' => true) );
/* @var $object kDBItem */
$object->setID(0);
$this->Application->SetVar($event->getPrefixSpecial() . '_id', 0);
}
}
/**
* Apply same processing to each item being selected in grid
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function iterateItems(kEvent &$event)
+ protected function iterateItems(kEvent $event)
{
if ( $this->Application->CheckPermission('SYSTEM_ACCESS.READONLY', 1) ) {
$event->status = kEvent::erFAIL;
return ;
}
$object =& $event->getObject(Array ('skip_autoload' => true));
/* @var $object kDBItem */
$ids = $this->StoreSelectedIDs($event);
if ( $ids ) {
$status_field = array_shift( $this->Application->getUnitOption($event->Prefix, 'StatusField') );
$order_field = $this->Application->getUnitOption($event->Prefix, 'OrderField');
if ( !$order_field ) {
$order_field = 'Priority';
}
foreach ($ids as $id) {
$object->Load($id);
switch ( $event->Name ) {
case 'OnMassApprove':
$object->SetDBField($status_field, 1);
break;
case 'OnMassDecline':
$object->SetDBField($status_field, 0);
break;
case 'OnMassMoveUp':
$object->SetDBField($order_field, $object->GetDBField($order_field) + 1);
break;
case 'OnMassMoveDown':
$object->SetDBField($order_field, $object->GetDBField($order_field) - 1);
break;
}
if ( $object->Update() ) {
$event->status = kEvent::erSUCCESS;
}
else {
$event->status = kEvent::erFAIL;
$event->redirect = false;
break;
}
}
}
$this->clearSelectedIDs($event);
}
/**
* Clones selected items in list
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnMassClone(kEvent &$event)
+ protected function OnMassClone(kEvent $event)
{
if ( $this->Application->CheckPermission('SYSTEM_ACCESS.READONLY', 1) ) {
$event->status = kEvent::erFAIL;
return;
}
- $temp_handler =& $this->Application->recallObject($event->getPrefixSpecial() . '_TempHandler', 'kTempTablesHandler', Array ('parent_event' => &$event));
+ $temp_handler =& $this->Application->recallObject($event->getPrefixSpecial() . '_TempHandler', 'kTempTablesHandler', Array ('parent_event' => $event));
/* @var $temp_handler kTempTablesHandler */
$ids = $this->StoreSelectedIDs($event);
if ( $ids ) {
$temp_handler->CloneItems($event->Prefix, $event->Special, $ids);
}
$this->clearSelectedIDs($event);
}
/**
* Checks if given value is present in given array
*
* @param Array $records
* @param string $field
* @param mixed $value
* @return bool
* @access protected
*/
protected function check_array($records, $field, $value)
{
foreach ($records as $record) {
if ($record[$field] == $value) {
return true;
}
}
return false;
}
/**
* Saves data from editing form to database without checking required fields
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnPreSavePopup(kEvent &$event)
+ protected function OnPreSavePopup(kEvent $event)
{
$object =& $event->getObject();
/* @var $object kDBItem */
$this->RemoveRequiredFields($object);
$event->CallSubEvent('OnPreSave');
$event->SetRedirectParam('opener', 'u');
}
/* End of Edit events */
// III. Events that allow to put some code before and after Update,Load,Create and Delete methods of item
/**
* Occurs before loading item, 'id' parameter
* allows to get id of item being loaded
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnBeforeItemLoad(kEvent &$event)
+ protected function OnBeforeItemLoad(kEvent $event)
{
}
/**
* Occurs after loading item, 'id' parameter
* allows to get id of item that was loaded
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnAfterItemLoad(kEvent &$event)
+ protected function OnAfterItemLoad(kEvent $event)
{
}
/**
* Occurs before creating item
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnBeforeItemCreate(kEvent &$event)
+ protected function OnBeforeItemCreate(kEvent $event)
{
}
/**
* Occurs after creating item
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnAfterItemCreate(kEvent &$event)
+ protected function OnAfterItemCreate(kEvent $event)
{
$object =& $event->getObject();
/* @var $object kDBItem */
if ( !$object->IsTempTable() ) {
$this->_proccessPendingActions($event);
}
}
/**
* Occurs before updating item
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnBeforeItemUpdate(kEvent &$event)
+ protected function OnBeforeItemUpdate(kEvent $event)
{
}
/**
* Occurs after updating item
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnAfterItemUpdate(kEvent &$event)
+ protected function OnAfterItemUpdate(kEvent $event)
{
$object =& $event->getObject();
/* @var $object kDBItem */
if ( !$object->IsTempTable() ) {
$this->_proccessPendingActions($event);
}
}
/**
* Occurs before deleting item, id of item being
* deleted is stored as 'id' event param
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnBeforeItemDelete(kEvent &$event)
+ protected function OnBeforeItemDelete(kEvent $event)
{
}
/**
* Occurs after deleting item, id of deleted item
* is stored as 'id' param of event
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnAfterItemDelete(kEvent &$event)
+ protected function OnAfterItemDelete(kEvent $event)
{
}
/**
* Occurs before validation attempt
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnBeforeItemValidate(kEvent &$event)
+ protected function OnBeforeItemValidate(kEvent $event)
{
}
/**
* Occurs after successful item validation
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnAfterItemValidate(kEvent &$event)
+ protected function OnAfterItemValidate(kEvent $event)
{
}
/**
* Occurs after an item has been copied to temp
* Id of copied item is passed as event' 'id' param
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnAfterCopyToTemp(kEvent &$event)
+ protected function OnAfterCopyToTemp(kEvent $event)
{
}
/**
* Occurs before an item is deleted from live table when copying from temp
* (temp handler deleted all items from live and then copy over all items from temp)
* Id of item being deleted is passed as event' 'id' param
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnBeforeDeleteFromLive(kEvent &$event)
+ protected function OnBeforeDeleteFromLive(kEvent $event)
{
}
/**
* Occurs before an item is copied to live table (after all foreign keys have been updated)
* Id of item being copied is passed as event' 'id' param
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnBeforeCopyToLive(kEvent &$event)
+ protected function OnBeforeCopyToLive(kEvent $event)
{
}
/**
* Occurs after an item has been copied to live table
* Id of copied item is passed as event' 'id' param
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnAfterCopyToLive(kEvent &$event)
+ protected function OnAfterCopyToLive(kEvent $event)
{
$this->_proccessPendingActions($event);
}
/**
* Processing file pending actions (e.g. delete scheduled files)
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function _proccessPendingActions(kEvent &$event)
+ protected function _proccessPendingActions(kEvent $event)
{
$var_name = $this->_getPendingActionVariableName($event);
$schedule = $this->Application->RecallVar($var_name);
if ( $schedule ) {
$schedule = unserialize($schedule);
foreach ($schedule as $data) {
if ( $data['action'] == 'delete' ) {
unlink($data['file']);
}
}
$this->Application->RemoveVar($var_name);
}
}
/**
* Returns variable name, used to store pending file actions
*
* @param kEvent $event
* @return string
* @access protected
*/
- protected function _getPendingActionVariableName(kEvent &$event)
+ protected function _getPendingActionVariableName(kEvent $event)
{
$window_id = $this->Application->GetTopmostWid($event->Prefix);
return $event->Prefix . '_file_pending_actions' . $window_id;
}
/**
* 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(kEvent &$event)
+ protected function OnBeforeClone(kEvent $event)
{
}
/**
* Occurs after 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 OnAfterClone(kEvent &$event)
+ protected function OnAfterClone(kEvent $event)
{
}
/**
* Occurs after list is queried
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnAfterListQuery(kEvent &$event)
+ protected function OnAfterListQuery(kEvent $event)
{
}
/**
* Ensures that popup will be closed automatically
* and parent window will be refreshed with template
* passed
*
* @param kEvent $event
* @return void
* @access protected
* @deprecated
*/
- protected function finalizePopup(kEvent &$event)
+ protected function finalizePopup(kEvent $event)
{
$event->SetRedirectParam('opener', 'u');
}
/**
* Create search filters based on search query
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnSearch(kEvent &$event)
+ protected function OnSearch(kEvent $event)
{
$event->setPseudoClass('_List');
$search_helper =& $this->Application->recallObject('SearchHelper');
/* @var $search_helper kSearchHelper */
$search_helper->performSearch($event);
}
/**
* Clear search keywords
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnSearchReset(kEvent &$event)
+ protected function OnSearchReset(kEvent $event)
{
$search_helper =& $this->Application->recallObject('SearchHelper');
/* @var $search_helper kSearchHelper */
$search_helper->resetSearch($event);
}
/**
* Set's new filter value (filter_id meaning from config)
*
* @param kEvent $event
* @return void
* @access protected
* @deprecated
*/
- protected function OnSetFilter(kEvent &$event)
+ protected function OnSetFilter(kEvent $event)
{
$filter_id = $this->Application->GetVar('filter_id');
$filter_value = $this->Application->GetVar('filter_value');
$view_filter = $this->Application->RecallVar($event->getPrefixSpecial() . '_view_filter');
$view_filter = $view_filter ? unserialize($view_filter) : Array ();
$view_filter[$filter_id] = $filter_value;
$this->Application->StoreVar($event->getPrefixSpecial() . '_view_filter', serialize($view_filter));
}
/**
* Sets view filter based on request
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnSetFilterPattern(kEvent &$event)
+ protected function OnSetFilterPattern(kEvent $event)
{
$filters = $this->Application->GetVar($event->getPrefixSpecial(true) . '_filters');
if ( !$filters ) {
return;
}
$view_filter = $this->Application->RecallVar($event->getPrefixSpecial() . '_view_filter');
$view_filter = $view_filter ? unserialize($view_filter) : Array ();
$filters = explode(',', $filters);
foreach ($filters as $a_filter) {
list($id, $value) = explode('=', $a_filter);
$view_filter[$id] = $value;
}
$this->Application->StoreVar($event->getPrefixSpecial() . '_view_filter', serialize($view_filter));
$event->redirect = false;
}
/**
* Add/Remove all filters applied to list from "View" menu
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function FilterAction(kEvent &$event)
+ protected function FilterAction(kEvent $event)
{
$view_filter = Array ();
$filter_menu = $this->Application->getUnitOption($event->Prefix, 'FilterMenu');
switch ($event->Name) {
case 'OnRemoveFilters':
$filter_value = 1;
break;
case 'OnApplyFilters':
$filter_value = 0;
break;
default:
$filter_value = 0;
break;
}
foreach ($filter_menu['Filters'] as $filter_key => $filter_params) {
if ( !$filter_params ) {
continue;
}
$view_filter[$filter_key] = $filter_value;
}
$this->Application->StoreVar($event->getPrefixSpecial() . '_view_filter', serialize($view_filter));
}
/**
* Enter description here...
*
* @param kEvent $event
* @access protected
*/
- protected function OnPreSaveAndOpenTranslator(kEvent &$event)
+ protected function OnPreSaveAndOpenTranslator(kEvent $event)
{
$this->Application->SetVar('allow_translation', true);
$object =& $event->getObject();
/* @var $object kDBItem */
$this->RemoveRequiredFields($object);
$event->CallSubEvent('OnPreSave');
if ( $event->status == kEvent::erSUCCESS ) {
$resource_id = $this->Application->GetVar('translator_resource_id');
if ( $resource_id ) {
$t_prefixes = explode(',', $this->Application->GetVar('translator_prefixes'));
$cdata =& $this->Application->recallObject($t_prefixes[1], null, Array ('skip_autoload' => true));
/* @var $cdata kDBItem */
$cdata->Load($resource_id, 'ResourceId');
if ( !$cdata->isLoaded() ) {
$cdata->SetDBField('ResourceId', $resource_id);
$cdata->Create();
}
$this->Application->SetVar($cdata->getPrefixSpecial() . '_id', $cdata->GetID());
}
$event->redirect = $this->Application->GetVar('translator_t');
$redirect_params = Array (
'pass' => 'all,trans,' . $this->Application->GetVar('translator_prefixes'),
'opener' => 's',
$event->getPrefixSpecial(true) . '_id' => $object->GetID(),
'trans_event' => 'OnLoad',
'trans_prefix' => $this->Application->GetVar('translator_prefixes'),
'trans_field' => $this->Application->GetVar('translator_field'),
'trans_multi_line' => $this->Application->GetVar('translator_multi_line'),
);
$event->setRedirectParams($redirect_params);
// 1. SAVE LAST TEMPLATE TO SESSION (really needed here, because of tweaky redirect)
$last_template = $this->Application->RecallVar('last_template');
preg_match('/index4\.php\|' . $this->Application->GetSID() . '-(.*):/U', $last_template, $rets);
$this->Application->StoreVar('return_template', $this->Application->GetVar('t'));
}
}
/**
* Makes all fields non-required
*
* @param kDBItem $object
* @return void
* @access protected
*/
protected function RemoveRequiredFields(&$object)
{
// making all field non-required to achieve successful presave
$fields = array_keys( $object->getFields() );
foreach ($fields as $field) {
if ( $object->isRequired($field) ) {
$object->setRequired($field, false);
}
}
}
/**
* Saves selected user in needed field
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnSelectUser(kEvent &$event)
+ protected function OnSelectUser(kEvent $event)
{
$object =& $event->getObject();
/* @var $object kDBItem */
$items_info = $this->Application->GetVar('u');
if ( $items_info ) {
$user_id = array_shift(array_keys($items_info));
$this->RemoveRequiredFields($object);
$is_new = !$object->isLoaded();
$is_main = substr($this->Application->GetVar($event->Prefix . '_mode'), 0, 1) == 't';
if ( $is_new ) {
$new_event = $is_main ? 'OnPreCreate' : 'OnNew';
$event->CallSubEvent($new_event);
$event->redirect = true;
}
$object->SetDBField($this->Application->RecallVar('dst_field'), $user_id);
if ( $is_new ) {
$object->Create();
}
else {
$object->Update();
}
}
$event->SetRedirectParam($event->getPrefixSpecial() . '_id', $object->GetID());
$event->SetRedirectParam('opener', 'u');
}
/** EXPORT RELATED **/
/**
* Shows export dialog
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnExport(kEvent &$event)
+ protected function OnExport(kEvent $event)
{
$selected_ids = $this->StoreSelectedIDs($event);
if ( implode(',', $selected_ids) == '' ) {
// K4 fix when no ids found bad selected ids array is formed
$selected_ids = false;
}
$this->Application->StoreVar($event->Prefix . '_export_ids', $selected_ids ? implode(',', $selected_ids) : '');
$this->Application->LinkVar('export_finish_t');
$this->Application->LinkVar('export_progress_t');
$this->Application->StoreVar('export_oroginal_special', $event->Special);
$export_helper =& $this->Application->recallObject('CatItemExportHelper');
/*list ($index_file, $env) = explode('|', $this->Application->RecallVar('last_template'));
$finish_url = $this->Application->BaseURL('/admin') . $index_file . '?' . ENV_VAR_NAME . '=' . $env;
$this->Application->StoreVar('export_finish_url', $finish_url);*/
$redirect_params = Array (
$this->Prefix . '.export_event' => 'OnNew',
'pass' => 'all,' . $this->Prefix . '.export'
);
$event->setRedirectParams($redirect_params);
}
/**
* 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, kEvent &$event)
+ protected function prepareObject(&$object, kEvent $event)
{
if ( $event->Special == 'export' || $event->Special == 'import' ) {
$export_helper =& $this->Application->recallObject('CatItemExportHelper');
/* @var $export_helper kCatDBItemExportHelper */
$export_helper->prepareExportColumns($event);
}
}
/**
* Returns specific to each item type columns only
*
* @param kEvent $event
* @return Array
* @access public
*/
- public function getCustomExportColumns(kEvent &$event)
+ public function getCustomExportColumns(kEvent $event)
{
return Array();
}
/**
* Export form validation & processing
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnExportBegin(kEvent &$event)
+ protected function OnExportBegin(kEvent $event)
{
$export_helper =& $this->Application->recallObject('CatItemExportHelper');
/* @var $export_helper kCatDBItemExportHelper */
$export_helper->OnExportBegin($event);
}
/**
* Enter description here...
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnExportCancel(kEvent &$event)
+ protected function OnExportCancel(kEvent $event)
{
$this->OnGoBack($event);
}
/**
* Allows configuring export options
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnBeforeExportBegin(kEvent &$event)
+ protected function OnBeforeExportBegin(kEvent $event)
{
}
/**
* Deletes export preset
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnDeleteExportPreset(kEvent &$event)
+ protected function OnDeleteExportPreset(kEvent $event)
{
$field_values = $this->getSubmittedFields($event);
if ( !$field_values ) {
return ;
}
$preset_key = $field_values['ExportPresets'];
$export_settings = $this->Application->RecallPersistentVar('export_settings');
if ( !$export_settings ) {
return ;
}
$export_settings = unserialize($export_settings);
if ( !isset($export_settings[$event->Prefix]) ) {
return ;
}
$to_delete = '';
foreach ($export_settings[$event->Prefix] as $key => $val) {
if ( implode('|', $val['ExportColumns']) == $preset_key ) {
$to_delete = $key;
break;
}
}
if ( $to_delete ) {
unset($export_settings[$event->Prefix][$to_delete]);
$this->Application->StorePersistentVar('export_settings', serialize($export_settings));
}
}
/**
* Saves changes & changes language
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnPreSaveAndChangeLanguage(kEvent &$event)
+ protected function OnPreSaveAndChangeLanguage(kEvent $event)
{
if ( $this->UseTempTables($event) ) {
$event->CallSubEvent('OnPreSave');
}
if ( $event->status == kEvent::erSUCCESS ) {
$this->Application->SetVar('m_lang', $this->Application->GetVar('language'));
$data = $this->Application->GetVar('st_id');
if ( $data ) {
$event->SetRedirectParam('st_id', $data);
}
}
}
/**
* Used to save files uploaded via swfuploader
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnUploadFile(kEvent &$event)
+ protected function OnUploadFile(kEvent $event)
{
$event->status = kEvent::erSTOP;
// define('DBG_SKIP_REPORTING', 0);
$default_msg = "Flash requires that we output something or it won't fire the uploadSuccess event";
if ( !$this->Application->HttpQuery->Post ) {
// Variables {field, id, flashsid} are always submitted through POST!
// When file size is larger, then "upload_max_filesize" (in php.ini),
// then these variables also are not submitted -> handle such case.
header('HTTP/1.0 413 File size exceeds allowed limit');
echo $default_msg;
return;
}
if ( !$this->_checkFlashUploaderPermission($event) ) {
// 403 Forbidden
header('HTTP/1.0 403 You don\'t have permissions to upload');
echo $default_msg;
return;
}
$value = $this->Application->GetVar('Filedata');
if ( !$value || ($value['error'] != UPLOAD_ERR_OK) ) {
// 413 Request Entity Too Large (file uploads disabled OR uploaded file was
// to large for web server to accept, see "upload_max_filesize" in php.ini)
header('HTTP/1.0 413 File size exceeds allowed limit');
echo $default_msg;
return;
}
$tmp_path = WRITEABLE . '/tmp/';
$fname = $value['name'];
$id = $this->Application->GetVar('id');
if ( $id ) {
$fname = $id . '_' . $fname;
}
$field_name = $this->Application->GetVar('field');
$fields = $this->Application->getUnitOption($event->Prefix, 'Fields');
$virtual_fields = $this->Application->getUnitOption($event->Prefix, 'VirtualFields');
$field_options = array_key_exists($field_name, $fields) ? $fields[$field_name] : $virtual_fields[$field_name];
$upload_dir = $field_options['upload_dir'];
$storage_format = array_key_exists('storage_format', $field_options) ? $field_options['storage_format'] : false;
if ( !is_writable($tmp_path) ) {
// 500 Internal Server Error
// check both temp and live upload directory
header('HTTP/1.0 500 Write permissions not set on the server');
echo $default_msg;
return;
}
$file_helper =& $this->Application->recallObject('FileHelper');
/* @var $file_helper FileHelper */
$fname = $file_helper->ensureUniqueFilename($tmp_path, $fname);
if ( $storage_format ) {
$image_helper =& $this->Application->recallObject('ImageHelper');
/* @var $image_helper ImageHelper */
move_uploaded_file($value['tmp_name'], $value['tmp_name'] . '.jpg'); // add extension, so ResizeImage can work
$url = $image_helper->ResizeImage($value['tmp_name'] . '.jpg', $storage_format);
$tmp_name = preg_replace('/^' . preg_quote($this->Application->BaseURL(), '/') . '/', '/', $url);
rename($tmp_name, $tmp_path . $fname);
}
else {
move_uploaded_file($value['tmp_name'], $tmp_path . $fname);
}
echo preg_replace('/^' . preg_quote($id, '/') . '_/', '', $fname);
$this->deleteTempFiles($tmp_path);
}
/**
* Delete temporary files, that won't be used for sure
*
* @param string $path
* @return void
* @access protected
*/
protected function deleteTempFiles($path)
{
$files = glob($path . '*.*');
$max_file_date = strtotime('-1 day');
foreach ($files as $file) {
if (filemtime($file) < $max_file_date) {
unlink($file);
}
}
}
/**
* Checks, that flash uploader is allowed to perform upload
*
* @param kEvent $event
* @return bool
*/
- protected function _checkFlashUploaderPermission(kEvent &$event)
+ protected function _checkFlashUploaderPermission(kEvent $event)
{
// Flash uploader does NOT send correct cookies, so we need to make our own check
$cookie_name = 'adm_' . $this->Application->ConfigValue('SessionCookieName');
$this->Application->HttpQuery->Cookie['cookies_on'] = 1;
$this->Application->HttpQuery->Cookie[$cookie_name] = $this->Application->GetVar('flashsid');
// this prevents session from auto-expiring when KeepSessionOnBrowserClose & FireFox is used
$this->Application->HttpQuery->Cookie[$cookie_name . '_live'] = $this->Application->GetVar('flashsid');
$admin_ses =& $this->Application->recallObject('Session.admin');
/* @var $admin_ses Session */
if ( $admin_ses->RecallVar('user_id') == USER_ROOT ) {
return true;
}
// copy some data from given session to current session
$backup_user_id = $this->Application->RecallVar('user_id');
$this->Application->StoreVar('user_id', $admin_ses->RecallVar('user_id'));
$backup_user_groups = $this->Application->RecallVar('UserGroups');
$this->Application->StoreVar('UserGroups', $admin_ses->RecallVar('UserGroups'));
// check permissions using event, that have "add|edit" rule
$check_event = new kEvent($event->getPrefixSpecial() . ':OnProcessSelected');
$check_event->setEventParam('top_prefix', $this->Application->GetTopmostPrefix($event->Prefix, true));
$allowed_to_upload = $this->CheckPermission($check_event);
// restore changed data, so nothing gets saved to database
$this->Application->StoreVar('user_id', $backup_user_id);
$this->Application->StoreVar('UserGroups', $backup_user_groups);
return $allowed_to_upload;
}
/**
* Remembers, that file should be deleted on item's save from temp table
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnDeleteFile(kEvent &$event)
+ protected function OnDeleteFile(kEvent $event)
{
$event->status = kEvent::erSTOP;
if ( strpos($this->Application->GetVar('file'), '../') !== false ) {
return;
}
$object =& $event->getObject(Array ('skip_autoload' => true));
$options = $object->GetFieldOptions($this->Application->GetVar('field'));
$var_name = $this->_getPendingActionVariableName($event);
$schedule = $this->Application->RecallVar($var_name);
$schedule = $schedule ? unserialize($schedule) : Array ();
$schedule[] = Array ('action' => 'delete', 'file' => FULL_PATH . $options['upload_dir'] . $this->Application->GetVar('file'));
$this->Application->StoreVar($var_name, serialize($schedule));
}
/**
* Returns url for viewing uploaded file
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnViewFile(kEvent &$event)
+ protected function OnViewFile(kEvent $event)
{
$event->status = kEvent::erSTOP;
$file = $this->Application->GetVar('file');
if ( (strpos($file, '../') !== false) || (trim($file) !== $file) ) {
// when relative paths or special chars are found template names from url, then it's hacking attempt
return;
}
$object =& $event->getObject(Array ('skip_autoload' => true));
/* @var $object kDBItem */
$field = $this->Application->GetVar('field');
$options = $object->GetFieldOptions($field);
// set current uploaded file
if ( $this->Application->GetVar('tmp') ) {
$options['upload_dir'] = WRITEBALE_BASE . '/tmp/';
unset($options['include_path']);
$object->SetFieldOptions($field, $options);
$object->SetDBField($field, $this->Application->GetVar('id') . '_' . $file);
}
else {
$object->SetDBField($field, $file);
}
// get url to uploaded file
if ( $this->Application->GetVar('thumb') ) {
$url = $object->GetField($field, $options['thumb_format']);
}
else {
$url = $object->GetField($field, 'full_url'); // don't use "file_urls" format to prevent recursion
}
$file_helper =& $this->Application->recallObject('FileHelper');
/* @var $file_helper FileHelper */
$path = $file_helper->urlToPath($url);
if ( !file_exists($path) ) {
exit;
}
header('Content-Length: ' . filesize($path));
header('Content-Type: ' . kUtil::mimeContentType($path));
header('Content-Disposition: inline; filename="' . $file . '"');
readfile($path);
}
/**
* Validates MInput control fields
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnValidateMInputFields(kEvent &$event)
+ protected function OnValidateMInputFields(kEvent $event)
{
$minput_helper =& $this->Application->recallObject('MInputHelper');
/* @var $minput_helper MInputHelper */
$minput_helper->OnValidateMInputFields($event);
}
/**
* Validates individual object field and returns the result
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnValidateField(kEvent &$event)
+ protected function OnValidateField(kEvent $event)
{
$event->status = kEvent::erSTOP;
$field = $this->Application->GetVar('field');
if ( ($this->Application->GetVar('ajax') != 'yes') || !$field ) {
return;
}
$object =& $event->getObject(Array ('skip_autoload' => true));
/* @var $object kDBItem */
$items_info = $this->Application->GetVar($event->getPrefixSpecial(true));
if ( !$items_info ) {
return;
}
list ($id, $field_values) = each($items_info);
$object->Load($id);
$object->SetFieldsFromHash($field_values, $this->getRequestProtectedFields($field_values));
$object->setID($id);
$response = Array ('status' => 'OK');
$event->CallSubEvent($object->isLoaded() ? 'OnBeforeItemUpdate' : 'OnBeforeItemCreate');
// validate all fields, since "Password_plain" field sets error to "Password" field, which is passed here
$error_field = $object->GetFieldOption($field, 'error_field', false, $field);
if ( !$object->Validate() && $object->GetErrorPseudo($error_field) ) {
$response['status'] = $object->GetErrorMsg($error_field);
}
$ajax_form_helper =& $this->Application->recallObject('AjaxFormHelper');
/* @var $ajax_form_helper AjaxFormHelper */
$response['other_errors'] = $ajax_form_helper->getErrorMessages($object);
$event->status = kEvent::erSTOP; // since event's OnBefore... events can change this event status
echo json_encode($response);
}
/**
* Returns auto-complete values for ajax-dropdown
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnSuggestValues(kEvent &$event)
+ protected function OnSuggestValues(kEvent $event)
{
if ( !$this->Application->isAdminUser ) {
// very careful here, because this event allows to
// view every object field -> limit only to logged-in admins
return;
}
$event->status = kEvent::erSTOP;
$field = $this->Application->GetVar('field');
$cur_value = $this->Application->GetVar('cur_value');
$fields = $this->Application->getUnitOption($event->Prefix, 'Fields');
$object =& $event->getObject();
if ( !$field || !$cur_value || !$object->isField($field) ) {
return;
}
$limit = $this->Application->GetVar('limit');
if ( !$limit ) {
$limit = 20;
}
$sql = 'SELECT DISTINCT ' . $field . '
FROM ' . $this->Application->getUnitOption($event->Prefix, 'TableName') . '
WHERE ' . $field . ' LIKE ' . $this->Conn->qstr($cur_value . '%') . '
ORDER BY ' . $field . '
LIMIT 0,' . $limit;
$data = $this->Conn->GetCol($sql);
$this->Application->XMLHeader();
echo '<suggestions>';
foreach ($data as $item) {
echo '<item>' . htmlspecialchars($item) . '</item>';
}
echo '</suggestions>';
}
/**
* Enter description here...
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnSaveWidths(kEvent &$event)
+ protected function OnSaveWidths(kEvent $event)
{
$event->status = kEvent::erSTOP;
/*$lang =& $this->Application->recallObject('lang.current');
header('Content-type: text/xml; charset=' . $lang->GetDBField('Charset'));*/
$picker_helper =& $this->Application->RecallObject('ColumnPickerHelper');
/* @var $picker_helper kColumnPickerHelper */
$picker_helper->PreparePicker($event->getPrefixSpecial(), $this->Application->GetVar('grid_name'));
$picker_helper->SaveWidths($event->getPrefixSpecial(), $this->Application->GetVar('widths'));
echo 'OK';
}
/**
* Called from CSV import script after item fields
* are set and validated, but before actual item create/update.
* If event status is kEvent::erSUCCESS, line will be imported,
* else it will not be imported but added to skipped lines
* and displayed in the end of import.
* Event status is preset from import script.
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnBeforeCSVLineImport(kEvent &$event)
+ protected function OnBeforeCSVLineImport(kEvent $event)
{
// abstract, for hooking
}
/**
* [HOOK] Allows to add cloned subitem to given prefix
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnCloneSubItem(kEvent &$event)
+ protected function OnCloneSubItem(kEvent $event)
{
$clones = $this->Application->getUnitOption($event->MasterEvent->Prefix, 'Clones');
$subitem_prefix = $event->Prefix . '-' . preg_replace('/^#/', '', $event->MasterEvent->Prefix);
$clones[$subitem_prefix] = Array ('ParentPrefix' => $event->Prefix);
$this->Application->setUnitOption($event->MasterEvent->Prefix, 'Clones', $clones);
}
/**
* Returns constrain for priority calculations
*
* @param kEvent $event
* @return void
* @see PriorityEventHandler
* @access protected
*/
- protected function OnGetConstrainInfo(kEvent &$event)
+ protected function OnGetConstrainInfo(kEvent $event)
{
$event->setEventParam('constrain_info', Array ('', ''));
}
}
\ No newline at end of file
Index: branches/5.2.x/core/kernel/db/dbitem.php
===================================================================
--- branches/5.2.x/core/kernel/db/dbitem.php (revision 15129)
+++ branches/5.2.x/core/kernel/db/dbitem.php (revision 15130)
@@ -1,1440 +1,1435 @@
<?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!');
/**
* DBItem
*
*/
class kDBItem extends kDBBase {
/**
* Description
*
* @var array Associative array of current item' field values
* @access protected
*/
protected $FieldValues = Array ();
/**
* Unformatted field values, before parse
*
* @var Array
* @access protected
*/
protected $DirtyFieldValues = Array ();
/**
* Holds item values after loading (not affected by submit)
*
* @var Array
* @access protected
*/
protected $OriginalFieldValues = Array ();
/**
* If set to true, Update will skip Validation before running
*
* @var array Associative array of current item' field values
* @access public
*/
public $IgnoreValidation = false;
/**
* Remembers if object was loaded
*
* @var bool
* @access protected
*/
protected $Loaded = false;
/**
* Holds item' primary key value
*
* @var int Value of primary key field for current item
* @access protected
*/
protected $ID;
/**
* This object is used in cloning operations
*
* @var bool
* @access public
*/
public $inCloning = false;
/**
* Validator object reference
*
* @var kValidator
*/
protected $validator = null;
/**
* Creates validator object, only when required
*
*/
public function initValidator()
{
if ( !is_object($this->validator) ) {
$validator_class = $this->Application->getUnitOption($this->Prefix, 'ValidatorClass', 'kValidator');
$this->validator =& $this->Application->makeClass($validator_class);
}
$this->validator->setDataSource($this);
}
public function SetDirtyField($field_name, $field_value)
{
$this->DirtyFieldValues[$field_name] = $field_value;
}
public function GetDirtyField($field_name)
{
return $this->DirtyFieldValues[$field_name];
}
public function GetOriginalField($field_name, $formatted = false, $format=null)
{
if (array_key_exists($field_name, $this->OriginalFieldValues)) {
// item was loaded before
$value = $this->OriginalFieldValues[$field_name];
}
else {
// no original fields -> use default field value
$value = $this->Fields[$field_name]['default'];
}
if (!$formatted) {
return $value;
}
$res = $value;
$formatter = $this->GetFieldOption($field_name, 'formatter');
if ( $formatter ) {
$formatter =& $this->Application->recallObject($formatter);
/* @var $formatter kFormatter */
$res = $formatter->Format($value, $field_name, $this, $format);
}
return $res;
}
/**
* Sets original field value (useful for custom virtual fields)
*
* @param string $field_name
* @param string $field_value
*/
public function SetOriginalField($field_name, $field_value)
{
$this->OriginalFieldValues[$field_name] = $field_value;
}
/**
* Set's default values for all fields
*
* @access public
*/
public function SetDefaultValues()
{
parent::SetDefaultValues();
if ($this->populateMultiLangFields) {
$this->PopulateMultiLangFields();
}
foreach ($this->Fields as $field => $field_options) {
$default_value = isset($field_options['default']) ? $field_options['default'] : NULL;
$this->SetDBField($field, $default_value);
}
}
/**
* Sets current item field value
* (applies formatting)
*
* @access public
* @param string $name Name of the field
* @param mixed $value Value to set the field to
* @return void
*/
public function SetField($name,$value)
{
$options = $this->GetFieldOptions($name);
$parsed = $value;
if ($value == '') {
$parsed = NULL;
}
// kFormatter is always used, to make sure, that numeric value is converted to normal representation
// according to regional format, even when formatter is not set (try seting format to 1.234,56 to understand why)
$formatter =& $this->Application->recallObject(isset($options['formatter']) ? $options['formatter'] : 'kFormatter');
/* @var $formatter kFormatter */
$parsed = $formatter->Parse($value, $name, $this);
$this->SetDBField($name,$parsed);
}
/**
* Sets current item field value
* (doesn't apply formatting)
*
* @access public
* @param string $name Name of the field
* @param mixed $value Value to set the field to
* @return void
*/
public function SetDBField($name,$value)
{
$this->FieldValues[$name] = $value;
}
/**
* Set's field error, if pseudo passed not found then create it with message text supplied.
* Don't overwrite existing pseudo translation.
*
* @param string $field
* @param string $pseudo
* @param string $error_label
* @param Array $error_params
*
* @return bool
* @access public
*/
public function SetError($field, $pseudo, $error_label = null, $error_params = null)
{
$this->initValidator();
return $this->validator->SetError($field, $pseudo, $error_label, $error_params);
}
/**
* Removes error on field
*
* @param string $field
* @access public
*/
public function RemoveError($field)
{
if ( !is_object($this->validator) ) {
return ;
}
$this->validator->RemoveError($field);
}
/**
* Returns error pseudo
*
* @param string $field
* @return string
*/
public function GetErrorPseudo($field)
{
if ( !is_object($this->validator) ) {
return '';
}
return $this->validator->GetErrorPseudo($field);
}
/**
* Return current item' field value by field name
* (doesn't apply formatter)
*
* @param string $name field name to return
* @return mixed
* @access public
*/
public function GetDBField($name)
{
/*if (!array_key_exists($name, $this->FieldValues) && defined('DEBUG_MODE') && DEBUG_MODE) {
$this->Application->Debugger->appendTrace();
}*/
return $this->FieldValues[$name];
}
public function HasField($name)
{
return array_key_exists($name, $this->FieldValues);
}
public function GetFieldValues()
{
return $this->FieldValues;
}
/**
* Sets item' fields corresponding to elements in passed $hash values.
*
* The function sets current item fields to values passed in $hash, by matching $hash keys with field names
* of current item. If current item' fields are unknown {@link kDBItem::PrepareFields()} is called before actually setting the fields
*
* @param Array $hash
* @param Array $skip_fields Optional param, field names in target object not to set, other fields will be set
* @param Array $set_fields Optional param, field names in target object to set, other fields will be skipped
* @return void
* @access public
*/
public function SetFieldsFromHash($hash, $skip_fields = Array (), $set_fields = Array ())
{
if ( !$set_fields ) {
$set_fields = array_keys($hash);
}
if ( $skip_fields ) {
$set_fields = array_diff($set_fields, $skip_fields);
}
$set_fields = array_intersect($set_fields, array_keys($this->Fields));
// used in formatter which work with multiple fields together
foreach ($set_fields as $field_name) {
$this->SetDirtyField($field_name, $hash[$field_name]);
}
// formats all fields using associated formatters
foreach ($set_fields as $field_name) {
$this->SetField($field_name, $hash[$field_name]);
}
}
/**
* Sets object fields from $hash array
* @param Array $hash
* @param Array|null $skip_fields
* @param Array|null $set_fields
* @return void
* @access public
*/
public function SetDBFieldsFromHash($hash, $skip_fields = Array (), $set_fields = Array ())
{
if ( !$set_fields ) {
$set_fields = array_keys($hash);
}
if ( $skip_fields ) {
$set_fields = array_diff($set_fields, $skip_fields);
}
$set_fields = array_intersect($set_fields, array_keys($this->Fields));
foreach ($set_fields as $field_name) {
$this->SetDBField($field_name, $hash[$field_name]);
}
}
/**
* Returns part of SQL WHERE clause identifying the record, ex. id = 25
*
* @param string $method Child class may want to know who called GetKeyClause, Load(), Update(), Delete() send its names as method
* @param Array $keys_hash alternative, then item id, keys hash to load item by
* @see kDBItem::Load()
* @see kDBItem::Update()
* @see kDBItem::Delete()
* @return string
* @access protected
*/
protected function GetKeyClause($method = null, $keys_hash = null)
{
if ( !isset($keys_hash) ) {
$keys_hash = Array ($this->IDField => $this->ID);
}
$ret = '';
foreach ($keys_hash as $field => $value) {
$value_part = is_null($value) ? ' IS NULL' : ' = ' . $this->Conn->qstr($value);
$ret .= '(' . (strpos($field, '.') === false ? '`' . $this->TableName . '`.' : '') . $field . $value_part . ') AND ';
}
return substr($ret, 0, -5);
}
/**
* Loads item from the database by given id
*
* @access public
* @param mixed $id item id of keys->values hash to load item by
* @param string $id_field_name Optional parameter to load item by given Id field
* @param bool $cachable cache this query result based on it's prefix serial
* @return bool True if item has been loaded, false otherwise
*/
public function Load($id, $id_field_name = null, $cachable = false)
{
if ( isset($id_field_name) ) {
$this->IDField = $id_field_name; // set new IDField
}
$keys_sql = '';
if (is_array($id)) {
$keys_sql = $this->GetKeyClause('load', $id);
}
else {
$this->setID($id);
$keys_sql = $this->GetKeyClause('load');
}
if ( isset($id_field_name) ) {
// restore original IDField from unit config
$this->IDField = $this->Application->getUnitOption($this->Prefix, 'IDField');
}
if (($id === false) || !$keys_sql) {
return $this->Clear();
}
if (!$this->raiseEvent('OnBeforeItemLoad', $id)) {
return false;
}
$q = $this->GetSelectSQL() . ' WHERE ' . $keys_sql;
if ($cachable && $this->Application->isCachingType(CACHING_TYPE_MEMORY)) {
$serial_name = $this->Application->incrementCacheSerial($this->Prefix == 'st' ? 'c' : $this->Prefix, isset($id_field_name) ? null : $id, false);
$cache_key = 'kDBItem::Load_' . crc32(serialize($id) . '-' . $this->IDField) . '[%' . $serial_name . '%]';
$field_values = $this->Application->getCache($cache_key, false);
if ($field_values === false) {
$field_values = $this->Conn->GetRow($q);
if ($field_values !== false) {
// only cache, when data was retrieved
$this->Application->setCache($cache_key, $field_values);
}
}
}
else {
$field_values = $this->Conn->GetRow($q);
}
if ($field_values) {
$this->FieldValues = array_merge($this->FieldValues, $field_values);
$this->OriginalFieldValues = $this->FieldValues;
}
else {
return $this->Clear();
}
if (is_array($id) || isset($id_field_name)) {
$this->setID($this->FieldValues[$this->IDField]);
}
$this->UpdateFormattersSubFields(); // used for updating separate virtual date/time fields from DB timestamp (for example)
$this->raiseEvent('OnAfterItemLoad', $this->GetID());
$this->Loaded = true;
return true;
}
/**
* Loads object from hash (not db)
*
* @param Array $fields_hash
* @param string $id_field
*/
public function LoadFromHash($fields_hash, $id_field = null)
{
if (!isset($id_field)) {
$id_field = $this->IDField;
}
$this->Clear();
if (!$fields_hash || !array_key_exists($id_field, $fields_hash)) {
// no data OR id field missing
return false;
}
$id = $fields_hash[$id_field];
if ( !$this->raiseEvent('OnBeforeItemLoad', $id) ) {
return false;
}
$this->FieldValues = array_merge($this->FieldValues, $fields_hash);
$this->OriginalFieldValues = $this->FieldValues;
$this->setID($id);
$this->UpdateFormattersSubFields(); // used for updating separate virtual date/time fields from DB timestamp (for example)
$this->raiseEvent('OnAfterItemLoad', $id);
$this->Loaded = true;
return true;
}
/**
* Builds select sql, SELECT ... FROM parts only
*
* @access public
* @return string
*/
/**
* Returns SELECT part of list' query
*
* @param string $base_query
* @param bool $replace_table
* @return string
* @access public
*/
public function GetSelectSQL($base_query = null, $replace_table = true)
{
if (!isset($base_query)) {
$base_query = $this->SelectClause;
}
$base_query = $this->addCalculatedFields($base_query);
return parent::GetSelectSQL($base_query, $replace_table);
}
public function UpdateFormattersMasterFields()
{
$this->initValidator(); // used, when called not from kValidator::Validate method
foreach ($this->Fields as $field => $options) {
if ( isset($options['formatter']) ) {
$formatter =& $this->Application->recallObject($options['formatter']);
/* @var $formatter kFormatter */
$formatter->UpdateMasterFields($field, $this->GetDBField($field), $options, $this);
}
}
}
/**
* Allows to skip certain fields from getting into sql queries
*
* @param string $field_name
* @param mixed $force_id
* @return bool
*/
public function skipField($field_name, $force_id = false)
{
$skip = false;
// 1. skipping 'virtual' field
$skip = $skip || array_key_exists($field_name, $this->VirtualFields);
// 2. don't write empty field value to db, when "skip_empty" option is set
$field_value = array_key_exists($field_name, $this->FieldValues) ? $this->FieldValues[$field_name] : false;
if (array_key_exists($field_name, $this->Fields)) {
$skip_empty = array_key_exists('skip_empty', $this->Fields[$field_name]) ? $this->Fields[$field_name]['skip_empty'] : false;
}
else {
// field found in database, but not declared in unit config
$skip_empty = false;
}
$skip = $skip || (!$field_value && $skip_empty);
// 3. skipping field not in Fields (nor virtual, nor real)
$skip = $skip || !array_key_exists($field_name, $this->Fields);
return $skip;
}
/**
* Updates previously loaded record with current item' values
*
* @access public
* @param int $id Primary Key Id to update
* @param bool $system_update
* @return bool
* @access public
*/
public function Update($id = null, $system_update = false)
{
if ( isset($id) ) {
$this->setID($id);
}
if ( !$this->raiseEvent('OnBeforeItemUpdate') ) {
return false;
}
if ( !isset($this->ID) ) {
// ID could be set inside OnBeforeItemUpdate event, so don't combine this check with previous one
return false;
}
// validate before updating
if ( !$this->Validate() ) {
return false;
}
if ( !$this->FieldValues ) {
// nothing to update
return true;
}
$sql = '';
foreach ($this->FieldValues as $field_name => $field_value) {
if ( $this->skipField($field_name) ) {
continue;
}
if ( is_null($field_value) ) {
if ( array_key_exists('not_null', $this->Fields[$field_name]) && $this->Fields[$field_name]['not_null'] ) {
// "kFormatter::Parse" methods converts empty values to NULL and for
// not-null fields they are replaced with default value here
$field_value = $this->Fields[$field_name]['default'];
}
}
$sql .= '`' . $field_name . '` = ' . $this->Conn->qstr($field_value) . ', ';
}
$sql = 'UPDATE ' . $this->TableName . '
SET ' . substr($sql, 0, -2) . '
WHERE ' . $this->GetKeyClause('update');
if ( $this->Conn->ChangeQuery($sql) === false ) {
// there was and sql error
$this->SetError($this->IDField, 'sql_error', '#' . $this->Conn->getErrorCode() . ': ' . $this->Conn->getErrorMsg());
return false;
}
$affected_rows = $this->Conn->getAffectedRows();
if ( !$system_update && ($affected_rows > 0) ) {
$this->setModifiedFlag(ChangeLog::UPDATE);
}
$this->saveCustomFields();
$this->raiseEvent('OnAfterItemUpdate');
$this->OriginalFieldValues = $this->FieldValues;
$this->Loaded = true;
if ( !$this->IsTempTable() ) {
$this->Application->resetCounters($this->TableName);
}
return true;
}
/**
* Validates given field
*
* @param string $field
* @return bool
* @access public
*/
public function ValidateField($field)
{
$this->initValidator();
return $this->validator->ValidateField($field);
}
/**
* Validate all item fields based on
* constraints set in each field options
* in config
*
* @return bool
* @access private
*/
public function Validate()
{
if ( $this->IgnoreValidation ) {
return true;
}
$this->initValidator();
// will apply any custom validation to the item
$this->raiseEvent('OnBeforeItemValidate');
if ( $this->validator->Validate() ) {
// no validation errors
$this->raiseEvent('OnAfterItemValidate');
return true;
}
return false;
}
/**
* Check if item has errors
*
* @param Array $skip_fields fields to skip during error checking
* @return bool
*/
public function HasErrors($skip_fields = Array ())
{
if ( !is_object($this->validator) ) {
return false;
}
return $this->validator->HasErrors($skip_fields);
}
/**
* Check if value is set for required field
*
* @param string $field field name
* @param Array $params field options from config
* @return bool
* @access public
* @todo Find a way to get rid of direct call from kMultiLanguage::UpdateMasterFields method
*/
public function ValidateRequired($field, $params)
{
return $this->validator->ValidateRequired($field, $params);
}
/**
* Return error message for field
*
* @param string $field
* @param bool $force_escape
* @return string
* @access public
*/
public function GetErrorMsg($field, $force_escape = null)
{
if ( !is_object($this->validator) ) {
return '';
}
return $this->validator->GetErrorMsg($field, $force_escape);
}
/**
* Returns field errors
*
* @return Array
* @access public
*/
public function GetFieldErrors()
{
if ( !is_object($this->validator) ) {
return Array ();
}
return $this->validator->GetFieldErrors();
}
/**
* Creates a record in the database table with current item' values
*
* @param mixed $force_id Set to TRUE to force creating of item's own ID or to value to force creating of passed id. Do not pass 1 for true, pass exactly TRUE!
* @param bool $system_create
* @return bool
* @access public
*/
public function Create($force_id = false, $system_create = false)
{
if (!$this->raiseEvent('OnBeforeItemCreate')) {
return false;
}
// Validating fields before attempting to create record
if (!$this->Validate()) {
return false;
}
if (is_int($force_id)) {
$this->FieldValues[$this->IDField] = $force_id;
}
elseif (!$force_id || !is_bool($force_id)) {
$this->FieldValues[$this->IDField] = $this->generateID();
}
$fields_sql = '';
$values_sql = '';
foreach ($this->FieldValues as $field_name => $field_value) {
if ($this->skipField($field_name, $force_id)) {
continue;
}
if (is_null($field_value)) {
if (array_key_exists('not_null', $this->Fields[$field_name]) && $this->Fields[$field_name]['not_null']) {
// "kFormatter::Parse" methods converts empty values to NULL and for
// not-null fields they are replaced with default value here
$values_sql .= $this->Conn->qstr($this->Fields[$field_name]['default']);
}
else {
$values_sql .= $this->Conn->qstr($field_value);
}
}
else {
if (($field_name == $this->IDField) && ($field_value == 0) && !is_int($force_id)) {
// don't skip IDField in INSERT statement, just use DEFAULT keyword as it's value
$values_sql .= 'DEFAULT';
}
else {
$values_sql .= $this->Conn->qstr($field_value);
}
}
$fields_sql .= '`' . $field_name . '`, '; //Adding field name to fields block of Insert statement
$values_sql .= ', ';
}
$sql = 'INSERT INTO ' . $this->TableName . ' (' . substr($fields_sql, 0, -2) . ')
VALUES (' . substr($values_sql, 0, -2) . ')';
//Executing the query and checking the result
if ($this->Conn->ChangeQuery($sql) === false) {
$this->SetError($this->IDField, 'sql_error', '#' . $this->Conn->getErrorCode() . ': ' . $this->Conn->getErrorMsg());
return false;
}
$insert_id = $this->Conn->getInsertID();
if ($insert_id == 0) {
// insert into temp table (id is not auto-increment field)
$insert_id = $this->FieldValues[$this->IDField];
}
$this->setID($insert_id);
$this->OriginalFieldValues = $this->FieldValues;
if (!$system_create){
$this->setModifiedFlag(ChangeLog::CREATE);
}
$this->saveCustomFields();
if (!$this->IsTempTable()) {
$this->Application->resetCounters($this->TableName);
}
if ($this->IsTempTable() && ($this->Application->GetTopmostPrefix($this->Prefix) != $this->Prefix) && !is_int($force_id)) {
// temp table + subitem = set negative id
$this->setTempID();
}
$this->raiseEvent('OnAfterItemCreate');
$this->Loaded = true;
return true;
}
/**
* Deletes the record from database
*
* @param int $id
* @return bool
* @access public
*/
public function Delete($id = null)
{
if ( isset($id) ) {
$this->setID($id);
}
if ( !$this->raiseEvent('OnBeforeItemDelete') ) {
return false;
}
$sql = 'DELETE FROM ' . $this->TableName . '
WHERE ' . $this->GetKeyClause('Delete');
$ret = $this->Conn->ChangeQuery($sql);
$affected_rows = $this->Conn->getAffectedRows();
if ( $affected_rows > 0 ) {
$this->setModifiedFlag(ChangeLog::DELETE); // will change affected rows, so get it before this line
// something was actually deleted
$this->raiseEvent('OnAfterItemDelete');
}
if ( !$this->IsTempTable() ) {
$this->Application->resetCounters($this->TableName);
}
return $ret;
}
public function PopulateMultiLangFields()
{
foreach ($this->Fields as $field => $options) {
// master field is set only for CURRENT language
$formatter = array_key_exists('formatter', $options) ? $options['formatter'] : false;
if ( ($formatter == 'kMultiLanguage') && isset($options['master_field']) && isset($options['error_field']) ) {
// MuliLanguage formatter sets error_field to master_field, but in PopulateMlFields mode,
// we display ML fields directly so we set it back to itself, otherwise error won't be displayed
unset( $this->Fields[$field]['error_field'] );
}
}
}
/**
* Sets new name for item in case if it is being copied in same table
*
* @param array $master Table data from TempHandler
* @param int $foreign_key ForeignKey value to filter name check query by
* @param string $title_field FieldName to alter, by default - TitleField of the prefix
* @param string $format sprintf-style format of renaming pattern, by default Copy %1$s of %2$s which makes it Copy [Number] of Original Name
* @access public
*/
public function NameCopy($master=null, $foreign_key=null, $title_field=null, $format='Copy %1$s of %2$s')
{
if (!isset($title_field)) {
$title_field = $this->Application->getUnitOption($this->Prefix, 'TitleField');
if (!$title_field || isset($this->CalculatedFields[$title_field]) ) return;
}
$new_name = $this->GetDBField($title_field);
$original_checked = false;
do {
if ( preg_match('/'.sprintf($format, '([0-9]*) *', '(.*)').'/', $new_name, $regs) ) {
$new_name = sprintf($format, ($regs[1]+1), $regs[2]);
}
elseif ($original_checked) {
$new_name = sprintf($format, '', $new_name);
}
// 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 '.$this->TableName.'
WHERE '.$title_field.' = '.$this->Conn->qstr($new_name);
$foreign_key_field = getArrayValue($master, 'ForeignKey');
$foreign_key_field = is_array($foreign_key_field) ? $foreign_key_field[ $master['ParentPrefix'] ] : $foreign_key_field;
if ($foreign_key_field && isset($foreign_key)) {
$query .= ' AND '.$foreign_key_field.' = '.$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);
$this->SetDBField($title_field, $new_name);
}
protected function raiseEvent($name, $id = null, $additional_params = Array())
{
- $event = new kEvent( $this->getPrefixSpecial() . ':' . $name );
+ $additional_params['id'] = isset($id) ? $id : $this->GetID();
+ $event = new kEvent($this->getPrefixSpecial() . ':' . $name, $additional_params);
if ( is_object($this->parentEvent) ) {
$event->MasterEvent =& $this->parentEvent;
}
- $additional_params['id'] = isset($id) ? $id : $this->GetID();
-
- foreach ($additional_params as $ap_name => $ap_value) {
- $event->setEventParam($ap_name, $ap_value);
- }
-
$this->Application->HandleEvent($event);
return $event->status == kEvent::erSUCCESS;
}
/**
* Set's new ID for item
*
* @param int $new_id
* @access public
*/
public function setID($new_id)
{
$this->ID = $new_id;
$this->SetDBField($this->IDField, $new_id);
}
/**
* Generate and set new temporary id
*
* @access private
*/
public function setTempID()
{
$new_id = (int)$this->Conn->GetOne('SELECT MIN('.$this->IDField.') FROM '.$this->TableName);
if($new_id > 0) $new_id = 0;
--$new_id;
$this->Conn->Query('UPDATE '.$this->TableName.' SET `'.$this->IDField.'` = '.$new_id.' WHERE `'.$this->IDField.'` = '.$this->GetID());
if ($this->ShouldLogChanges(true)) {
// Updating TempId in ChangesLog, if changes are disabled
$ses_var_name = $this->Application->GetTopmostPrefix($this->Prefix) . '_changes_' . $this->Application->GetTopmostWid($this->Prefix);
$changes = $this->Application->RecallVar($ses_var_name);
$changes = $changes ? unserialize($changes) : Array ();
if ($changes) {
foreach ($changes as $key => $rec) {
if ($rec['Prefix'] == $this->Prefix && $rec['ItemId'] == $this->GetID()) {
// change log for record, that's ID was just updated -> update in change log record too
$changes[$key]['ItemId'] = $new_id;
}
if ($rec['MasterPrefix'] == $this->Prefix && $rec['MasterId'] == $this->GetID()) {
// master item id was changed
$changes[$key]['MasterId'] = $new_id;
}
if (in_array($this->Prefix, $rec['ParentPrefix']) && $rec['ParentId'][$this->Prefix] == $this->GetID()) {
// change log record of given item's sub item -> update changed id's in dependent fields
$changes[$key]['ParentId'][$this->Prefix] = $new_id;
if (array_key_exists('DependentFields', $rec)) {
// these are fields from table of $rec['Prefix'] table!
// when one of dependent fields goes into idfield of it's parent item, that was changed
$parent_table_key = $this->Application->getUnitOption($rec['Prefix'], 'ParentTableKey');
$parent_table_key = is_array($parent_table_key) ? $parent_table_key[$this->Prefix] : $parent_table_key;
if ($parent_table_key == $this->IDField) {
$foreign_key = $this->Application->getUnitOption($rec['Prefix'], 'ForeignKey');
$foreign_key = is_array($foreign_key) ? $foreign_key[$this->Prefix] : $foreign_key;
$changes[$key]['DependentFields'][$foreign_key] = $new_id;
}
}
}
}
}
$this->Application->StoreVar($ses_var_name, serialize($changes));
}
$this->SetID($new_id);
}
/**
* Set's modification flag for main prefix of current prefix to true
*
* @param int $mode
* @access private
*/
public function setModifiedFlag($mode = null)
{
$main_prefix = $this->Application->GetTopmostPrefix($this->Prefix);
$this->Application->StoreVar($main_prefix . '_modified', '1', true); // true for optional
if ($this->ShouldLogChanges(true)) {
$this->LogChanges($main_prefix, $mode);
if (!$this->IsTempTable()) {
$handler =& $this->Application->recallObject($this->Prefix . '_EventHandler');
/* @var $handler kDBEventHandler */
$ses_var_name = $main_prefix . '_changes_' . $this->Application->GetTopmostWid($this->Prefix);
$handler->SaveLoggedChanges($ses_var_name, $this->ShouldLogChanges());
}
}
}
/**
* Determines, that changes made to this item should be written to change log
*
* @param bool $log_changes
* @return bool
*/
public function ShouldLogChanges($log_changes = null)
{
if (!isset($log_changes)) {
// specific logging mode no forced -> use global logging settings
$log_changes = $this->Application->getUnitOption($this->Prefix, 'LogChanges') || $this->Application->ConfigValue('UseChangeLog');
}
return $log_changes && !$this->Application->getUnitOption($this->Prefix, 'ForceDontLogChanges');
}
protected function LogChanges($main_prefix, $mode)
{
if ( !$mode ) {
return ;
}
$ses_var_name = $main_prefix . '_changes_' . $this->Application->GetTopmostWid($this->Prefix);
$changes = $this->Application->RecallVar($ses_var_name);
$changes = $changes ? unserialize($changes) : Array ();
$fields_hash = Array (
'Prefix' => $this->Prefix,
'ItemId' => $this->GetID(),
'OccuredOn' => adodb_mktime(),
'MasterPrefix' => $main_prefix,
'Action' => $mode,
);
if ( $this->Prefix == $main_prefix ) {
// main item
$fields_hash['MasterId'] = $this->GetID();
$fields_hash['ParentPrefix'] = Array ($main_prefix);
$fields_hash['ParentId'] = Array ($main_prefix => $this->GetID());
}
else {
// sub item
// collect foreign key values (for serial reset)
$foreign_keys = $this->Application->getUnitOption($this->Prefix, 'ForeignKey', Array ());
$dependent_fields = $fields_hash['ParentId'] = $fields_hash['ParentPrefix'] = Array ();
/* @var $foreign_keys Array */
if ( is_array($foreign_keys) ) {
foreach ($foreign_keys as $prefix => $field_name) {
$dependent_fields[$field_name] = $this->GetDBField($field_name);
$fields_hash['ParentPrefix'][] = $prefix;
$fields_hash['ParentId'][$prefix] = $this->getParentId($prefix);
}
}
else {
$dependent_fields[$foreign_keys] = $this->GetDBField($foreign_keys);
$fields_hash['ParentPrefix'] = Array ( $this->Application->getUnitOption($this->Prefix, 'ParentPrefix') );
$fields_hash['ParentId'][ $fields_hash['ParentPrefix'][0] ] = $this->getParentId('auto');
}
$fields_hash['DependentFields'] = $dependent_fields;
// works only, when main item is present in url, when sub-item is changed
$master_id = $this->Application->GetVar($main_prefix . '_id');
if ( $master_id === false ) {
// works in case of we are not editing topmost item, when sub-item is created/updated/deleted
$master_id = $this->getParentId('auto', true);
}
$fields_hash['MasterId'] = $master_id;
}
switch ( $mode ) {
case ChangeLog::UPDATE:
$to_save = array_merge($this->GetTitleField(), $this->GetChangedFields());
break;
case ChangeLog::CREATE:
$to_save = $this->GetTitleField();
break;
case ChangeLog::DELETE:
$to_save = array_merge($this->GetTitleField(), $this->GetRealFields());
break;
default:
$to_save = Array ();
break;
}
$fields_hash['Changes'] = serialize($to_save);
$changes[] = $fields_hash;
$this->Application->StoreVar($ses_var_name, serialize($changes));
}
/**
* Returns current item parent's ID
*
* @param string $parent_prefix
* @param bool $top_most return topmost parent, when used
* @return int
*/
protected function getParentId($parent_prefix, $top_most = false)
{
$current_id = $this->GetID();
$current_prefix = $this->Prefix;
if ($parent_prefix == 'auto') {
$parent_prefix = $this->Application->getUnitOption($current_prefix, 'ParentPrefix');
}
if (!$parent_prefix) {
return $current_id;
}
do {
// field in this table
$foreign_key = $this->Application->getUnitOption($current_prefix, 'ForeignKey');
$foreign_key = is_array($foreign_key) ? $foreign_key[$parent_prefix] : $foreign_key;
// get foreign key value for $current_prefix
if ($current_prefix == $this->Prefix) {
$foreign_key_value = $this->GetDBField($foreign_key);
}
else {
$id_field = $this->Application->getUnitOption($current_prefix, 'IDField');
$table_name = $this->Application->getUnitOption($current_prefix, 'TableName');
if ($this->IsTempTable()) {
$table_name = $this->Application->GetTempName($table_name, 'prefix:' . $current_prefix);
}
$sql = 'SELECT ' . $foreign_key . '
FROM ' . $table_name . '
WHERE ' . $id_field . ' = ' . $current_id;
$foreign_key_value = $this->Conn->GetOne($sql);
}
// field in parent table
$parent_table_key = $this->Application->getUnitOption($current_prefix, 'ParentTableKey');
$parent_table_key = is_array($parent_table_key) ? $parent_table_key[$parent_prefix] : $parent_table_key;
$parent_id_field = $this->Application->getUnitOption($parent_prefix, 'IDField');
$parent_table_name = $this->Application->getUnitOption($parent_prefix, 'TableName');
if ($this->IsTempTable()) {
$parent_table_name = $this->Application->GetTempName($parent_table_name, 'prefix:' . $current_prefix);
}
if ($parent_id_field == $parent_table_key) {
// sub-item is related by parent item idfield
$current_id = $foreign_key_value;
}
else {
// sub-item is related by other parent item field
$sql = 'SELECT ' . $parent_id_field . '
FROM ' . $parent_table_name . '
WHERE ' . $parent_table_key . ' = ' . $foreign_key_value;
$current_id = $this->Conn->GetOne($sql);
}
$current_prefix = $parent_prefix;
if (!$top_most) {
break;
}
} while ( $parent_prefix = $this->Application->getUnitOption($current_prefix, 'ParentPrefix') );
return $current_id;
}
/**
* Returns title field (if any)
*
* @return Array
*/
public function GetTitleField()
{
$title_field = $this->Application->getUnitOption($this->Prefix, 'TitleField');
if ($title_field) {
$value = $this->GetField($title_field);
return $value ? Array ($title_field => $value) : Array ();
}
return Array ();
}
/**
* Returns only fields, that are present in database (no virtual and no calculated fields)
*
* @return Array
*/
public function GetRealFields()
{
return array_diff_key($this->FieldValues, $this->VirtualFields, $this->CalculatedFields);
}
/**
* Returns only changed database field
*
* @param bool $include_virtual_fields
* @return Array
*/
public function GetChangedFields($include_virtual_fields = false)
{
$changes = Array ();
$fields = $include_virtual_fields ? $this->FieldValues : $this->GetRealFields();
$diff = array_diff_assoc($fields, $this->OriginalFieldValues);
foreach ($diff as $field => $new_value) {
$old_value = $this->GetOriginalField($field, true);
$new_value = $this->GetField($field);
if ($old_value != $new_value) {
// "0.00" and "0.0000" are stored as strings and will differ. Double check to prevent that.
$changes[$field] = Array ('old' => $old_value, 'new' => $new_value);
}
}
return $changes;
}
/**
* Returns ID of currently processed record
*
* @return int
* @access public
*/
public function GetID()
{
return $this->ID;
}
/**
* Generates ID for new items before inserting into database
*
* @return int
* @access private
*/
protected function generateID()
{
return 0;
}
/**
* Returns true if item was loaded successfully by Load method
*
* @return bool
*/
public function isLoaded()
{
return $this->Loaded;
}
/**
* Checks if field is required
*
* @param string $field
* @return bool
*/
public function isRequired($field)
{
return isset($this->Fields[$field]['required']) && $this->Fields[$field]['required'];
}
/**
* Sets new required flag to field
*
* @param mixed $fields
* @param bool $is_required
*/
public function setRequired($fields, $is_required = true)
{
if ( !is_array($fields) ) {
$fields = explode(',', $fields);
}
foreach ($fields as $field) {
$this->Fields[$field]['required'] = $is_required;
}
}
/**
* Removes all data from an object
*
* @param int $new_id
* @return bool
* @access public
*/
public function Clear($new_id = null)
{
$this->Loaded = false;
$this->FieldValues = $this->OriginalFieldValues = Array ();
$this->SetDefaultValues(); // will wear off kDBItem::setID effect, so set it later
if ( is_object($this->validator) ) {
$this->validator->reset();
}
$this->setID($new_id);
return $this->Loaded;
}
public function Query($force = false)
{
throw new Exception('<b>Query</b> method is called in class <strong>' . get_class($this) . '</strong> for prefix <strong>' . $this->getPrefixSpecial() . '</strong>');
}
protected function saveCustomFields()
{
if ( !$this->customFields || $this->inCloning ) {
return true;
}
$cdata_key = rtrim($this->Prefix . '-cdata.' . $this->Special, '.');
$cdata =& $this->Application->recallObject($cdata_key, null, Array ('skip_autoload' => true));
/* @var $cdata kDBItem */
$resource_id = $this->GetDBField('ResourceId');
$cdata->Load($resource_id, 'ResourceId');
$cdata->SetDBField('ResourceId', $resource_id);
$ml_formatter =& $this->Application->recallObject('kMultiLanguage');
/* @var $ml_formatter kMultiLanguage */
$ml_helper =& $this->Application->recallObject('kMultiLanguageHelper');
/* @var $ml_helper kMultiLanguageHelper */
$languages = $ml_helper->getLanguages();
foreach ($this->customFields as $custom_id => $custom_name) {
$force_primary = $cdata->GetFieldOption('cust_' . $custom_id, 'force_primary');
if ( $force_primary ) {
$cdata->SetDBField($ml_formatter->LangFieldName('cust_' . $custom_id, true), $this->GetDBField('cust_' . $custom_name));
}
else {
foreach ($languages as $language_id) {
$cdata->SetDBField('l' . $language_id . '_cust_' . $custom_id, $this->GetDBField('l' . $language_id . '_cust_' . $custom_name));
}
}
}
return $cdata->isLoaded() ? $cdata->Update() : $cdata->Create();
}
/**
* Returns specified field value from all selected rows.
* Don't affect current record index
*
* @param string $field
* @param bool $formatted
* @param string $format
* @return Array
*/
public function GetCol($field, $formatted = false, $format = null)
{
if ($formatted) {
return Array (0 => $this->GetField($field, $format));
}
return Array (0 => $this->GetDBField($field));
}
/**
* Set's loaded status of object
*
* @param bool $is_loaded
* @access public
* @todo remove this method, since item can't be marked as loaded externally
*/
public function setLoaded($is_loaded = true)
{
$this->Loaded = $is_loaded;
}
}
\ No newline at end of file
Index: branches/5.2.x/core/kernel/db/cat_event_handler.php
===================================================================
--- branches/5.2.x/core/kernel/db/cat_event_handler.php (revision 15129)
+++ branches/5.2.x/core/kernel/db/cat_event_handler.php (revision 15130)
@@ -1,2953 +1,2953 @@
<?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 kCatDBEventHandler extends kDBEventHandler {
/**
* Allows to override standard permission mapping
*
* @return void
* @access protected
* @see kEventHandler::$permMapping
*/
protected function mapPermissions()
{
parent::mapPermissions();
$permissions = Array(
'OnSaveSettings' => Array ('self' => 'add|edit|advanced:import'),
'OnResetSettings' => Array ('self' => 'add|edit|advanced:import'),
'OnBeforeDeleteOriginal' => Array ('self' => 'edit|advanced:approve'),
'OnAfterDeleteOriginal' => Array ('self' => 'edit|advanced:approve'),
'OnCopy' => Array ('self' => true),
'OnDownloadFile' => Array ('self' => 'view'),
'OnCancelAction' => Array ('self' => true),
'OnItemBuild' => Array ('self' => true),
'OnMakeVote' => Array ('self' => true),
'OnReviewHelpful' => Array ('self' => true),
);
$this->permMapping = array_merge($this->permMapping, $permissions);
}
/**
* Load item if id is available
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function LoadItem(kEvent &$event)
+ protected function LoadItem(kEvent $event)
{
$object =& $event->getObject();
/* @var $object kDBItem */
$id = $this->getPassedID($event);
if ( $object->Load($id) ) {
$actions =& $this->Application->recallObject('kActions');
/* @var $actions Params */
$actions->Set($event->getPrefixSpecial() . '_id', $object->GetID());
$use_pending_editing = $this->Application->getUnitOption($event->Prefix, 'UsePendingEditing');
if ( $use_pending_editing && $event->Special != 'original' ) {
$this->Application->SetVar($event->Prefix . '.original_id', $object->GetDBField('OrgId'));
}
}
else {
$object->setID($id);
}
}
/**
* Checks user permission to execute given $event
*
* @param kEvent $event
* @return bool
* @access public
*/
- public function CheckPermission(kEvent &$event)
+ public function CheckPermission(kEvent $event)
{
if ( !$this->Application->isAdmin ) {
if ( $event->Name == 'OnSetSortingDirect' ) {
// allow sorting on front event without view permission
return true;
}
}
if ( $event->Name == 'OnExport' ) {
// save category_id before doing export
$this->Application->LinkVar('m_cat_id');
}
if ( in_array($event->Name, $this->_getMassPermissionEvents()) ) {
$items = $this->_getPermissionCheckInfo($event);
$perm_helper =& $this->Application->recallObject('PermissionsHelper');
/* @var $perm_helper kPermissionsHelper */
if ( ($event->Name == 'OnSave') && array_key_exists(0, $items) ) {
// adding new item (ID = 0)
$perm_value = $perm_helper->AddCheckPermission($items[0]['CategoryId'], $event->Prefix) > 0;
}
else {
// leave only items, that can be edited
$ids = Array ();
$check_method = in_array($event->Name, Array ('OnMassDelete', 'OnCut')) ? 'DeleteCheckPermission' : 'ModifyCheckPermission';
foreach ($items as $item_id => $item_data) {
if ( $perm_helper->$check_method($item_data['CreatedById'], $item_data['CategoryId'], $event->Prefix) > 0 ) {
$ids[] = $item_id;
}
}
if ( !$ids ) {
// no items left for editing -> no permission
return $perm_helper->finalizePermissionCheck($event, false);
}
$perm_value = true;
$event->setEventParam('ids', $ids); // will be used later by "kDBEventHandler::StoreSelectedIDs" method
}
return $perm_helper->finalizePermissionCheck($event, $perm_value);
}
$export_events = Array ('OnSaveSettings', 'OnResetSettings', 'OnExportBegin');
if ( in_array($event->Name, $export_events) ) {
// when import settings before selecting target import category
return $this->Application->CheckPermission('in-portal:main_import.view');
}
if ( $event->Name == 'OnProcessSelected' ) {
if ( $this->Application->RecallVar('dst_field') == 'ImportCategory' ) {
// when selecting target import category
return $this->Application->CheckPermission('in-portal:main_import.view');
}
}
return parent::CheckPermission($event);
}
/**
* Returns events, that require item-based (not just event-name based) permission check
*
* @return Array
*/
function _getMassPermissionEvents()
{
return Array (
'OnEdit', 'OnSave', 'OnMassDelete', 'OnMassApprove',
'OnMassDecline', 'OnMassMoveUp', 'OnMassMoveDown',
'OnCut',
);
}
/**
* Returns category item IDs, that require permission checking
*
* @param kEvent $event
* @return string
*/
- function _getPermissionCheckIDs(&$event)
+ function _getPermissionCheckIDs($event)
{
if ($event->Name == 'OnSave') {
$selected_ids = implode(',', $this->getSelectedIDs($event, true));
if (!$selected_ids) {
$selected_ids = 0; // when saving newly created item (OnPreCreate -> OnPreSave -> OnSave)
}
}
else {
// OnEdit, OnMassDelete events, when items are checked in grid
$selected_ids = implode(',', $this->StoreSelectedIDs($event));
}
return $selected_ids;
}
/**
* Returns information used in permission checking
*
* @param kEvent $event
* @return Array
*/
- function _getPermissionCheckInfo(&$event)
+ function _getPermissionCheckInfo($event)
{
$perm_helper =& $this->Application->recallObject('PermissionsHelper');
/* @var $perm_helper kPermissionsHelper */
// when saving data from temp table to live table check by data from temp table
$item_ids = $this->_getPermissionCheckIDs($event);
$items = $perm_helper->GetCategoryItemData($event->Prefix, $item_ids, $event->Name == 'OnSave');
if (!$items) {
// when item not present in temp table, then permission is not checked, because there are no data in db to check
$items_info = $this->Application->GetVar( $event->getPrefixSpecial(true) );
list ($id, $fields_hash) = each($items_info);
if (array_key_exists('CategoryId', $fields_hash)) {
$item_category = $fields_hash['CategoryId'];
}
else {
$item_category = $this->Application->GetVar('m_cat_id');
}
$items[$id] = Array (
'CreatedById' => $this->Application->RecallVar('use_id'),
'CategoryId' => $item_category,
);
}
return $items;
}
/**
* Add selected items to clipboard with mode = COPY (CLONE)
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnCopy(&$event)
+ protected function OnCopy($event)
{
$this->Application->RemoveVar('clipboard');
$clipboard_helper =& $this->Application->recallObject('ClipboardHelper');
/* @var $clipboard_helper kClipboardHelper */
$clipboard_helper->setClipboard($event, 'copy', $this->StoreSelectedIDs($event));
$this->clearSelectedIDs($event);
}
/**
* Add selected items to clipboard with mode = CUT
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnCut(&$event)
+ protected function OnCut($event)
{
$this->Application->RemoveVar('clipboard');
$clipboard_helper =& $this->Application->recallObject('ClipboardHelper');
/* @var $clipboard_helper kClipboardHelper */
$clipboard_helper->setClipboard($event, 'cut', $this->StoreSelectedIDs($event));
$this->clearSelectedIDs($event);
}
/**
* Checks permission for OnPaste event
*
* @param kEvent $event
* @return bool
*/
- function _checkPastePermission(&$event)
+ function _checkPastePermission($event)
{
$perm_helper =& $this->Application->recallObject('PermissionsHelper');
/* @var $perm_helper kPermissionsHelper */
$category_id = $this->Application->GetVar('m_cat_id');
if ($perm_helper->AddCheckPermission($category_id, $event->Prefix) == 0) {
// no items left for editing -> no permission
return $perm_helper->finalizePermissionCheck($event, false);
}
return true;
}
/**
* Performs category item paste
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnPaste(&$event)
+ protected function OnPaste($event)
{
if ( $this->Application->CheckPermission('SYSTEM_ACCESS.READONLY', 1) || !$this->_checkPastePermission($event) ) {
$event->status = kEvent::erFAIL;
return;
}
$clipboard_data = $event->getEventParam('clipboard_data');
if ( !$clipboard_data['cut'] && !$clipboard_data['copy'] ) {
return;
}
if ( $clipboard_data['copy'] ) {
$temp =& $this->Application->recallObject($event->getPrefixSpecial() . '_TempHandler', 'kTempTablesHandler');
/* @var $temp kTempTablesHandler */
$this->Application->SetVar('ResetCatBeforeClone', 1); // used in "kCatDBEventHandler::OnBeforeClone"
$temp->CloneItems($event->Prefix, $event->Special, $clipboard_data['copy']);
}
if ( $clipboard_data['cut'] ) {
$object =& $this->Application->recallObject($event->getPrefixSpecial() . '.item', $event->Prefix, Array ('skip_autoload' => true));
/* @var $object kCatDBItem */
foreach ($clipboard_data['cut'] as $id) {
$object->Load($id);
$object->MoveToCat();
}
}
}
/**
* 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(kEvent &$event)
+ protected function OnMassDelete(kEvent $event)
{
if ( $this->Application->CheckPermission('SYSTEM_ACCESS.READONLY', 1) ) {
$event->status = kEvent::erFAIL;
return;
}
$ids = $this->StoreSelectedIDs($event);
$to_delete = Array ();
$recycle_bin = $this->Application->ConfigValue('RecycleBinFolder');
if ( $recycle_bin ) {
$rb =& $this->Application->recallObject('c.recycle', null, array ('skip_autoload' => true));
/* @var $rb CategoriesItem */
$rb->Load($recycle_bin);
$object =& $this->Application->recallObject($event->Prefix . '.recycleitem', null, Array ('skip_autoload' => true));
/* @var $object kCatDBItem */
foreach ($ids as $id) {
$object->Load($id);
if ( preg_match('/^' . preg_quote($rb->GetDBField('ParentPath'), '/') . '/', $object->GetDBField('ParentPath')) ) {
$to_delete[] = $id;
continue;
}
$object->MoveToCat($recycle_bin);
}
$ids = $to_delete;
}
$temp_handler =& $this->Application->recallObject($event->getPrefixSpecial() . '_TempHandler', 'kTempTablesHandler');
/* @var $temp_handler kTempTablesHandler */
$event->setEventParam('ids', $ids);
$this->customProcessing($event, 'before');
$ids = $event->getEventParam('ids');
if ( $ids ) {
$temp_handler->DeleteItems($event->Prefix, $event->Special, $ids);
}
$this->clearSelectedIDs($event);
}
/**
* Return type clauses for list bulding on front
*
* @param kEvent $event
* @return Array
*/
- function getTypeClauses(&$event)
+ function getTypeClauses($event)
{
$types = $event->getEventParam('types');
$types = $types ? explode(',', $types) : Array ();
$except_types = $event->getEventParam('except');
$except_types = $except_types ? explode(',', $except_types) : Array ();
$type_clauses = Array();
$user_id = $this->Application->RecallVar('user_id');
$owner_field = $this->getOwnerField($event->Prefix);
$type_clauses['my_items']['include'] = '%1$s.'.$owner_field.' = '.$user_id;
$type_clauses['my_items']['except'] = '%1$s.'.$owner_field.' <> '.$user_id;
$type_clauses['my_items']['having_filter'] = false;
$type_clauses['pick']['include'] = '%1$s.EditorsPick = 1 AND '.TABLE_PREFIX.'CategoryItems.PrimaryCat = 1';
$type_clauses['pick']['except'] = '%1$s.EditorsPick! = 1 AND '.TABLE_PREFIX.'CategoryItems.PrimaryCat = 1';
$type_clauses['pick']['having_filter'] = false;
$type_clauses['hot']['include'] = '`IsHot` = 1 AND PrimaryCat = 1';
$type_clauses['hot']['except'] = '`IsHot`! = 1 AND PrimaryCat = 1';
$type_clauses['hot']['having_filter'] = true;
$type_clauses['pop']['include'] = '`IsPop` = 1 AND PrimaryCat = 1';
$type_clauses['pop']['except'] = '`IsPop`! = 1 AND PrimaryCat = 1';
$type_clauses['pop']['having_filter'] = true;
$type_clauses['new']['include'] = '`IsNew` = 1 AND PrimaryCat = 1';
$type_clauses['new']['except'] = '`IsNew`! = 1 AND PrimaryCat = 1';
$type_clauses['new']['having_filter'] = true;
$type_clauses['displayed']['include'] = '';
$displayed = $this->Application->GetVar($event->Prefix.'_displayed_ids');
if ($displayed) {
$id_field = $this->Application->getUnitOption($event->Prefix, 'IDField');
$type_clauses['displayed']['except'] = '%1$s.'.$id_field.' NOT IN ('.$displayed.')';
}
else {
$type_clauses['displayed']['except'] = '';
}
$type_clauses['displayed']['having_filter'] = false;
if (in_array('search', $types) || in_array('search', $except_types)) {
$event_mapping = Array (
'simple' => 'OnSimpleSearch',
'subsearch' => 'OnSubSearch',
'advanced' => 'OnAdvancedSearch'
);
$keywords = $event->getEventParam('keyword_string');
$type = $this->Application->GetVar('search_type', 'simple');
if ( $keywords ) {
// processing keyword_string param of ListProducts tag
$this->Application->SetVar('keywords', $keywords);
$type = 'simple';
}
$search_event = $event_mapping[$type];
$this->$search_event($event);
$object =& $event->getObject();
/* @var $object kDBList */
$search_sql = ' FROM ' . TABLE_PREFIX . 'ses_' . $this->Application->GetSID() . '_' . TABLE_PREFIX . 'Search
search_result LEFT JOIN %1$s ON %1$s.ResourceId = search_result.ResourceId';
$sql = str_replace('FROM %1$s', $search_sql, $object->GetPlainSelectSQL());
$object->SetSelectSQL($sql);
$object->addCalculatedField('Relevance', 'search_result.Relevance');
$object->AddOrderField('search_result.Relevance', 'desc', true);
$type_clauses['search']['include'] = 'PrimaryCat = 1 AND ('.TABLE_PREFIX.'Categories.Status = '.STATUS_ACTIVE.')';
$type_clauses['search']['except'] = 'PrimaryCat = 1 AND ('.TABLE_PREFIX.'Categories.Status = '.STATUS_ACTIVE.')';
$type_clauses['search']['having_filter'] = false;
}
if (in_array('related', $types) || in_array('related', $except_types)) {
$related_to = $event->getEventParam('related_to');
if (!$related_to) {
$related_prefix = $event->Prefix;
}
else {
$sql = 'SELECT Prefix
FROM '.TABLE_PREFIX.'ItemTypes
WHERE ItemName = '.$this->Conn->qstr($related_to);
$related_prefix = $this->Conn->GetOne($sql);
}
$rel_table = $this->Application->getUnitOption('rel', 'TableName');
$item_type = (int)$this->Application->getUnitOption($event->Prefix, 'ItemType');
if ($item_type == 0) {
trigger_error('<strong>ItemType</strong> not defined for prefix <strong>' . $event->Prefix . '</strong>', E_USER_WARNING);
}
// process case, then this list is called inside another list
$prefix_special = $event->getEventParam('PrefixSpecial');
if (!$prefix_special) {
$prefix_special = $this->Application->Parser->GetParam('PrefixSpecial');
}
$id = false;
if ($prefix_special !== false) {
$processed_prefix = $this->Application->processPrefix($prefix_special);
if ($processed_prefix['prefix'] == $related_prefix) {
// printing related categories within list of items (not on details page)
$list =& $this->Application->recallObject($prefix_special);
/* @var $list kDBList */
$id = $list->GetID();
}
}
if ($id === false) {
// printing related categories for single item (possibly on details page)
if ($related_prefix == 'c') {
$id = $this->Application->GetVar('m_cat_id');
}
else {
$id = $this->Application->GetVar($related_prefix . '_id');
}
}
$p_item =& $this->Application->recallObject($related_prefix.'.current', null, Array('skip_autoload' => true));
/* @var $p_item kCatDBItem */
$p_item->Load( (int)$id );
$p_resource_id = $p_item->GetDBField('ResourceId');
$sql = 'SELECT SourceId, TargetId FROM '.$rel_table.'
WHERE
(Enabled = 1)
AND (
(Type = 0 AND SourceId = '.$p_resource_id.' AND TargetType = '.$item_type.')
OR
(Type = 1
AND (
(SourceId = '.$p_resource_id.' AND TargetType = '.$item_type.')
OR
(TargetId = '.$p_resource_id.' AND SourceType = '.$item_type.')
)
)
)';
$related_ids_array = $this->Conn->Query($sql);
$related_ids = Array();
foreach ($related_ids_array as $record) {
$related_ids[] = $record[ $record['SourceId'] == $p_resource_id ? 'TargetId' : 'SourceId' ];
}
if (count($related_ids) > 0) {
$type_clauses['related']['include'] = '%1$s.ResourceId IN ('.implode(',', $related_ids).') AND PrimaryCat = 1';
$type_clauses['related']['except'] = '%1$s.ResourceId NOT IN ('.implode(',', $related_ids).') AND PrimaryCat = 1';
}
else {
$type_clauses['related']['include'] = '0';
$type_clauses['related']['except'] = '1';
}
$type_clauses['related']['having_filter'] = false;
}
if (in_array('favorites', $types) || in_array('favorites', $except_types)) {
$sql = 'SELECT ResourceId
FROM '.$this->Application->getUnitOption('fav', 'TableName').'
WHERE PortalUserId = '.$this->Application->RecallVar('user_id');
$favorite_ids = $this->Conn->GetCol($sql);
if ($favorite_ids) {
$type_clauses['favorites']['include'] = '%1$s.ResourceId IN ('.implode(',', $favorite_ids).') AND PrimaryCat = 1';
$type_clauses['favorites']['except'] = '%1$s.ResourceId NOT IN ('.implode(',', $favorite_ids).') AND PrimaryCat = 1';
}
else {
$type_clauses['favorites']['include'] = 0;
$type_clauses['favorites']['except'] = 1;
}
$type_clauses['favorites']['having_filter'] = false;
}
return $type_clauses;
}
/**
* Returns SQL clause, that will help to select only data from specified category & it's children
*
* @param int $category_id
* @return string
*/
function getCategoryLimitClause($category_id)
{
if (!$category_id) {
return false;
}
$tree_indexes = $this->Application->getTreeIndex($category_id);
if (!$tree_indexes) {
// id of non-existing category was given
return 'FALSE';
}
return TABLE_PREFIX.'Categories.TreeLeft BETWEEN '.$tree_indexes['TreeLeft'].' AND '.$tree_indexes['TreeRight'];
}
/**
* Apply any custom changes to list's sql query
*
* @param kEvent $event
* @return void
* @access protected
* @see kDBEventHandler::OnListBuild()
*/
- protected function SetCustomQuery(kEvent &$event)
+ protected function SetCustomQuery(kEvent $event)
{
parent::SetCustomQuery($event);
$object =& $event->getObject();
/* @var $object kDBList */
// add category filter if needed
if ($event->Special != 'showall' && $event->Special != 'user') {
if ( (string)$event->getEventParam('parent_cat_id') !== '' ) {
$parent_cat_id = $event->getEventParam('parent_cat_id');
}
else {
$parent_cat_id = $this->Application->GetVar('c_id');
if (!$parent_cat_id) {
$parent_cat_id = $this->Application->GetVar('m_cat_id');
}
if (!$parent_cat_id) {
$parent_cat_id = 0;
}
}
if ("$parent_cat_id" == '0') {
// replace "0" category with "Content" category id (this way template
$parent_cat_id = $this->Application->getBaseCategory();
}
if ((string)$parent_cat_id != 'any') {
if ($event->getEventParam('recursive')) {
$filter_clause = $this->getCategoryLimitClause($parent_cat_id);
if ($filter_clause !== false) {
$object->addFilter('category_filter', $filter_clause);
}
$object->addFilter('primary_filter', 'PrimaryCat = 1');
}
else {
$object->addFilter('category_filter', TABLE_PREFIX.'CategoryItems.CategoryId = '.$parent_cat_id );
}
}
else {
$object->addFilter('primary_filter', 'PrimaryCat = 1');
}
}
else {
$object->addFilter('primary_filter', 'PrimaryCat = 1');
// if using recycle bin don't show items from there
$recycle_bin = $this->Application->ConfigValue('RecycleBinFolder');
if ($recycle_bin) {
$object->addFilter('recyclebin_filter', TABLE_PREFIX.'CategoryItems.CategoryId <> '.$recycle_bin);
}
}
if ($event->Special == 'user') {
$editable_user = $this->Application->GetVar('u_id');
$object->addFilter('owner_filter', '%1$s.'.$this->getOwnerField($event->Prefix).' = '.$editable_user);
}
// add permission filter
if ($this->Application->RecallVar('user_id') == USER_ROOT) {
// for "root" CATEGORY.VIEW permission is checked for items lists too
$view_perm = 1;
}
else {
// for any real user itemlist view permission is checked instead of CATEGORY.VIEW
$count_helper =& $this->Application->recallObject('CountHelper');
/* @var $count_helper kCountHelper */
list ($view_perm, $view_filter) = $count_helper->GetPermissionClause($event->Prefix, 'perm');
$object->addFilter('perm_filter2', $view_filter);
}
$object->addFilter('perm_filter', 'perm.PermId = '.$view_perm);
$types = $event->getEventParam('types');
$this->applyItemStatusFilter($object, $types);
$except_types = $event->getEventParam('except');
$type_clauses = $this->getTypeClauses($event);
$search_helper =& $this->Application->recallObject('SearchHelper');
/* @var $search_helper kSearchHelper */
$search_helper->SetComplexFilter($event, $type_clauses, $types, $except_types);
}
/**
* Adds filter that filters out items with non-required statuses
*
* @param kDBList $object
* @param string $types
*/
function applyItemStatusFilter(&$object, $types)
{
// Link1 (before modifications) [Status = 1, OrgId = NULL], Link2 (after modifications) [Status = -2, OrgId = Link1_ID]
$pending_editing = $this->Application->getUnitOption($object->Prefix, 'UsePendingEditing');
if (!$this->Application->isAdminUser) {
$types = explode(',', $types);
if (in_array('my_items', $types)) {
$allow_statuses = Array (STATUS_ACTIVE, STATUS_PENDING, STATUS_PENDING_EDITING);
$object->addFilter('status_filter', '%1$s.Status IN ('.implode(',', $allow_statuses).')');
if ($pending_editing) {
$user_id = $this->Application->RecallVar('user_id');
$this->applyPendingEditingFilter($object, $user_id);
}
}
else {
$object->addFilter('status_filter', '(%1$s.Status = ' . STATUS_ACTIVE . ') AND (' . TABLE_PREFIX . 'Categories.Status = ' . STATUS_ACTIVE . ')');
if ($pending_editing) {
// if category item uses pending editing abilities, then in no cases show pending copies on front
$object->addFilter('original_filter', '%1$s.OrgId = 0 OR %1$s.OrgId IS NULL');
}
}
}
else {
if ($pending_editing) {
$this->applyPendingEditingFilter($object);
}
}
}
/**
* Adds filter, that removes live items if they have pending editing copies
*
* @param kDBList $object
* @param int $user_id
*/
function applyPendingEditingFilter(&$object, $user_id = null)
{
$sql = 'SELECT OrgId
FROM '.$object->TableName.'
WHERE Status = '.STATUS_PENDING_EDITING.' AND OrgId IS NOT NULL';
if (isset($user_id)) {
$owner_field = $this->getOwnerField($object->Prefix);
$sql .= ' AND '.$owner_field.' = '.$user_id;
}
$pending_ids = $this->Conn->GetCol($sql);
if ($pending_ids) {
$object->addFilter('no_original_filter', '%1$s.'.$object->IDField.' NOT IN ('.implode(',', $pending_ids).')');
}
}
/**
* Adds calculates fields for item statuses
*
* @param kDBItem|kDBList $object
* @param kEvent $event
* @return void
* @access protected
*/
- protected function prepareObject(&$object, kEvent &$event)
+ protected function prepareObject(&$object, kEvent $event)
{
$this->prepareItemStatuses($event);
$object->addCalculatedField('CachedNavbar', 'l' . $this->Application->GetVar('m_lang') . '_CachedNavbar');
if ( $event->Special == 'export' || $event->Special == 'import' ) {
$export_helper =& $this->Application->recallObject('CatItemExportHelper');
/* @var $export_helper kCatDBItemExportHelper */
$export_helper->prepareExportColumns($event);
}
}
/**
* Creates calculated fields for all item statuses based on config settings
*
* @param kEvent $event
*/
- function prepareItemStatuses(&$event)
+ function prepareItemStatuses($event)
{
$object =& $event->getObject( Array('skip_autoload' => true) );
$property_map = $this->Application->getUnitOption($event->Prefix, 'ItemPropertyMappings');
if (!$property_map) {
return ;
}
// new items
$object->addCalculatedField('IsNew', ' IF(%1$s.NewItem = 2,
IF(%1$s.CreatedOn >= (UNIX_TIMESTAMP() - '.
$this->Application->ConfigValue($property_map['NewDays']).
'*3600*24), 1, 0),
%1$s.NewItem
)');
// hot items (cache updated every hour)
if ($this->Application->isCachingType(CACHING_TYPE_MEMORY)) {
$serial_name = $this->Application->incrementCacheSerial($event->Prefix, null, false);
$hot_limit = $this->Application->getCache($property_map['HotLimit'] . '[%' . $serial_name . '%]');
}
else {
$hot_limit = $this->Application->getDBCache($property_map['HotLimit']);
}
if ($hot_limit === false) {
$hot_limit = $this->CalculateHotLimit($event);
}
$object->addCalculatedField('IsHot', ' IF(%1$s.HotItem = 2,
IF(%1$s.'.$property_map['ClickField'].' >= '.$hot_limit.', 1, 0),
%1$s.HotItem
)');
// popular items
$object->addCalculatedField('IsPop', ' IF(%1$s.PopItem = 2,
IF(%1$s.CachedVotesQty >= '.
$this->Application->ConfigValue($property_map['MinPopVotes']).
' AND %1$s.CachedRating >= '.
$this->Application->ConfigValue($property_map['MinPopRating']).
', 1, 0),
%1$s.PopItem)');
}
/**
* Calculates hot limit for current item's table
*
* @param kEvent $event
* @return float
* @access protected
*/
- protected function CalculateHotLimit(&$event)
+ protected function CalculateHotLimit($event)
{
$property_map = $this->Application->getUnitOption($event->Prefix, 'ItemPropertyMappings');
if ( !$property_map ) {
return 0.00;
}
$click_field = $property_map['ClickField'];
$last_hot = $this->Application->ConfigValue($property_map['MaxHotNumber']) - 1;
$sql = 'SELECT ' . $click_field . '
FROM ' . $this->Application->getUnitOption($event->Prefix, 'TableName') . '
ORDER BY ' . $click_field . ' DESC
LIMIT ' . $last_hot . ', 1';
$res = $this->Conn->GetCol($sql);
$hot_limit = (double)array_shift($res);
if ( $this->Application->isCachingType(CACHING_TYPE_MEMORY) ) {
$serial_name = $this->Application->incrementCacheSerial($event->Prefix, null, false);
$this->Application->setCache($property_map['HotLimit'] . '[%' . $serial_name . '%]', $hot_limit);
}
else {
$this->Application->setDBCache($property_map['HotLimit'], $hot_limit, 3600);
}
return $hot_limit;
}
/**
* Moves item to preferred category, updates item hits
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnBeforeItemUpdate(kEvent &$event)
+ protected function OnBeforeItemUpdate(kEvent $event)
{
parent::OnBeforeItemUpdate($event);
$object =& $event->getObject();
/* @var $object kCatDBItem */
// update hits field
$property_map = $this->Application->getUnitOption($event->Prefix, 'ItemPropertyMappings');
if ( $property_map ) {
$click_field = $property_map['ClickField'];
if ( $this->Application->isAdminUser && ($this->Application->GetVar($click_field . '_original') !== false) && floor($this->Application->GetVar($click_field . '_original')) != $object->GetDBField($click_field) ) {
$sql = 'SELECT MAX(' . $click_field . ')
FROM ' . $this->Application->getUnitOption($event->Prefix, 'TableName') . '
WHERE FLOOR(' . $click_field . ') = ' . $object->GetDBField($click_field);
$hits = ($res = $this->Conn->GetOne($sql)) ? $res + 0.000001 : $object->GetDBField($click_field);
$object->SetDBField($click_field, $hits);
}
}
// change category
$target_category = $object->GetDBField('CategoryId');
if ( $object->GetOriginalField('CategoryId') != $target_category ) {
$object->MoveToCat($target_category);
}
}
/**
* Occurs after loading item, 'id' parameter
* allows to get id of item that was loaded
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnAfterItemLoad(kEvent &$event)
+ protected function OnAfterItemLoad(kEvent $event)
{
parent::OnAfterItemLoad($event);
$special = substr($event->Special, -6);
$object =& $event->getObject();
/* @var $object kCatDBItem */
if ( $special == 'import' || $special == 'export' ) {
$image_data = $object->getPrimaryImageData();
if ( $image_data ) {
$thumbnail_image = $image_data[$image_data['LocalThumb'] ? 'ThumbPath' : 'ThumbUrl'];
if ( $image_data['SameImages'] ) {
$full_image = '';
}
else {
$full_image = $image_data[$image_data['LocalImage'] ? 'LocalPath' : 'Url'];
}
$object->SetDBField('ThumbnailImage', $thumbnail_image);
$object->SetDBField('FullImage', $full_image);
$object->SetDBField('ImageAlt', $image_data['AltName']);
}
}
// substituting pending status value for pending editing
if ( $object->HasField('OrgId') && $object->GetDBField('OrgId') > 0 && $object->GetDBField('Status') == -2 ) {
$new_options = Array ();
$options = $object->GetFieldOption('Status', 'options', false, Array ());
foreach ($options as $key => $val) {
if ( $key == 2 ) {
$key = -2;
}
$new_options[$key] = $val;
}
$object->SetFieldOption('Status', 'options', $new_options);
}
if ( !$this->Application->isAdmin ) {
// linking existing images for item with virtual fields
$image_helper =& $this->Application->recallObject('ImageHelper');
/* @var $image_helper ImageHelper */
$image_helper->LoadItemImages($object);
// linking existing files for item with virtual fields
$file_helper =& $this->Application->recallObject('FileHelper');
/* @var $file_helper FileHelper */
$file_helper->LoadItemFiles($object);
}
if ( $object->isVirtualField('MoreCategories') ) {
// set item's additional categories to virtual field (used in editing)
$item_categories = $this->getItemCategories($object->GetDBField('ResourceId'));
$object->SetDBField('MoreCategories', $item_categories ? '|' . implode('|', $item_categories) . '|' : '');
}
}
/**
* Occurs after updating item
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnAfterItemUpdate(kEvent &$event)
+ protected function OnAfterItemUpdate(kEvent $event)
{
parent::OnAfterItemUpdate($event);
$this->CalculateHotLimit($event);
if ( substr($event->Special, -6) == 'import' ) {
$this->setCustomExportColumns($event);
}
$object =& $event->getObject();
/* @var $object kCatDBItem */
if ( !$this->Application->isAdmin ) {
$image_helper =& $this->Application->recallObject('ImageHelper');
/* @var $image_helper ImageHelper */
// process image upload in virtual fields
$image_helper->SaveItemImages($object);
$file_helper =& $this->Application->recallObject('FileHelper');
/* @var $file_helper FileHelper */
// process file upload in virtual fields
$file_helper->SaveItemFiles($object);
if ( $event->Special != '-item' ) {
// don't touch categories during cloning
$this->processAdditionalCategories($object, 'update');
}
}
$recycle_bin = $this->Application->ConfigValue('RecycleBinFolder');
if ( $this->Application->isAdminUser && $recycle_bin ) {
$sql = 'SELECT CategoryId
FROM ' . $this->Application->getUnitOption('ci', 'TableName') . '
WHERE ItemResourceId = ' . $object->GetDBField('ResourceId') . ' AND PrimaryCat = 1';
$primary_category = $this->Conn->GetOne($sql);
if ( $primary_category == $recycle_bin ) {
$event->CallSubEvent('OnAfterItemDelete');
}
}
if ( $object->GetChangedFields() ) {
$now = adodb_mktime();
$object->SetDBField('Modified_date', $now);
$object->SetDBField('Modified_time', $now);
$object->SetDBField('ModifiedById', $this->Application->RecallVar('user_id'));
}
}
/**
* Sets values for import process
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnAfterItemCreate(kEvent &$event)
+ protected function OnAfterItemCreate(kEvent $event)
{
parent::OnAfterItemCreate($event);
$object =& $event->getObject();
/* @var $object kCatDBItem */
if ( substr($event->Special, -6) == 'import' ) {
$this->setCustomExportColumns($event);
}
$object->assignPrimaryCategory();
if ( !$this->Application->isAdmin ) {
$image_helper =& $this->Application->recallObject('ImageHelper');
/* @var $image_helper ImageHelper */
// process image upload in virtual fields
$image_helper->SaveItemImages($object);
$file_helper =& $this->Application->recallObject('FileHelper');
/* @var $file_helper FileHelper */
// process file upload in virtual fields
$file_helper->SaveItemFiles($object);
if ( $event->Special != '-item' ) {
// don't touch categories during cloning
$this->processAdditionalCategories($object, 'create');
}
}
}
/**
* Make record to search log
*
* @param string $keywords
* @param int $search_type 0 - simple search, 1 - advanced search
*/
function saveToSearchLog($keywords, $search_type = 0)
{
// don't save keywords for each module separately, just one time
// static variable can't help here, because each module uses it's own class instance !
if (!$this->Application->GetVar('search_logged')) {
$sql = 'UPDATE '.TABLE_PREFIX.'SearchLogs
SET Indices = Indices + 1
WHERE Keyword = '.$this->Conn->qstr($keywords).' AND SearchType = '.$search_type; // 0 - simple search, 1 - advanced search
$this->Conn->Query($sql);
if ($this->Conn->getAffectedRows() == 0) {
$fields_hash = Array('Keyword' => $keywords, 'Indices' => 1, 'SearchType' => $search_type);
$this->Conn->doInsert($fields_hash, TABLE_PREFIX.'SearchLogs');
}
$this->Application->SetVar('search_logged', 1);
}
}
/**
* Makes simple search for category items
* based on keywords string
*
* @param kEvent $event
*/
- function OnSimpleSearch(&$event)
+ function OnSimpleSearch($event)
{
$event->redirect = false;
$search_table = TABLE_PREFIX.'ses_'.$this->Application->GetSID().'_'.TABLE_PREFIX.'Search';
$keywords = kUtil::unhtmlentities( trim($this->Application->GetVar('keywords')) );
$query_object =& $this->Application->recallObject('HTTPQuery');
/* @var $query_object kHTTPQuery */
$sql = 'SHOW TABLES LIKE "'.$search_table.'"';
if(!isset($query_object->Get['keywords']) &&
!isset($query_object->Post['keywords']) &&
$this->Conn->Query($sql))
{
return; // used when navigating by pages or changing sorting in search results
}
if(!$keywords || strlen($keywords) < $this->Application->ConfigValue('Search_MinKeyword_Length'))
{
$this->Conn->Query('DROP TABLE IF EXISTS '.$search_table);
$this->Application->SetVar('keywords_too_short', 1);
return; // if no or too short keyword entered, doing nothing
}
$this->Application->StoreVar('keywords', $keywords);
$this->saveToSearchLog($keywords, 0); // 0 - simple search, 1 - advanced search
$event->setPseudoClass('_List');
$object =& $event->getObject();
/* @var $object kDBList */
$this->Application->SetVar($event->getPrefixSpecial().'_Page', 1);
$lang = $this->Application->GetVar('m_lang');
$items_table = $this->Application->getUnitOption($event->Prefix, 'TableName');
$module_name = $this->Application->findModule('Var', $event->Prefix, 'Name');
$sql = 'SELECT *
FROM ' . $this->Application->getUnitOption('confs', 'TableName') . '
WHERE ModuleName = ' . $this->Conn->qstr($module_name) . ' AND SimpleSearch = 1';
$search_config = $this->Conn->Query($sql, 'FieldName');
$field_list = array_keys($search_config);
$join_clauses = Array();
// field processing
$weight_sum = 0;
$alias_counter = 0;
$custom_fields = $this->Application->getUnitOption($event->Prefix, 'CustomFields');
if ($custom_fields) {
$custom_table = $this->Application->getUnitOption($event->Prefix.'-cdata', 'TableName');
$join_clauses[] = ' LEFT JOIN '.$custom_table.' custom_data ON '.$items_table.'.ResourceId = custom_data.ResourceId';
}
// what field in search config becomes what field in sql (key - new field, value - old field (from searchconfig table))
$search_config_map = Array();
foreach ($field_list as $key => $field) {
$local_table = TABLE_PREFIX.$search_config[$field]['TableName'];
$weight_sum += $search_config[$field]['Priority']; // counting weight sum; used when making relevance clause
// processing multilingual fields
if ( !$search_config[$field]['CustomFieldId'] && $object->GetFieldOption($field, 'formatter') == 'kMultiLanguage' ) {
$field_list[$key.'_primary'] = 'l'.$this->Application->GetDefaultLanguageId().'_'.$field;
$field_list[$key] = 'l'.$lang.'_'.$field;
if (!isset($search_config[$field]['ForeignField'])) {
$field_list[$key.'_primary'] = $local_table.'.'.$field_list[$key.'_primary'];
$search_config_map[ $field_list[$key.'_primary'] ] = $field;
}
}
// processing fields from other tables
$foreign_field = $search_config[$field]['ForeignField'];
if ( $foreign_field ) {
$exploded = explode(':', $foreign_field, 2);
if ($exploded[0] == 'CALC') {
// ignoring having type clauses in simple search
unset($field_list[$key]);
continue;
}
else {
$multi_lingual = false;
if ($exploded[0] == 'MULTI') {
$multi_lingual = true;
$foreign_field = $exploded[1];
}
$exploded = explode('.', $foreign_field); // format: table.field_name
$foreign_table = TABLE_PREFIX.$exploded[0];
$alias_counter++;
$alias = 't'.$alias_counter;
if ($multi_lingual) {
$field_list[$key] = $alias.'.'.'l'.$lang.'_'.$exploded[1];
$field_list[$key.'_primary'] = 'l'.$this->Application->GetDefaultLanguageId().'_'.$field;
$search_config_map[ $field_list[$key] ] = $field;
$search_config_map[ $field_list[$key.'_primary'] ] = $field;
}
else {
$field_list[$key] = $alias.'.'.$exploded[1];
$search_config_map[ $field_list[$key] ] = $field;
}
$join_clause = str_replace('{ForeignTable}', $alias, $search_config[$field]['JoinClause']);
$join_clause = str_replace('{LocalTable}', $items_table, $join_clause);
$join_clauses[] = ' LEFT JOIN '.$foreign_table.' '.$alias.'
ON '.$join_clause;
}
}
else {
// processing fields from local table
if ($search_config[$field]['CustomFieldId']) {
$local_table = 'custom_data';
// search by custom field value on current language
$custom_field_id = array_search($field_list[$key], $custom_fields);
$field_list[$key] = 'l'.$lang.'_cust_'.$custom_field_id;
// search by custom field value on primary language
$field_list[$key.'_primary'] = $local_table.'.l'.$this->Application->GetDefaultLanguageId().'_cust_'.$custom_field_id;
$search_config_map[ $field_list[$key.'_primary'] ] = $field;
}
$field_list[$key] = $local_table.'.'.$field_list[$key];
$search_config_map[ $field_list[$key] ] = $field;
}
}
// keyword string processing
$search_helper =& $this->Application->recallObject('SearchHelper');
/* @var $search_helper kSearchHelper */
$where_clause = Array ();
foreach ($field_list as $field) {
if (preg_match('/^' . preg_quote($items_table, '/') . '\.(.*)/', $field, $regs)) {
// local real field
$filter_data = $search_helper->getSearchClause($object, $regs[1], $keywords, false);
if ($filter_data) {
$where_clause[] = $filter_data['value'];
}
}
elseif (preg_match('/^custom_data\.(.*)/', $field, $regs)) {
$custom_field_name = 'cust_' . $search_config_map[$field];
$filter_data = $search_helper->getSearchClause($object, $custom_field_name, $keywords, false);
if ($filter_data) {
$where_clause[] = str_replace('`' . $custom_field_name . '`', $field, $filter_data['value']);
}
}
else {
$where_clause[] = $search_helper->buildWhereClause($keywords, Array ($field));
}
}
$where_clause = '((' . implode(') OR (', $where_clause) . '))'; // 2 braces for next clauses, see below!
$search_scope = $this->Application->GetVar('search_scope');
if ($search_scope == 'category') {
$category_id = $this->Application->GetVar('m_cat_id');
$category_filter = $this->getCategoryLimitClause($category_id);
if ($category_filter !== false) {
$join_clauses[] = ' LEFT JOIN '.TABLE_PREFIX.'CategoryItems ON '.TABLE_PREFIX.'CategoryItems.ItemResourceId = '.$items_table.'.ResourceId';
$join_clauses[] = ' LEFT JOIN '.TABLE_PREFIX.'Categories ON '.TABLE_PREFIX.'Categories.CategoryId = '.TABLE_PREFIX.'CategoryItems.CategoryId';
$where_clause = '('.$this->getCategoryLimitClause($category_id).') AND '.$where_clause;
}
}
$where_clause = $where_clause . ' AND (' . $items_table . '.Status = ' . STATUS_ACTIVE . ')';
if ($event->MasterEvent && $event->MasterEvent->Name == 'OnListBuild') {
if ($event->MasterEvent->getEventParam('ResultIds')) {
$where_clause .= ' AND '.$items_table.'.ResourceId IN ('.implode(',', $event->MasterEvent->getEventParam('ResultIds')).')';
}
}
// making relevance clause
$positive_words = $search_helper->getPositiveKeywords($keywords);
$this->Application->StoreVar('highlight_keywords', serialize($positive_words));
$revelance_parts = Array();
reset($search_config);
foreach ($positive_words as $keyword_index => $positive_word) {
$positive_word = $search_helper->transformWildcards($positive_word);
$positive_words[$keyword_index] = $this->Conn->escape($positive_word);
}
foreach ($field_list as $field) {
if (!array_key_exists($field, $search_config_map)) {
$map_key = $search_config_map[$items_table . '.' . $field];
}
else {
$map_key = $search_config_map[$field];
}
$config_elem = $search_config[ $map_key ];
$weight = $config_elem['Priority'];
// search by whole words only ([[:<:]] - word boundary)
/*$revelance_parts[] = 'IF('.$field.' REGEXP "[[:<:]]('.implode(' ', $positive_words).')[[:>:]]", '.$weight.', 0)';
foreach ($positive_words as $keyword) {
$revelance_parts[] = 'IF('.$field.' REGEXP "[[:<:]]('.$keyword.')[[:>:]]", '.$weight.', 0)';
}*/
// search by partial word matches too
$revelance_parts[] = 'IF('.$field.' LIKE "%'.implode(' ', $positive_words).'%", '.$weight_sum.', 0)';
foreach ($positive_words as $keyword) {
$revelance_parts[] = 'IF('.$field.' LIKE "%'.$keyword.'%", '.$weight.', 0)';
}
}
$revelance_parts = array_unique($revelance_parts);
$conf_postfix = $this->Application->getUnitOption($event->Prefix, 'SearchConfigPostfix');
$rel_keywords = $this->Application->ConfigValue('SearchRel_Keyword_'.$conf_postfix) / 100;
$rel_pop = $this->Application->ConfigValue('SearchRel_Pop_'.$conf_postfix) / 100;
$rel_rating = $this->Application->ConfigValue('SearchRel_Rating_'.$conf_postfix) / 100;
$relevance_clause = '('.implode(' + ', $revelance_parts).') / '.$weight_sum.' * '.$rel_keywords;
if ($rel_pop && $object->isField('Hits')) {
$relevance_clause .= ' + (Hits + 1) / (MAX(Hits) + 1) * '.$rel_pop;
}
if ($rel_rating && $object->isField('CachedRating')) {
$relevance_clause .= ' + (CachedRating + 1) / (MAX(CachedRating) + 1) * '.$rel_rating;
}
// building final search query
if (!$this->Application->GetVar('do_not_drop_search_table')) {
$this->Conn->Query('DROP TABLE IF EXISTS '.$search_table); // erase old search table if clean k4 event
$this->Application->SetVar('do_not_drop_search_table', true);
}
$search_table_exists = $this->Conn->Query('SHOW TABLES LIKE "'.$search_table.'"');
if ($search_table_exists) {
$select_intro = 'INSERT INTO '.$search_table.' (Relevance, ItemId, ResourceId, ItemType, EdPick) ';
}
else {
$select_intro = 'CREATE TABLE '.$search_table.' AS ';
}
$edpick_clause = $this->Application->getUnitOption($event->Prefix.'.EditorsPick', 'Fields') ? $items_table.'.EditorsPick' : '0';
$sql = $select_intro.' SELECT '.$relevance_clause.' AS Relevance,
'.$items_table.'.'.$this->Application->getUnitOption($event->Prefix, 'IDField').' AS ItemId,
'.$items_table.'.ResourceId,
'.$this->Application->getUnitOption($event->Prefix, 'ItemType').' AS ItemType,
'.$edpick_clause.' AS EdPick
FROM '.$object->TableName.'
'.implode(' ', $join_clauses).'
WHERE '.$where_clause.'
GROUP BY '.$items_table.'.'.$this->Application->getUnitOption($event->Prefix, 'IDField').' ORDER BY Relevance DESC';
$this->Conn->Query($sql);
if ( !$search_table_exists ) {
$sql = 'ALTER TABLE ' . $search_table . '
ADD INDEX (ResourceId),
ADD INDEX (Relevance)';
$this->Conn->Query($sql);
}
}
/**
* Enter description here...
*
* @param kEvent $event
*/
- function OnSubSearch(&$event)
+ function OnSubSearch($event)
{
$ids = Array ();
$search_table = TABLE_PREFIX . 'ses_' . $this->Application->GetSID() . '_' . TABLE_PREFIX . 'Search';
$sql = 'SHOW TABLES LIKE "' . $search_table . '"';
if ( $this->Conn->Query($sql) ) {
$sql = 'SELECT DISTINCT ResourceId
FROM ' . $search_table;
$ids = $this->Conn->GetCol($sql);
}
$event->setEventParam('ResultIds', $ids);
$event->CallSubEvent('OnSimpleSearch');
}
/**
* Enter description here...
*
* @param kEvent $event
* @todo Change all hardcoded Products table & In-Commerce module usage to dynamic usage from item config !!!
*/
- function OnAdvancedSearch(&$event)
+ function OnAdvancedSearch($event)
{
$query_object =& $this->Application->recallObject('HTTPQuery');
/* @var $query_object kHTTPQuery */
if ( !isset($query_object->Post['andor']) ) {
// used when navigating by pages or changing sorting in search results
return;
}
$this->Application->RemoveVar('keywords');
$this->Application->RemoveVar('Search_Keywords');
$module_name = $this->Application->findModule('Var', $event->Prefix, 'Name');
$sql = 'SELECT *
FROM '.$this->Application->getUnitOption('confs', 'TableName').'
WHERE (ModuleName = '.$this->Conn->qstr($module_name).') AND (AdvancedSearch = 1)';
$search_config = $this->Conn->Query($sql);
$lang = $this->Application->GetVar('m_lang');
$object =& $event->getObject();
/* @var $object kDBList */
$object->SetPage(1);
$items_table = $this->Application->getUnitOption($event->Prefix, 'TableName');
$search_keywords = $this->Application->GetVar('value'); // will not be changed
$keywords = $this->Application->GetVar('value'); // will be changed down there
$verbs = $this->Application->GetVar('verb');
$glues = $this->Application->GetVar('andor');
$and_conditions = Array();
$or_conditions = Array();
$and_having_conditions = Array();
$or_having_conditions = Array();
$join_clauses = Array();
$highlight_keywords = Array();
$relevance_parts = Array();
$alias_counter = 0;
$custom_fields = $this->Application->getUnitOption($event->Prefix, 'CustomFields');
if ($custom_fields) {
$custom_table = $this->Application->getUnitOption($event->Prefix.'-cdata', 'TableName');
$join_clauses[] = ' LEFT JOIN '.$custom_table.' custom_data ON '.$items_table.'.ResourceId = custom_data.ResourceId';
}
$search_log = '';
$weight_sum = 0;
// processing fields and preparing conditions
foreach ($search_config as $record) {
$field = $record['FieldName'];
$join_clause = '';
$condition_mode = 'WHERE';
// field processing
$local_table = TABLE_PREFIX.$record['TableName'];
$weight_sum += $record['Priority']; // counting weight sum; used when making relevance clause
// processing multilingual fields
if ( $object->GetFieldOption($field, 'formatter') == 'kMultiLanguage' ) {
$field_name = 'l'.$lang.'_'.$field;
}
else {
$field_name = $field;
}
// processing fields from other tables
$foreign_field = $record['ForeignField'];
if ( $foreign_field ) {
$exploded = explode(':', $foreign_field, 2);
if($exploded[0] == 'CALC')
{
$user_groups = $this->Application->RecallVar('UserGroups');
$field_name = str_replace('{PREFIX}', TABLE_PREFIX, $exploded[1]);
$join_clause = str_replace('{PREFIX}', TABLE_PREFIX, $record['JoinClause']);
$join_clause = str_replace('{USER_GROUPS}', $user_groups, $join_clause);
$join_clause = ' LEFT JOIN '.$join_clause;
$condition_mode = 'HAVING';
}
else {
$exploded = explode('.', $foreign_field);
$foreign_table = TABLE_PREFIX.$exploded[0];
if($record['CustomFieldId']) {
$exploded[1] = 'l'.$lang.'_'.$exploded[1];
}
$alias_counter++;
$alias = 't'.$alias_counter;
$field_name = $alias.'.'.$exploded[1];
$join_clause = str_replace('{ForeignTable}', $alias, $record['JoinClause']);
$join_clause = str_replace('{LocalTable}', $items_table, $join_clause);
if($record['CustomFieldId'])
{
$join_clause .= ' AND '.$alias.'.CustomFieldId='.$record['CustomFieldId'];
}
$join_clause = ' LEFT JOIN '.$foreign_table.' '.$alias.'
ON '.$join_clause;
}
}
else
{
// processing fields from local table
if ($record['CustomFieldId']) {
$local_table = 'custom_data';
$field_name = 'l'.$lang.'_cust_'.array_search($field_name, $custom_fields);
}
$field_name = $local_table.'.'.$field_name;
}
$condition = $this->getAdvancedSearchCondition($field_name, $record, $keywords, $verbs, $highlight_keywords);
if ($record['CustomFieldId'] && strlen($condition)) {
// search in primary value of custom field + value in current language
$field_name = $local_table.'.'.'l'.$this->Application->GetDefaultLanguageId().'_cust_'.array_search($field, $custom_fields);
$primary_condition = $this->getAdvancedSearchCondition($field_name, $record, $keywords, $verbs, $highlight_keywords);
$condition = '('.$condition.' OR '.$primary_condition.')';
}
if ($condition) {
if ($join_clause) {
$join_clauses[] = $join_clause;
}
$relevance_parts[] = 'IF('.$condition.', '.$record['Priority'].', 0)';
if ($glues[$field] == 1) { // and
if ($condition_mode == 'WHERE') {
$and_conditions[] = $condition;
}
else {
$and_having_conditions[] = $condition;
}
}
else { // or
if ($condition_mode == 'WHERE') {
$or_conditions[] = $condition;
}
else {
$or_having_conditions[] = $condition;
}
}
// create search log record
$search_log_data = Array('search_config' => $record, 'verb' => getArrayValue($verbs, $field), 'value' => ($record['FieldType'] == 'range') ? $search_keywords[$field.'_from'].'|'.$search_keywords[$field.'_to'] : $search_keywords[$field]);
$search_log[] = $this->Application->Phrase('la_Field').' "'.$this->getHuman('Field', $search_log_data).'" '.$this->getHuman('Verb', $search_log_data).' '.$this->Application->Phrase('la_Value').' '.$this->getHuman('Value', $search_log_data).' '.$this->Application->Phrase($glues[$field] == 1 ? 'lu_And' : 'lu_Or');
}
}
if ($search_log) {
$search_log = implode('<br />', $search_log);
$search_log = preg_replace('/(.*) '.preg_quote($this->Application->Phrase('lu_and'), '/').'|'.preg_quote($this->Application->Phrase('lu_or'), '/').'$/is', '\\1', $search_log);
$this->saveToSearchLog($search_log, 1); // advanced search
}
$this->Application->StoreVar('highlight_keywords', serialize($highlight_keywords));
// making relevance clause
if($relevance_parts)
{
$conf_postfix = $this->Application->getUnitOption($event->Prefix, 'SearchConfigPostfix');
$rel_keywords = $this->Application->ConfigValue('SearchRel_Keyword_'.$conf_postfix) / 100;
$rel_pop = $this->Application->ConfigValue('SearchRel_Pop_'.$conf_postfix) / 100;
$rel_rating = $this->Application->ConfigValue('SearchRel_Rating_'.$conf_postfix) / 100;
$relevance_clause = '('.implode(' + ', $relevance_parts).') / '.$weight_sum.' * '.$rel_keywords;
$relevance_clause .= ' + (Hits + 1) / (MAX(Hits) + 1) * '.$rel_pop;
$relevance_clause .= ' + (CachedRating + 1) / (MAX(CachedRating) + 1) * '.$rel_rating;
}
else
{
$relevance_clause = '0';
}
// building having clause
if($or_having_conditions)
{
$and_having_conditions[] = '('.implode(' OR ', $or_having_conditions).')';
}
$having_clause = implode(' AND ', $and_having_conditions);
$having_clause = $having_clause ? ' HAVING '.$having_clause : '';
// building where clause
if($or_conditions)
{
$and_conditions[] = '('.implode(' OR ', $or_conditions).')';
}
// $and_conditions[] = $items_table.'.Status = 1';
$where_clause = implode(' AND ', $and_conditions);
if(!$where_clause)
{
if($having_clause)
{
$where_clause = '1';
}
else
{
$where_clause = '0';
$this->Application->SetVar('adv_search_error', 1);
}
}
$where_clause .= ' AND '.$items_table.'.Status = 1';
// building final search query
$search_table = TABLE_PREFIX.'ses_'.$this->Application->GetSID().'_'.TABLE_PREFIX.'Search';
$this->Conn->Query('DROP TABLE IF EXISTS '.$search_table);
$id_field = $this->Application->getUnitOption($event->Prefix, 'IDField');
$fields = $this->Application->getUnitOption($event->Prefix, 'Fields');
$pick_field = isset($fields['EditorsPick']) ? $items_table.'.EditorsPick' : '0';
$sql = ' CREATE TABLE '.$search_table.'
SELECT '.$relevance_clause.' AS Relevance,
'.$items_table.'.'.$id_field.' AS ItemId,
'.$items_table.'.ResourceId AS ResourceId,
11 AS ItemType,
'.$pick_field.' AS EdPick
FROM '.$items_table.'
'.implode(' ', $join_clauses).'
WHERE '.$where_clause.'
GROUP BY '.$items_table.'.'.$id_field.
$having_clause;
$res = $this->Conn->Query($sql);
}
function getAdvancedSearchCondition($field_name, $record, $keywords, $verbs, &$highlight_keywords)
{
$field = $record['FieldName'];
$condition_patterns = Array (
'any' => '%s LIKE %s',
'contains' => '%s LIKE %s',
'notcontains' => '(NOT (%1$s LIKE %2$s) OR %1$s IS NULL)',
'is' => '%s = %s',
'isnot' => '(%1$s != %2$s OR %1$s IS NULL)'
);
$condition = '';
switch ($record['FieldType']) {
case 'select':
$keywords[$field] = kUtil::unhtmlentities( $keywords[$field] );
if ($keywords[$field]) {
$condition = sprintf($condition_patterns['is'], $field_name, $this->Conn->qstr( $keywords[$field] ));
}
break;
case 'multiselect':
$keywords[$field] = kUtil::unhtmlentities( $keywords[$field] );
if ($keywords[$field]) {
$condition = Array ();
$values = explode('|', substr($keywords[$field], 1, -1));
foreach ($values as $selected_value) {
$condition[] = sprintf($condition_patterns['contains'], $field_name, $this->Conn->qstr('%|'.$selected_value.'|%'));
}
$condition = '('.implode(' OR ', $condition).')';
}
break;
case 'text':
$keywords[$field] = kUtil::unhtmlentities( $keywords[$field] );
if (mb_strlen($keywords[$field]) >= $this->Application->ConfigValue('Search_MinKeyword_Length')) {
$highlight_keywords[] = $keywords[$field];
if (in_array($verbs[$field], Array('any', 'contains', 'notcontains'))) {
$keywords[$field] = '%'.strtr($keywords[$field], Array('%' => '\\%', '_' => '\\_')).'%';
}
$condition = sprintf($condition_patterns[$verbs[$field]], $field_name, $this->Conn->qstr( $keywords[$field] ));
}
break;
case 'boolean':
if ($keywords[$field] != -1) {
$property_mappings = $this->Application->getUnitOption($this->Prefix, 'ItemPropertyMappings');
$items_table = $this->Application->getUnitOption($this->Prefix, 'TableName');
switch ($field) {
case 'HotItem':
$hot_limit_var = getArrayValue($property_mappings, 'HotLimit');
if ($hot_limit_var) {
$hot_limit = (int)$this->Application->getDBCache($hot_limit_var);
$condition = 'IF('.$items_table.'.HotItem = 2,
IF('.$items_table.'.Hits >= '.
$hot_limit.
', 1, 0), '.$items_table.'.HotItem) = '.$keywords[$field];
}
break;
case 'PopItem':
$votes2pop_var = getArrayValue($property_mappings, 'VotesToPop');
$rating2pop_var = getArrayValue($property_mappings, 'RatingToPop');
if ($votes2pop_var && $rating2pop_var) {
$condition = 'IF('.$items_table.'.PopItem = 2, IF('.$items_table.'.CachedVotesQty >= '.
$this->Application->ConfigValue($votes2pop_var).
' AND '.$items_table.'.CachedRating >= '.
$this->Application->ConfigValue($rating2pop_var).
', 1, 0), '.$items_table.'.PopItem) = '.$keywords[$field];
}
break;
case 'NewItem':
$new_days_var = getArrayValue($property_mappings, 'NewDays');
if ($new_days_var) {
$condition = 'IF('.$items_table.'.NewItem = 2,
IF('.$items_table.'.CreatedOn >= (UNIX_TIMESTAMP() - '.
$this->Application->ConfigValue($new_days_var).
'*3600*24), 1, 0), '.$items_table.'.NewItem) = '.$keywords[$field];
}
break;
case 'EditorsPick':
$condition = $items_table.'.EditorsPick = '.$keywords[$field];
break;
}
}
break;
case 'range':
$range_conditions = Array();
if ($keywords[$field.'_from'] && !preg_match("/[^0-9]/i", $keywords[$field.'_from'])) {
$range_conditions[] = $field_name.' >= '.$keywords[$field.'_from'];
}
if ($keywords[$field.'_to'] && !preg_match("/[^0-9]/i", $keywords[$field.'_to'])) {
$range_conditions[] = $field_name.' <= '.$keywords[$field.'_to'];
}
if ($range_conditions) {
$condition = implode(' AND ', $range_conditions);
}
break;
case 'date':
if ($keywords[$field]) {
if (in_array($keywords[$field], Array('today', 'yesterday'))) {
$current_time = getdate();
$day_begin = adodb_mktime(0, 0, 0, $current_time['mon'], $current_time['mday'], $current_time['year']);
$time_mapping = Array('today' => $day_begin, 'yesterday' => ($day_begin - 86400));
$min_time = $time_mapping[$keywords[$field]];
}
else {
$time_mapping = Array (
'last_week' => 604800, 'last_month' => 2628000, 'last_3_months' => 7884000,
'last_6_months' => 15768000, 'last_year' => 31536000,
);
$min_time = adodb_mktime() - $time_mapping[$keywords[$field]];
}
$condition = $field_name.' > '.$min_time;
}
break;
}
return $condition;
}
/**
* Returns human readable representation of searched data to be placed in search log
* @param string $type
* @param Array $search_data
* @return string
* @access protected
*/
protected function getHuman($type, $search_data)
{
// all 3 variables are retrieved from $search_data array
/* @var $search_config Array */
/* @var $verb string */
/* @var $value string */
$type = ucfirst(strtolower($type));
extract($search_data);
switch ($type) {
case 'Field':
return $this->Application->Phrase($search_config['DisplayName']);
break;
case 'Verb':
return $verb ? $this->Application->Phrase('lu_advsearch_'.$verb) : '';
break;
case 'Value':
switch ($search_config['FieldType']) {
case 'date':
$values = Array(0 => 'lu_comm_Any', 'today' => 'lu_comm_Today',
'yesterday' => 'lu_comm_Yesterday', 'last_week' => 'lu_comm_LastWeek',
'last_month' => 'lu_comm_LastMonth', 'last_3_months' => 'lu_comm_Last3Months',
'last_6_months' => 'lu_comm_Last6Months', 'last_year' => 'lu_comm_LastYear');
$ret = $this->Application->Phrase($values[$value]);
break;
case 'range':
$value = explode('|', $value);
return $this->Application->Phrase('lu_comm_From').' "'.$value[0].'" '.$this->Application->Phrase('lu_comm_To').' "'.$value[1].'"';
break;
case 'boolean':
$values = Array(1 => 'lu_comm_Yes', 0 => 'lu_comm_No', -1 => 'lu_comm_Both');
$ret = $this->Application->Phrase($values[$value]);
break;
default:
$ret = $value;
break;
}
return '"'.$ret.'"';
break;
}
return '';
}
/**
* Set's correct page for list based on data provided with event
*
* @param kEvent $event
* @return void
* @access protected
* @see kDBEventHandler::OnListBuild()
*/
- protected function SetPagination(kEvent &$event)
+ protected function SetPagination(kEvent $event)
{
$object =& $event->getObject();
/* @var $object kDBList */
// get PerPage (forced -> session -> config -> 10)
$object->SetPerPage($this->getPerPage($event));
// main lists on Front-End have special get parameter for page
$page = $object->isMainList() ? $this->Application->GetVar('page') : false;
if ( !$page ) {
// page is given in "env" variable for given prefix
$page = $this->Application->GetVar($event->getPrefixSpecial() . '_Page');
}
if ( !$page && $event->Special ) {
// when not part of env, then variables like "prefix.special_Page" are
// replaced (by PHP) with "prefix_special_Page", so check for that too
$page = $this->Application->GetVar($event->getPrefixSpecial(true) . '_Page');
}
if ( !$object->isMainList() ) {
// main lists doesn't use session for page storing
$this->Application->StoreVarDefault($event->getPrefixSpecial() . '_Page', 1, true); // true for optional
if ( !$page ) {
if ( $this->Application->RewriteURLs() ) {
// when page not found by prefix+special, then try to search it without special at all
$page = $this->Application->GetVar($event->Prefix . '_Page');
if ( !$page ) {
// page not found in request -> get from session
$page = $this->Application->RecallVar($event->Prefix . '_Page');
}
if ( $page ) {
// page found in request -> store in session
$this->Application->StoreVar($event->getPrefixSpecial() . '_Page', $page, true); //true for optional
}
}
else {
// page not found in request -> get from session
$page = $this->Application->RecallVar($event->getPrefixSpecial() . '_Page');
}
}
else {
// page found in request -> store in session
$this->Application->StoreVar($event->getPrefixSpecial() . '_Page', $page, true); //true for optional
}
if ( !$event->getEventParam('skip_counting') ) {
// when stored page is larger, then maximal list page number
// (such case is also processed in kDBList::Query method)
$pages = $object->GetTotalPages();
if ( $page > $pages ) {
$page = 1;
$this->Application->StoreVar($event->getPrefixSpecial() . '_Page', 1, true);
}
}
}
$object->SetPage($page);
}
/* === RELATED TO IMPORT/EXPORT: BEGIN === */
/**
* Shows export dialog
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnExport(kEvent &$event)
+ protected function OnExport(kEvent $event)
{
$selected_ids = $this->StoreSelectedIDs($event);
if ( implode(',', $selected_ids) == '' ) {
// K4 fix when no ids found bad selected ids array is formed
$selected_ids = false;
}
$selected_cats_ids = $this->Application->GetVar('export_categories');
$this->Application->StoreVar($event->Prefix . '_export_ids', $selected_ids ? implode(',', $selected_ids) : '');
$this->Application->StoreVar($event->Prefix . '_export_cats_ids', $selected_cats_ids);
$export_helper =& $this->Application->recallObject('CatItemExportHelper');
/* @var $export_helper kCatDBItemExportHelper */
$redirect_params = Array (
$this->Prefix . '.export_event' => 'OnNew',
'pass' => 'all,' . $this->Prefix . '.export'
);
$event->setRedirectParams($redirect_params);
}
/**
* Performs each export step & displays progress percent
*
* @param kEvent $event
*/
- function OnExportProgress(&$event)
+ function OnExportProgress($event)
{
$export_object =& $this->Application->recallObject('CatItemExportHelper');
/* @var $export_object kCatDBItemExportHelper */
$event = new kEvent($event->getPrefixSpecial().':OnDummy');
$action_method = 'perform'.ucfirst($event->Special);
$field_values = $export_object->$action_method($event);
// finish code is done from JS now
if ($field_values['start_from'] == $field_values['total_records']) {
if ($event->Special == 'import') {
$this->Application->StoreVar('PermCache_UpdateRequired', 1);
$event->SetRedirectParam('m_cat_id', $this->Application->RecallVar('ImportCategory'));
$event->SetRedirectParam('anchor', 'tab-' . $event->Prefix);
$event->redirect = 'catalog/catalog';
}
elseif ($event->Special == 'export') {
$event->redirect = $export_object->getModuleName($event) . '/' . $event->Special . '_finish';
$event->SetRedirectParam('pass', 'all');
}
return ;
}
$export_options = $export_object->loadOptions($event);
echo $export_options['start_from'] * 100 / $export_options['total_records'];
$event->status = kEvent::erSTOP;
}
/**
* Returns specific to each item type columns only
*
* @param kEvent $event
* @return Array
* @access protected
*/
- public function getCustomExportColumns(kEvent &$event)
+ public function getCustomExportColumns(kEvent $event)
{
return Array (
'__VIRTUAL__ThumbnailImage' => 'ThumbnailImage',
'__VIRTUAL__FullImage' => 'FullImage',
'__VIRTUAL__ImageAlt' => 'ImageAlt'
);
}
/**
* Sets non standart virtual fields (e.g. to other tables)
*
* @param kEvent $event
*/
- function setCustomExportColumns(&$event)
+ function setCustomExportColumns($event)
{
$this->restorePrimaryImage($event);
}
/**
* Create/Update primary image record in info found in imported data
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function restorePrimaryImage(&$event)
+ protected function restorePrimaryImage($event)
{
$object =& $event->getObject();
/* @var $object kCatDBItem */
$has_image_info = $object->GetDBField('ImageAlt') && ($object->GetDBField('ThumbnailImage') || $object->GetDBField('FullImage'));
if ( !$has_image_info ) {
return ;
}
$image_data = $object->getPrimaryImageData();
$image =& $this->Application->recallObject('img', null, Array ('skip_autoload' => true));
/* @var $image kDBItem */
if ( $image_data ) {
$image->Load($image_data['ImageId']);
}
else {
$image->Clear();
$image->SetDBField('Name', 'main');
$image->SetDBField('DefaultImg', 1);
$image->SetDBField('ResourceId', $object->GetDBField('ResourceId'));
}
$image->SetDBField('AltName', $object->GetDBField('ImageAlt'));
if ( $object->GetDBField('ThumbnailImage') ) {
$thumbnail_field = $this->isURL($object->GetDBField('ThumbnailImage')) ? 'ThumbUrl' : 'ThumbPath';
$image->SetDBField($thumbnail_field, $object->GetDBField('ThumbnailImage'));
$image->SetDBField('LocalThumb', $thumbnail_field == 'ThumbPath' ? 1 : 0);
}
if ( !$object->GetDBField('FullImage') ) {
$image->SetDBField('SameImages', 1);
}
else {
$image->SetDBField('SameImages', 0);
$full_field = $this->isURL($object->GetDBField('FullImage')) ? 'Url' : 'LocalPath';
$image->SetDBField($full_field, $object->GetDBField('FullImage'));
$image->SetDBField('LocalImage', $full_field == 'LocalPath' ? 1 : 0);
}
if ( $image->isLoaded() ) {
$image->Update();
}
else {
$image->Create();
}
}
/**
* Detects if image url is specified in a given path (instead of path on disk)
*
* @param string $path
* @return bool
* @access protected
*/
protected function isURL($path)
{
return preg_match('#(http|https)://(.*)#', $path);
}
/**
* Prepares item for import/export operations
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnNew(kEvent &$event)
+ protected function OnNew(kEvent $event)
{
parent::OnNew($event);
if ( $event->Special == 'import' || $event->Special == 'export' ) {
$export_helper =& $this->Application->recallObject('CatItemExportHelper');
/* @var $export_helper kCatDBItemExportHelper */
$export_helper->setRequiredFields($event);
}
}
/**
* Process items selected in item_selector
*
* @param kEvent $event
*/
- function OnProcessSelected(&$event)
+ function OnProcessSelected($event)
{
$dst_field = $this->Application->RecallVar('dst_field');
$selected_ids = $this->Application->GetVar('selected_ids');
if ( $dst_field == 'ItemCategory' ) {
// Item Edit -> Categories Tab -> New Categories
$object =& $event->getObject();
/* @var $object kCatDBItem */
$category_ids = explode(',', $selected_ids['c']);
foreach ($category_ids as $category_id) {
$object->assignToCategory($category_id);
}
}
if ($dst_field == 'ImportCategory') {
// Tools -> Import -> Item Import -> Select Import Category
$this->Application->StoreVar('ImportCategory', $selected_ids['c']);
$event->SetRedirectParam($event->getPrefixSpecial() . '_id', 0);
$event->SetRedirectParam($event->getPrefixSpecial() . '_event', 'OnExportBegin');
}
$event->SetRedirectParam('opener', 'u');
}
/**
* Saves Import/Export settings to session
*
* @param kEvent $event
*/
- function OnSaveSettings(&$event)
+ function OnSaveSettings($event)
{
$event->redirect = false;
$items_info = $this->Application->GetVar($event->getPrefixSpecial(true));
if ( $items_info ) {
list($id, $field_values) = each($items_info);
$object =& $event->getObject(Array ('skip_autoload' => true));
/* @var $object kDBItem */
$object->SetFieldsFromHash($field_values, $this->getRequestProtectedFields($field_values));
$field_values['ImportFilename'] = $object->GetDBField('ImportFilename'); //if upload formatter has renamed the file during moving !!!
$field_values['ImportSource'] = 2;
$field_values['ImportLocalFilename'] = $object->GetDBField('ImportFilename');
$items_info[$id] = $field_values;
$this->Application->StoreVar($event->getPrefixSpecial() . '_ItemsInfo', serialize($items_info));
}
}
/**
* Saves Import/Export settings to session
*
* @param kEvent $event
*/
- function OnResetSettings(&$event)
+ function OnResetSettings($event)
{
$this->Application->StoreVar('ImportCategory', $this->Application->getBaseCategory());
}
/**
* Cancels item editing
* @param kEvent $event
* @return void
* @todo Used?
*/
- function OnCancelAction(&$event)
+ function OnCancelAction($event)
{
$event->redirect = $this->Application->GetVar('cancel_template');
$event->SetRedirectParam('pass', 'all,' . $event->getPrefixSpecial());
}
/* === RELATED TO IMPORT/EXPORT: END === */
/**
* Stores item's owner login into separate field together with id
*
* @param kEvent $event
* @param string $id_field
* @param string $cached_field
*/
- function cacheItemOwner(&$event, $id_field, $cached_field)
+ function cacheItemOwner($event, $id_field, $cached_field)
{
$object =& $event->getObject();
/* @var $object kDBItem */
$user_id = $object->GetDBField($id_field);
$options = $object->GetFieldOptions($id_field);
if ( isset($options['options'][$user_id]) ) {
$object->SetDBField($cached_field, $options['options'][$user_id]);
}
else {
$id_field = $this->Application->getUnitOption('u', 'IDField');
$table_name = $this->Application->getUnitOption('u', 'TableName');
$sql = 'SELECT Username
FROM ' . $table_name . '
WHERE ' . $id_field . ' = ' . $user_id;
$object->SetDBField($cached_field, $this->Conn->GetOne($sql));
}
}
/**
* 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(kEvent &$event)
+ protected function OnPreSave(kEvent $event)
{
parent::OnPreSave($event);
$use_pending_editing = $this->Application->getUnitOption($event->Prefix, 'UsePendingEditing');
if ( $event->status == kEvent::erSUCCESS && $use_pending_editing ) {
// decision: clone or not clone
$object =& $event->getObject();
/* @var $object kCatDBItem */
if ( $object->GetID() == 0 || $object->GetDBField('OrgId') > 0 ) {
// new items or cloned items shouldn't be cloned again
return ;
}
$perm_helper =& $this->Application->recallObject('PermissionsHelper');
/* @var $perm_helper kPermissionsHelper */
$owner_field = $this->getOwnerField($event->Prefix);
if ( $perm_helper->ModifyCheckPermission($object->GetDBField($owner_field), $object->GetDBField('CategoryId'), $event->Prefix) == 2 ) {
// 1. clone original item
$temp_handler =& $this->Application->recallObject($event->getPrefixSpecial() . '_TempHandler', 'kTempTablesHandler');
/* @var $temp_handler kTempTablesHandler */
$cloned_ids = $temp_handler->CloneItems($event->Prefix, $event->Special, Array ($object->GetID()), null, null, null, true);
$ci_table = $this->Application->GetTempName(TABLE_PREFIX . 'CategoryItems');
// 2. delete record from CategoryItems (about cloned item) that was automatically created during call of Create method of kCatDBItem
$sql = 'SELECT ResourceId
FROM ' . $object->TableName . '
WHERE ' . $object->IDField . ' = ' . $cloned_ids[0];
$clone_resource_id = $this->Conn->GetOne($sql);
$sql = 'DELETE FROM ' . $ci_table . '
WHERE ItemResourceId = ' . $clone_resource_id . ' AND PrimaryCat = 1';
$this->Conn->Query($sql);
// 3. copy main item categoryitems to cloned item
$sql = ' INSERT INTO ' . $ci_table . ' (CategoryId, ItemResourceId, PrimaryCat, ItemPrefix, Filename)
SELECT CategoryId, ' . $clone_resource_id . ' AS ItemResourceId, PrimaryCat, ItemPrefix, Filename
FROM ' . $ci_table . '
WHERE ItemResourceId = ' . $object->GetDBField('ResourceId');
$this->Conn->Query($sql);
// 4. put cloned id to OrgId field of item being cloned
$sql = 'UPDATE ' . $object->TableName . '
SET OrgId = ' . $object->GetID() . '
WHERE ' . $object->IDField . ' = ' . $cloned_ids[0];
$this->Conn->Query($sql);
// 5. substitute id of item being cloned with clone id
$this->Application->SetVar($event->getPrefixSpecial() . '_id', $cloned_ids[0]);
$selected_ids = $this->getSelectedIDs($event, true);
$selected_ids[ array_search($object->GetID(), $selected_ids) ] = $cloned_ids[0];
$this->StoreSelectedIDs($event, $selected_ids);
// 6. delete original item from temp table
$temp_handler->DeleteItems($event->Prefix, $event->Special, Array ($object->GetID()));
}
}
}
/**
* Sets item's owner field
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnPreCreate(kEvent &$event)
+ protected function OnPreCreate(kEvent $event)
{
parent::OnPreCreate($event);
if ( $event->status != kEvent::erSUCCESS ) {
return ;
}
$object =& $event->getObject();
/* @var $object kDBItem */
$owner_field = $this->getOwnerField($event->Prefix);
$object->SetDBField($owner_field, $this->Application->RecallVar('user_id'));
}
/**
* Occurs before original item of item in pending editing got deleted (for hooking only)
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnBeforeDeleteOriginal(kEvent &$event)
+ protected function OnBeforeDeleteOriginal(kEvent $event)
{
}
/**
* Occurs after original item of item in pending editing got deleted (for hooking only)
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnAfterDeleteOriginal(kEvent &$event)
+ protected function OnAfterDeleteOriginal(kEvent $event)
{
}
/**
* 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(kEvent &$event)
+ protected function OnBeforeClone(kEvent $event)
{
parent::OnBeforeClone($event);
$object =& $event->getObject();
/* @var $object kDBItem */
$object->SetDBField('ResourceId', 0); // this will reset it
if ( $this->Application->GetVar('ResetCatBeforeClone') ) {
$object->SetDBField('CategoryId', null);
}
}
/**
* Set status for new category item based on user permission in category
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnBeforeItemCreate(kEvent &$event)
+ protected function OnBeforeItemCreate(kEvent $event)
{
parent::OnBeforeItemCreate($event);
$object =& $event->getObject();
/* @var $object kCatDBItem */
$is_admin = $this->Application->isAdminUser;
$owner_field = $this->getOwnerField($event->Prefix);
if ( (!$object->IsTempTable() && !$is_admin) || ($is_admin && !$object->GetDBField($owner_field)) ) {
// Front-end OR owner not specified -> set to currently logged-in user
$object->SetDBField($owner_field, $this->Application->RecallVar('user_id'));
}
if ( !$this->Application->isAdmin ) {
$this->setItemStatusByPermission($event);
}
}
/**
* Sets category item status based on user permissions (only on Front-end)
*
* @param kEvent $event
*/
- function setItemStatusByPermission(&$event)
+ function setItemStatusByPermission($event)
{
$use_pending_editing = $this->Application->getUnitOption($event->Prefix, 'UsePendingEditing');
if (!$use_pending_editing) {
return ;
}
$object =& $event->getObject();
/* @var $object kCatDBItem */
$perm_helper =& $this->Application->recallObject('PermissionsHelper');
/* @var $perm_helper kPermissionsHelper */
$primary_category = $object->GetDBField('CategoryId') > 0 ? $object->GetDBField('CategoryId') : $this->Application->GetVar('m_cat_id');
$item_status = $perm_helper->AddCheckPermission($primary_category, $event->Prefix);
if ($item_status == STATUS_DISABLED) {
$event->status = kEvent::erFAIL;
}
else {
$object->SetDBField('Status', $item_status);
}
}
/**
* Creates category item & redirects to confirmation template (front-end only)
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnCreate(kEvent &$event)
+ protected function OnCreate(kEvent $event)
{
parent::OnCreate($event);
$this->SetFrontRedirectTemplate($event, 'suggest');
}
/**
* Returns item's categories (allows to exclude primary category)
*
* @param int $resource_id
* @param bool $with_primary
* @return Array
*/
function getItemCategories($resource_id, $with_primary = false)
{
$sql = 'SELECT CategoryId
FROM '.TABLE_PREFIX.'CategoryItems
WHERE (ItemResourceId = '.$resource_id.')';
if (!$with_primary) {
$sql .= ' AND (PrimaryCat = 0)';
}
return $this->Conn->GetCol($sql);
}
/**
* Adds new and removes old additional categories from category item
*
* @param kCatDBItem $object
* @param int $mode
*/
function processAdditionalCategories(&$object, $mode)
{
if ( !$object->isVirtualField('MoreCategories') ) {
// given category item doesn't require such type of processing
return ;
}
$process_categories = $object->GetDBField('MoreCategories');
if ($process_categories === '') {
// field was not in submit & have default value (when no categories submitted, then value is null)
return ;
}
if ($mode == 'create') {
// prevents first additional category to become primary
$object->assignPrimaryCategory();
}
$process_categories = $process_categories ? explode('|', substr($process_categories, 1, -1)) : Array ();
$existing_categories = $this->getItemCategories($object->GetDBField('ResourceId'));
$add_categories = array_diff($process_categories, $existing_categories);
foreach ($add_categories as $category_id) {
$object->assignToCategory($category_id);
}
$remove_categories = array_diff($existing_categories, $process_categories);
foreach ($remove_categories as $category_id) {
$object->removeFromCategory($category_id);
}
}
/**
* Creates category item & redirects to confirmation template (front-end only)
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnUpdate(kEvent &$event)
+ protected function OnUpdate(kEvent $event)
{
$use_pending = $this->Application->getUnitOption($event->Prefix, 'UsePendingEditing');
if ($this->Application->isAdminUser || !$use_pending) {
parent::OnUpdate($event);
$this->SetFrontRedirectTemplate($event, 'modify');
return ;
}
$object =& $event->getObject(Array('skip_autoload' => true));
/* @var $object kCatDBItem */
$items_info = $this->Application->GetVar($event->getPrefixSpecial(true));
if ($items_info) {
$perm_helper =& $this->Application->recallObject('PermissionsHelper');
/* @var $perm_helper kPermissionsHelper */
$temp_handler =& $this->Application->recallObject($event->getPrefixSpecial().'_TempHandler', 'kTempTablesHandler');
/* @var $temp_handler kTempTablesHandler */
$owner_field = $this->getOwnerField($event->Prefix);
$file_helper =& $this->Application->recallObject('FileHelper');
/* @var $file_helper FileHelper */
foreach ($items_info as $id => $field_values) {
$object->Load($id);
$edit_perm = $perm_helper->ModifyCheckPermission($object->GetDBField($owner_field), $object->GetDBField('CategoryId'), $event->Prefix);
if ($use_pending && !$object->GetDBField('OrgId') && ($edit_perm == STATUS_PENDING)) {
// pending editing enabled + not pending copy -> get/create pending copy & save changes to it
$original_id = $object->GetID();
$original_resource_id = $object->GetDBField('ResourceId');
$file_helper->PreserveItemFiles($field_values);
$object->Load($original_id, 'OrgId');
if (!$object->isLoaded()) {
// 1. user has no pending copy of live item -> clone live item
$cloned_ids = $temp_handler->CloneItems($event->Prefix, $event->Special, Array($original_id), null, null, null, true);
$object->Load($cloned_ids[0]);
$object->SetFieldsFromHash($field_values, $this->getRequestProtectedFields($field_values));
// 1a. delete record from CategoryItems (about cloned item) that was automatically created during call of Create method of kCatDBItem
$ci_table = $this->Application->getUnitOption('ci', 'TableName');
$sql = 'DELETE FROM '.$ci_table.'
WHERE ItemResourceId = '.$object->GetDBField('ResourceId').' AND PrimaryCat = 1';
$this->Conn->Query($sql);
// 1b. copy main item categoryitems to cloned item
$sql = 'INSERT INTO '.$ci_table.' (CategoryId, ItemResourceId, PrimaryCat, ItemPrefix, Filename)
SELECT CategoryId, '.$object->GetDBField('ResourceId').' AS ItemResourceId, PrimaryCat, ItemPrefix, Filename
FROM '.$ci_table.'
WHERE ItemResourceId = '.$original_resource_id;
$this->Conn->Query($sql);
// 1c. put cloned id to OrgId field of item being cloned
$object->SetDBField('Status', STATUS_PENDING_EDITING);
$object->SetDBField('OrgId', $original_id);
}
else {
// 2. user has pending copy of live item -> just update field values
$object->SetFieldsFromHash($field_values, $this->getRequestProtectedFields($field_values));
}
// update id in request (used for redirect in mod-rewrite mode)
$this->Application->SetVar($event->getPrefixSpecial().'_id', $object->GetID());
}
else {
// 3. already editing pending copy -> just update field values
$object->SetFieldsFromHash($field_values, $this->getRequestProtectedFields($field_values));
}
if ($object->Update()) {
$event->status = kEvent::erSUCCESS;
}
else {
$event->status = kEvent::erFAIL;
$event->redirect = false;
break;
}
}
}
$this->SetFrontRedirectTemplate($event, 'modify');
}
/**
* Sets next template to one required for front-end after adding/modifying item
*
* @param kEvent $event
* @param string $template_key - {suggest,modify}
*/
- function SetFrontRedirectTemplate(&$event, $template_key)
+ function SetFrontRedirectTemplate($event, $template_key)
{
if ( $this->Application->isAdmin || $event->status != kEvent::erSUCCESS ) {
return;
}
// prepare redirect template
$object =& $event->getObject();
/* @var $object kDBItem */
$is_active = ($object->GetDBField('Status') == STATUS_ACTIVE);
$next_template = $is_active ? 'confirm_template' : 'pending_confirm_template';
$event->redirect = $this->Application->GetVar($template_key . '_' . $next_template);
$event->SetRedirectParam('opener', 's');
// send email events
$perm_prefix = $this->Application->getUnitOption($event->Prefix, 'PermItemPrefix');
$owner_field = $this->getOwnerField($event->Prefix);
$owner_id = $object->GetDBField($owner_field);
switch ( $event->Name ) {
case 'OnCreate':
$event_suffix = $is_active ? 'ADD' : 'ADD.PENDING';
$this->Application->EmailEventAdmin($perm_prefix . '.' . $event_suffix); // there are no ADD.PENDING event for admin :(
$this->Application->EmailEventUser($perm_prefix . '.' . $event_suffix, $owner_id);
break;
case 'OnUpdate':
$event_suffix = $is_active ? 'MODIFY' : 'MODIFY.PENDING';
$user_id = is_numeric($object->GetDBField('ModifiedById')) ? $object->GetDBField('ModifiedById') : $owner_id;
$this->Application->EmailEventAdmin($perm_prefix . '.' . $event_suffix); // there are no ADD.PENDING event for admin :(
$this->Application->EmailEventUser($perm_prefix . '.' . $event_suffix, $user_id);
break;
}
}
/**
* Apply same processing to each item being selected in grid
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function iterateItems(kEvent &$event)
+ protected function iterateItems(kEvent $event)
{
if ( $event->Name != 'OnMassApprove' && $event->Name != 'OnMassDecline' ) {
parent::iterateItems($event);
}
if ( $this->Application->CheckPermission('SYSTEM_ACCESS.READONLY', 1) ) {
$event->status = kEvent::erFAIL;
return ;
}
$object =& $event->getObject(Array ('skip_autoload' => true));
/* @var $object kCatDBItem */
$ids = $this->StoreSelectedIDs($event);
if ( $ids ) {
foreach ($ids as $id) {
$ret = true;
$object->Load($id);
switch ( $event->Name ) {
case 'OnMassApprove':
$ret = $object->ApproveChanges();
break;
case 'OnMassDecline':
$ret = $object->DeclineChanges();
break;
}
if ( !$ret ) {
$event->status = kEvent::erFAIL;
$event->redirect = false;
break;
}
}
}
$this->clearSelectedIDs($event);
}
/**
* Deletes items & preserves clean env
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnDelete(kEvent &$event)
+ protected function OnDelete(kEvent $event)
{
parent::OnDelete($event);
if ( $event->status == kEvent::erSUCCESS && !$this->Application->isAdmin ) {
$event->SetRedirectParam('pass', 'm');
$event->SetRedirectParam('m_cat_id', 0);
}
}
/**
* Checks, that currently loaded item is allowed for viewing (non permission-based)
*
* @param kEvent $event
* @return bool
* @access protected
*/
- protected function checkItemStatus(kEvent &$event)
+ protected function checkItemStatus(kEvent $event)
{
$object =& $event->getObject();
/* @var $object kDBItem */
if ( !$object->isLoaded() ) {
if ( $event->Special != 'previous' && $event->Special != 'next' ) {
$this->_errorNotFound($event);
}
return true;
}
$status = $object->GetDBField('Status');
$user_id = $this->Application->RecallVar('user_id');
$owner_field = $this->getOwnerField($event->Prefix);
if ( ($status == STATUS_PENDING_EDITING || $status == STATUS_PENDING) && ($object->GetDBField($owner_field) == $user_id) ) {
return true;
}
return $status == STATUS_ACTIVE;
}
/**
* Set's correct sorting for list based on data provided with event
*
* @param kEvent $event
* @return void
* @access protected
* @see kDBEventHandler::OnListBuild()
*/
- protected function SetSorting(kEvent &$event)
+ protected function SetSorting(kEvent $event)
{
if ( !$this->Application->isAdmin ) {
$event->setEventParam('same_special', true);
}
parent::SetSorting($event);
}
/**
* Returns current per-page setting for list
*
* @param kEvent $event
* @return int
* @access protected
*/
- protected function getPerPage(kEvent &$event)
+ protected function getPerPage(kEvent $event)
{
if ( !$this->Application->isAdmin ) {
$event->setEventParam('same_special', true);
}
return parent::getPerPage($event);
}
/**
* Returns owner field for given prefix
*
* @param $prefix
* @return string
* @access protected
*/
protected function getOwnerField($prefix)
{
return $this->Application->getUnitOption($prefix, 'OwnerField', 'CreatedById');
}
/**
* Creates virtual image fields for item
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnAfterConfigRead(kEvent &$event)
+ protected function OnAfterConfigRead(kEvent $event)
{
parent::OnAfterConfigRead($event);
if (defined('IS_INSTALL') && IS_INSTALL) {
return ;
}
if ( !$this->Application->isAdmin ) {
$file_helper =& $this->Application->recallObject('FileHelper');
/* @var $file_helper FileHelper */
$file_helper->createItemFiles($event->Prefix, true); // create image fields
$file_helper->createItemFiles($event->Prefix, false); // create file fields
}
$this->changeSortings($event);
// add grids for advanced view (with primary category column)
$grids = $this->Application->getUnitOption($this->Prefix, 'Grids');
$process_grids = Array ('Default', 'Radio');
foreach ($process_grids as $process_grid) {
$grid_data = $grids[$process_grid];
$grid_data['Fields']['CachedNavbar'] = Array ('title' => 'la_col_Path', 'data_block' => 'grid_primary_category_td', 'filter_block' => 'grid_like_filter');
$grids[$process_grid . 'ShowAll'] = $grid_data;
}
$this->Application->setUnitOption($this->Prefix, 'Grids', $grids);
// add options for CategoryId field (quick way to select item's primary category)
$category_helper =& $this->Application->recallObject('CategoryHelper');
/* @var $category_helper CategoryHelper */
$virtual_fields = $this->Application->getUnitOption($event->Prefix, 'VirtualFields');
$virtual_fields['CategoryId']['default'] = (int)$this->Application->GetVar('m_cat_id');
$virtual_fields['CategoryId']['options'] = $category_helper->getStructureTreeAsOptions();
$this->Application->setUnitOption($event->Prefix, 'VirtualFields', $virtual_fields);
}
- function changeSortings(&$event)
+ function changeSortings($event)
{
$remove_sortings = Array ();
if ( !$this->Application->isAdmin ) {
// remove Pick sorting on Front-end, when not required
$config_mapping = $this->Application->getUnitOption($event->Prefix, 'ConfigMapping', Array ());
if ( !isset($config_mapping['ForceEditorPick']) || !$this->Application->ConfigValue($config_mapping['ForceEditorPick']) ) {
$remove_sortings[] = 'EditorsPick';
}
}
else {
// remove all forced sortings in Admin Console
$remove_sortings = array_merge($remove_sortings, Array ('Priority', 'EditorsPick'));
}
if ( !$remove_sortings ) {
return;
}
$list_sortings = $this->Application->getUnitOption($event->Prefix, 'ListSortings', Array ());
/* @var $list_sortings Array */
foreach ($list_sortings as $special => $sorting_fields) {
foreach ($remove_sortings as $sorting_field) {
unset($list_sortings[$special]['ForcedSorting'][$sorting_field]);
}
}
$this->Application->setUnitOption($event->Prefix, 'ListSortings', $list_sortings);
}
/**
* Returns file contents associated with item
*
* @param kEvent $event
*/
- function OnDownloadFile(&$event)
+ function OnDownloadFile($event)
{
$object =& $event->getObject();
/* @var $object kCatDBItem */
$event->status = kEvent::erSTOP;
$field = $this->Application->GetVar('field');
if (!preg_match('/^File([\d]+)/', $field)) {
return ;
}
$file_helper =& $this->Application->recallObject('FileHelper');
/* @var $file_helper FileHelper */
$filename = $object->GetField($field, 'full_path');
$file_helper->DownloadFile($filename);
}
/**
* Saves user's vote
*
* @param kEvent $event
*/
- function OnMakeVote(&$event)
+ function OnMakeVote($event)
{
$event->status = kEvent::erSTOP;
if ($this->Application->GetVar('ajax') != 'yes') {
// this is supposed to call from AJAX only
return ;
}
$rating_helper =& $this->Application->recallObject('RatingHelper');
/* @var $rating_helper RatingHelper */
$object =& $event->getObject( Array ('skip_autoload' => true) );
/* @var $object kCatDBItem */
$object->Load( $this->Application->GetVar('id') );
echo $rating_helper->makeVote($object);
}
/**
* Marks review as useful
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnReviewHelpful(&$event)
+ protected function OnReviewHelpful($event)
{
if ( $this->Application->GetVar('ajax') == 'yes' ) {
$event->status = kEvent::erSTOP;
}
$review_id = (int)$this->Application->GetVar('review_id');
if ( !$review_id ) {
return;
}
$spam_helper =& $this->Application->recallObject('SpamHelper');
/* @var $spam_helper SpamHelper */
$spam_helper->InitHelper($review_id, 'ReviewHelpful', strtotime('+1 month') - strtotime('now'));
$field = (int)$this->Application->GetVar('helpful') ? 'HelpfulCount' : 'NotHelpfulCount';
$sql = 'SELECT ' . $field . '
FROM ' . $this->Application->getUnitOption('rev', 'TableName') . '
WHERE ' . $this->Application->getUnitOption('rev', 'IDField') . ' = ' . $review_id;
$count = $this->Conn->GetOne($sql);
if ( $spam_helper->InSpamControl() ) {
if ( $this->Application->GetVar('ajax') == 'yes' ) {
echo $count;
}
return;
}
$sql = 'UPDATE ' . $this->Application->getUnitOption('rev', 'TableName') . '
SET ' . $field . ' = ' . $field . ' + 1
WHERE ' . $this->Application->getUnitOption('rev', 'IDField') . ' = ' . $review_id;
$this->Conn->Query($sql);
if ( $this->Conn->getAffectedRows() ) {
// db was changed -> review with such ID exists
$spam_helper->AddToSpamControl();
}
if ( $this->Application->GetVar('ajax') == 'yes' ) {
echo $count + 1;
}
}
/**
* [HOOK] Allows to add cloned subitem to given prefix
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnCloneSubItem(kEvent &$event)
+ protected function OnCloneSubItem(kEvent $event)
{
parent::OnCloneSubItem($event);
if ( $event->MasterEvent->Prefix == 'fav' ) {
$clones = $this->Application->getUnitOption($event->MasterEvent->Prefix, 'Clones');
$subitem_prefix = $event->Prefix . '-' . $event->MasterEvent->Prefix;
$clones[$subitem_prefix]['ParentTableKey'] = 'ResourceId';
$clones[$subitem_prefix]['ForeignKey'] = 'ResourceId';
$this->Application->setUnitOption($event->MasterEvent->Prefix, 'Clones', $clones);
}
}
/**
* Set's new unique resource id to user
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnAfterItemValidate(kEvent &$event)
+ protected function OnAfterItemValidate(kEvent $event)
{
$object =& $event->getObject();
/* @var $object kDBItem */
$resource_id = $object->GetDBField('ResourceId');
if ( !$resource_id ) {
$object->SetDBField('ResourceId', $this->Application->NextResourceId());
}
}
}
\ No newline at end of file
Index: branches/5.2.x/core/kernel/application.php
===================================================================
--- branches/5.2.x/core/kernel/application.php (revision 15129)
+++ branches/5.2.x/core/kernel/application.php (revision 15130)
@@ -1,3149 +1,3137 @@
<?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!');
/**
* Basic class for Kernel4-based Application
*
* This class is a Facade for any other class which needs to deal with Kernel4 framework.<br>
* The class encapsulates the main run-cycle of the script, provide access to all other objects in the framework.<br>
* <br>
* The class is a singleton, which means that there could be only one instance of kApplication in the script.<br>
* This could be guaranteed by NOT calling the class constructor directly, but rather calling kApplication::Instance() method,
* which returns an instance of the application. The method guarantees that it will return exactly the same instance for any call.<br>
* See singleton pattern by GOF.
*/
class kApplication implements kiCacheable {
/**
* Location of module helper class (used in installator too)
*/
const MODULE_HELPER_PATH = '/../units/helpers/modules_helper.php';
/**
* Is true, when Init method was called already, prevents double initialization
*
* @var bool
*/
public $InitDone = false;
/**
* Holds internal NParser object
*
* @var NParser
* @access public
*/
public $Parser;
/**
* Holds parser output buffer
*
* @var string
* @access protected
*/
protected $HTML = '';
/**
* The main Factory used to create
* almost any class of kernel and
* modules
*
* @var kFactory
* @access protected
*/
protected $Factory;
/**
* Template names, that will be used instead of regular templates
*
* @var Array
* @access public
*/
public $ReplacementTemplates = Array ();
/**
* Mod-Rewrite listeners used during url building and parsing
*
* @var Array
* @access public
*/
public $RewriteListeners = Array ();
/**
* Reference to debugger
*
* @var Debugger
* @access public
*/
public $Debugger = null;
/**
* Holds all phrases used
* in code and template
*
* @var PhrasesCache
* @access public
*/
public $Phrases;
/**
* Modules table content, key - module name
*
* @var Array
* @access public
*/
public $ModuleInfo = Array ();
/**
* Holds DBConnection
*
* @var kDBConnection
* @access public
*/
public $Conn = null;
/**
* Maintains list of user-defined error handlers
*
* @var Array
* @access public
*/
public $errorHandlers = Array ();
/**
* Maintains list of user-defined exception handlers
*
* @var Array
* @access public
*/
public $exceptionHandlers = Array ();
// performance needs:
/**
* Holds a reference to httpquery
*
* @var kHttpQuery
* @access public
*/
public $HttpQuery = null;
/**
* Holds a reference to UnitConfigReader
*
* @var kUnitConfigReader
* @access public
*/
public $UnitConfigReader = null;
/**
* Holds a reference to Session
*
* @var Session
* @access public
*/
public $Session = null;
/**
* Holds a ref to kEventManager
*
* @var kEventManager
* @access public
*/
public $EventManager = null;
/**
* Holds a ref to kUrlManager
*
* @var kUrlManager
* @access public
*/
public $UrlManager = null;
/**
* Ref for TemplatesCache
*
* @var TemplatesCache
* @access public
*/
public $TemplatesCache = null;
/**
* Holds current NParser tag while parsing, can be used in error messages to display template file and line
*
* @var _BlockTag
* @access public
*/
public $CurrentNTag = null;
/**
* Object of unit caching class
*
* @var kCacheManager
* @access public
*/
public $cacheManager = null;
/**
* Tells, that administrator has authenticated in administrative console
* Should be used to manipulate data change OR data restrictions!
*
* @var bool
* @access public
*/
public $isAdminUser = false;
/**
* Tells, that admin version of "index.php" was used, nothing more!
* Should be used to manipulate data display!
*
* @var bool
* @access public
*/
public $isAdmin = false;
/**
* Instance of site domain object
*
* @var kDBItem
* @access public
* @todo move away into separate module
*/
public $siteDomain = null;
/**
* Prevent kApplication class to be created directly, only via Instance method
*
- * @access protected
+ * @access private
*/
- protected function __construct()
+ private function __construct()
{
}
+ final private function __clone() {}
+
/**
* Returns kApplication instance anywhere in the script.
*
* This method should be used to get single kApplication object instance anywhere in the
* Kernel-based application. The method is guaranteed to return the SAME instance of kApplication.
* Anywhere in the script you could write:
* <code>
* $application =& kApplication::Instance();
* </code>
* or in an object:
* <code>
* $this->Application =& kApplication::Instance();
* </code>
* to get the instance of kApplication. Note that we call the Instance method as STATIC - directly from the class.
* To use descendant of standard kApplication class in your project you would need to define APPLICATION_CLASS constant
* BEFORE calling kApplication::Instance() for the first time. If APPLICATION_CLASS is not defined the method would
* create and return default KernelApplication instance.
*
* Pattern: Singleton
*
* @static
* @return kApplication
* @access public
*/
public static function &Instance()
{
static $instance = false;
if ( !$instance ) {
$class = defined('APPLICATION_CLASS') ? APPLICATION_CLASS : 'kApplication';
$instance = new $class();
- $instance->Application =& $instance;
}
return $instance;
}
/**
* Initializes the Application
*
+ * @param string $factory_class
* @return bool Was Init actually made now or before
* @access public
* @see kHTTPQuery
* @see Session
* @see TemplatesCache
*/
- public function Init()
+ public function Init($factory_class = 'kFactory')
{
if ( $this->InitDone ) {
return false;
}
$this->isAdmin = kUtil::constOn('ADMIN');
if ( !kUtil::constOn('SKIP_OUT_COMPRESSION') ) {
ob_start(); // collect any output from method (other then tags) into buffer
}
if ( defined('DEBUG_MODE') && $this->isDebugMode() && kUtil::constOn('DBG_PROFILE_MEMORY') ) {
$this->Debugger->appendMemoryUsage('Application before Init:');
}
if ( !$this->isDebugMode() && !kUtil::constOn('DBG_ZEND_PRESENT') ) {
error_reporting(0);
ini_set('display_errors', 0);
}
if ( !kUtil::constOn('DBG_ZEND_PRESENT') ) {
$error_handler = set_error_handler(Array (&$this, 'handleError'));
if ( $error_handler ) {
// wrap around previous error handler, if any was set
$this->errorHandlers[] = $error_handler;
}
$exception_handler = set_exception_handler(Array (&$this, 'handleException'));
if ( $exception_handler ) {
// wrap around previous exception handler, if any was set
$this->exceptionHandlers[] = $exception_handler;
}
}
- $this->Factory = new kFactory();
+ $this->Factory = new $factory_class();
$this->registerDefaultClasses();
$vars = kUtil::parseConfig(true);
$db_class = isset($vars['Databases']) ? 'kDBLoadBalancer' : 'kDBConnection';
$this->Conn =& $this->Factory->makeClass($db_class, Array (SQL_TYPE, Array (&$this, 'handleSQLError')));
$this->Conn->setup($vars);
$this->cacheManager =& $this->makeClass('kCacheManager');
$this->cacheManager->InitCache();
if ( defined('DEBUG_MODE') && $this->isDebugMode() ) {
$this->Debugger->appendTimestamp('Before UnitConfigReader');
}
// init config reader and all managers
$this->UnitConfigReader =& $this->makeClass('kUnitConfigReader');
$this->UnitConfigReader->scanModules(MODULES_PATH); // will also set RewriteListeners when existing cache is read
$this->registerModuleConstants();
if ( defined('DEBUG_MODE') && $this->isDebugMode() ) {
$this->Debugger->appendTimestamp('After UnitConfigReader');
}
define('MOD_REWRITE', $this->ConfigValue('UseModRewrite') && !$this->isAdmin ? 1 : 0);
// start processing request
$this->HttpQuery =& $this->recallObject('HTTPQuery');
$this->HttpQuery->process();
if ( defined('DEBUG_MODE') && $this->isDebugMode() ) {
$this->Debugger->appendTimestamp('Processed HTTPQuery initial');
}
$this->Session =& $this->recallObject('Session');
if ( defined('DEBUG_MODE') && $this->isDebugMode() ) {
$this->Debugger->appendTimestamp('Processed Session');
}
$this->UrlManager->LoadStructureTemplateMapping();
$this->Session->ValidateExpired(); // needs mod_rewrite url already parsed to keep user at proper template after session expiration
if ( defined('DEBUG_MODE') && $this->isDebugMode() ) {
$this->Debugger->appendTimestamp('Processed HTTPQuery AfterInit');
}
$this->cacheManager->LoadApplicationCache();
$site_timezone = $this->ConfigValue('Config_Site_Time');
if ( $site_timezone ) {
putenv('TZ=' . $site_timezone);
}
if ( defined('DEBUG_MODE') && $this->isDebugMode() ) {
$this->Debugger->appendTimestamp('Loaded cache and phrases');
}
$this->ValidateLogin(); // must be called before AfterConfigRead, because current user should be available there
$this->UnitConfigReader->AfterConfigRead(); // will set RewriteListeners when missing cache is built first time
if ( defined('DEBUG_MODE') && $this->isDebugMode() ) {
$this->Debugger->appendTimestamp('Processed AfterConfigRead');
}
if ( $this->GetVar('m_cat_id') === false ) {
$this->SetVar('m_cat_id', 0);
}
if ( !$this->RecallVar('curr_iso') ) {
$this->StoreVar('curr_iso', $this->GetPrimaryCurrency(), true); // true for optional
}
$visit_id = $this->RecallVar('visit_id');
if ( $visit_id !== false ) {
$this->SetVar('visits_id', $visit_id);
}
$language =& $this->recallObject('lang.current', null, Array ('live_table' => true));
/* @var $language LanguagesItem */
if ( preg_match('/utf-8/', $language->GetDBField('Charset')) ) {
setlocale(LC_ALL, 'en_US.UTF-8');
mb_internal_encoding('UTF-8');
}
if ( defined('DEBUG_MODE') && $this->isDebugMode() ) {
$this->Debugger->profileFinish('kernel4_startup');
}
$this->InitDone = true;
$this->HandleEvent(new kEvent('adm:OnStartup'));
return true;
}
/**
* Performs initialization of manager classes, that can be overridden from unit configs
*
* @return void
* @access public
* @throws Exception
*/
public function InitManagers()
{
if ( $this->InitDone ) {
throw new Exception('Duplicate call of ' . __METHOD__, E_USER_ERROR);
return;
}
$this->UrlManager =& $this->makeClass('kUrlManager');
$this->EventManager =& $this->makeClass('EventManager');
$this->Phrases =& $this->makeClass('kPhraseCache');
$this->RegisterDefaultBuildEvents();
}
/**
* Returns module information. Searches module by requested field
*
* @param string $field
* @param mixed $value
* @param string $return_field field value to returns, if not specified, then return all fields
* @return Array
*/
public function findModule($field, $value, $return_field = null)
{
$found = $module_info = false;
foreach ($this->ModuleInfo as $module_info) {
if ( strtolower($module_info[$field]) == strtolower($value) ) {
$found = true;
break;
}
}
if ( $found ) {
return isset($return_field) ? $module_info[$return_field] : $module_info;
}
return false;
}
/**
* Refreshes information about loaded modules
*
* @return void
* @access public
*/
public function refreshModuleInfo()
{
if ( defined('IS_INSTALL') && IS_INSTALL && !$this->TableFound('Modules', true) ) {
$this->registerModuleConstants();
return;
}
// use makeClass over recallObject, since used before kApplication initialization during installation
$modules_helper =& $this->makeClass('ModulesHelper');
/* @var $modules_helper kModulesHelper */
$this->Conn->nextQueryCachable = true;
$sql = 'SELECT *
FROM ' . TABLE_PREFIX . 'Modules
WHERE ' . $modules_helper->getWhereClause() . '
ORDER BY LoadOrder';
$this->ModuleInfo = $this->Conn->Query($sql, 'Name');
$this->registerModuleConstants();
}
/**
* Checks if passed language id if valid and sets it to primary otherwise
*
* @return void
* @access public
*/
public function VerifyLanguageId()
{
$language_id = $this->GetVar('m_lang');
if ( !$language_id ) {
$language_id = 'default';
}
$this->SetVar('lang.current_id', $language_id);
$this->SetVar('m_lang', $language_id);
$lang_mode = $this->GetVar('lang_mode');
$this->SetVar('lang_mode', '');
$lang =& $this->recallObject('lang.current');
/* @var $lang kDBItem */
if ( !$lang->isLoaded() || (!$this->isAdmin && !$lang->GetDBField('Enabled')) ) {
if ( !defined('IS_INSTALL') ) {
$this->ApplicationDie('Unknown or disabled language');
}
}
$this->SetVar('lang_mode', $lang_mode);
}
/**
* Checks if passed theme id if valid and sets it to primary otherwise
*
* @return void
* @access public
*/
public function VerifyThemeId()
{
if ( $this->isAdmin ) {
kUtil::safeDefine('THEMES_PATH', '/core/admin_templates');
return;
}
$path = $this->GetFrontThemePath();
if ( $path === false ) {
$this->ApplicationDie('No Primary Theme Selected or Current Theme is Unknown or Disabled');
}
kUtil::safeDefine('THEMES_PATH', $path);
}
/**
* Returns relative path to current front-end theme
*
* @param bool $force
* @return string
* @access public
*/
public function GetFrontThemePath($force = false)
{
static $path = null;
if ( !$force && isset($path) ) {
return $path;
}
$theme_id = $this->GetVar('m_theme');
if ( !$theme_id ) {
$theme_id = 'default'; // $this->GetDefaultThemeId(1); // 1 to force front-end mode!
}
$this->SetVar('m_theme', $theme_id);
$this->SetVar('theme.current_id', $theme_id); // KOSTJA: this is to fool theme' getPassedID
$theme =& $this->recallObject('theme.current');
/* @var $theme ThemeItem */
if ( !$theme->isLoaded() || !$theme->GetDBField('Enabled') ) {
return false;
}
// assign & then return, since it's static variable
$path = '/themes/' . $theme->GetDBField('Name');
return $path;
}
/**
* Returns primary front/admin language id
*
* @param bool $init
* @return int
* @access public
*/
public function GetDefaultLanguageId($init = false)
{
$cache_key = 'primary_language_info[%LangSerial%]';
$language_info = $this->getCache($cache_key);
if ( $language_info === false ) {
// cache primary language info first
$table = $this->getUnitOption('lang', 'TableName');
$id_field = $this->getUnitOption('lang', 'IDField');
$this->Conn->nextQueryCachable = true;
$sql = 'SELECT ' . $id_field . ', IF(AdminInterfaceLang, "Admin", "Front") AS LanguageKey
FROM ' . $table . '
WHERE (AdminInterfaceLang = 1 OR PrimaryLang = 1) AND (Enabled = 1)';
$language_info = $this->Conn->GetCol($sql, 'LanguageKey');
if ( $language_info !== false ) {
$this->setCache($cache_key, $language_info);
}
}
$language_key = ($this->isAdmin && $init) || count($language_info) == 1 ? 'Admin' : 'Front';
if ( array_key_exists($language_key, $language_info) && $language_info[$language_key] > 0 ) {
// get from cache
return $language_info[$language_key];
}
$language_id = $language_info && array_key_exists($language_key, $language_info) ? $language_info[$language_key] : false;
if ( !$language_id && defined('IS_INSTALL') && IS_INSTALL ) {
$language_id = 1;
}
return $language_id;
}
/**
* Returns front-end primary theme id (even, when called from admin console)
*
* @param bool $force_front
* @return int
* @access public
*/
public function GetDefaultThemeId($force_front = false)
{
static $theme_id = 0;
if ( $theme_id > 0 ) {
return $theme_id;
}
if ( kUtil::constOn('DBG_FORCE_THEME') ) {
$theme_id = DBG_FORCE_THEME;
}
elseif ( !$force_front && $this->isAdmin ) {
$theme_id = 999;
}
else {
$cache_key = 'primary_theme[%ThemeSerial%]';
$theme_id = $this->getCache($cache_key);
if ( $theme_id === false ) {
$this->Conn->nextQueryCachable = true;
$sql = 'SELECT ' . $this->getUnitOption('theme', 'IDField') . '
FROM ' . $this->getUnitOption('theme', 'TableName') . '
WHERE (PrimaryTheme = 1) AND (Enabled = 1)';
$theme_id = $this->Conn->GetOne($sql);
if ( $theme_id !== false ) {
$this->setCache($cache_key, $theme_id);
}
}
}
return $theme_id;
}
/**
* Returns site primary currency ISO code
*
* @return string
* @access public
* @todo Move into In-Commerce
*/
public function GetPrimaryCurrency()
{
$cache_key = 'primary_currency[%CurrSerial%][%SiteDomainSerial%]:' . $this->siteDomainField('DomainId');
$currency_iso = $this->getCache($cache_key);
if ( $currency_iso === false ) {
if ( $this->isModuleEnabled('In-Commerce') ) {
$this->Conn->nextQueryCachable = true;
$currency_id = $this->siteDomainField('PrimaryCurrencyId');
$sql = 'SELECT ISO
FROM ' . $this->getUnitOption('curr', 'TableName') . '
WHERE ' . ($currency_id > 0 ? 'CurrencyId = ' . $currency_id : 'IsPrimary = 1');
$currency_iso = $this->Conn->GetOne($sql);
}
else {
$currency_iso = 'USD';
}
$this->setCache($cache_key, $currency_iso);
}
return $currency_iso;
}
/**
* Returns site domain field. When none of site domains are found false is returned.
*
* @param string $field
* @param bool $formatted
* @param string $format
* @return mixed
* @todo Move into separate module
*/
public function siteDomainField($field, $formatted = false, $format = null)
{
if ( $this->isAdmin ) {
// don't apply any filtering in administrative console
return false;
}
if ( !$this->siteDomain ) {
$this->siteDomain =& $this->recallObject('site-domain.current');
/* @var $site_domain kDBItem */
}
if ( $this->siteDomain->isLoaded() ) {
return $formatted ? $this->siteDomain->GetField($field, $format) : $this->siteDomain->GetDBField($field);
}
return false;
}
/**
* Registers default classes such as kDBEventHandler, kUrlManager
*
* Called automatically while initializing kApplication
*
* @return void
* @access public
*/
public function RegisterDefaultClasses()
{
$this->registerClass('kHelper', KERNEL_PATH . '/kbase.php');
$this->registerClass('kMultipleFilter', KERNEL_PATH . '/utility/filters.php');
$this->registerClass('kiCacheable', KERNEL_PATH . '/interfaces/cacheable.php');
- $this->registerClass('kEventManager', KERNEL_PATH . '/event_manager.php', 'EventManager', 'kiCacheable');
- $this->registerClass('kHookManager', KERNEL_PATH . '/managers/hook_manager.php', null, 'kiCacheable');
- $this->registerClass('kScheduledTaskManager', KERNEL_PATH . '/managers/scheduled_task_manager.php', null, 'kiCacheable');
+ $this->registerClass('kEventManager', KERNEL_PATH . '/event_manager.php', 'EventManager');
+ $this->registerClass('kHookManager', KERNEL_PATH . '/managers/hook_manager.php');
+ $this->registerClass('kScheduledTaskManager', KERNEL_PATH . '/managers/scheduled_task_manager.php');
$this->registerClass('kRequestManager', KERNEL_PATH . '/managers/request_manager.php');
$this->registerClass('kUrlManager', KERNEL_PATH . '/managers/url_manager.php');
$this->registerClass('kUrlProcessor', KERNEL_PATH . '/managers/url_processor.php');
- $this->registerClass('kPlainUrlProcessor', KERNEL_PATH . '/managers/plain_url_processor.php', null, 'kUrlProcessor');
- $this->registerClass('kRewriteUrlProcessor', KERNEL_PATH . '/managers/rewrite_url_processor.php', null, 'kUrlProcessor');
+ $this->registerClass('kPlainUrlProcessor', KERNEL_PATH . '/managers/plain_url_processor.php');
+ $this->registerClass('kRewriteUrlProcessor', KERNEL_PATH . '/managers/rewrite_url_processor.php');
- $this->registerClass('kCacheManager', KERNEL_PATH . '/managers/cache_manager.php', null, 'kiCacheable');
+ $this->registerClass('kCacheManager', KERNEL_PATH . '/managers/cache_manager.php');
$this->registerClass('PhrasesCache', KERNEL_PATH . '/languages/phrases_cache.php', 'kPhraseCache');
$this->registerClass('kTempTablesHandler', KERNEL_PATH . '/utility/temp_handler.php');
$this->registerClass('kValidator', KERNEL_PATH . '/utility/validator.php');
$this->registerClass('kOpenerStack', KERNEL_PATH . '/utility/opener_stack.php');
$this->registerClass('kUnitConfigReader', KERNEL_PATH . '/utility/unit_config_reader.php');
// Params class descendants
$this->registerClass('kArray', KERNEL_PATH . '/utility/params.php');
$this->registerClass('Params', KERNEL_PATH . '/utility/params.php');
$this->registerClass('Params', KERNEL_PATH . '/utility/params.php', 'kActions');
$this->registerClass('kCache', KERNEL_PATH . '/utility/cache.php', 'kCache', 'Params');
- $this->registerClass('kHTTPQuery', KERNEL_PATH . '/utility/http_query.php', 'HTTPQuery', 'Params');
+ $this->registerClass('kHTTPQuery', KERNEL_PATH . '/utility/http_query.php', 'HTTPQuery');
// session
$this->registerClass('Session', KERNEL_PATH . '/session/session.php');
$this->registerClass('SessionStorage', KERNEL_PATH . '/session/session_storage.php');
$this->registerClass('InpSession', KERNEL_PATH . '/session/inp_session.php', 'Session');
$this->registerClass('InpSessionStorage', KERNEL_PATH . '/session/inp_session_storage.php', 'SessionStorage');
// template parser
$this->registerClass('kTagProcessor', KERNEL_PATH . '/processors/tag_processor.php');
- $this->registerClass('kMainTagProcessor', KERNEL_PATH . '/processors/main_processor.php', 'm_TagProcessor', 'kTagProcessor');
- $this->registerClass('kDBTagProcessor', KERNEL_PATH . '/db/db_tag_processor.php', null, 'kTagProcessor');
- $this->registerClass('kCatDBTagProcessor', KERNEL_PATH . '/db/cat_tag_processor.php', null, 'kDBTagProcessor');
+ $this->registerClass('kMainTagProcessor', KERNEL_PATH . '/processors/main_processor.php', 'm_TagProcessor');
+ $this->registerClass('kDBTagProcessor', KERNEL_PATH . '/db/db_tag_processor.php');
+ $this->registerClass('kCatDBTagProcessor', KERNEL_PATH . '/db/cat_tag_processor.php');
$this->registerClass('NParser', KERNEL_PATH . '/nparser/nparser.php');
- $this->registerClass('TemplatesCache', KERNEL_PATH . '/nparser/template_cache.php', null, Array ('kHelper', 'kDBTagProcessor'));
+ $this->registerClass('TemplatesCache', KERNEL_PATH . '/nparser/template_cache.php');
// database
$this->registerClass('kDBConnection', KERNEL_PATH . '/db/db_connection.php');
$this->registerClass('kDBLoadBalancer', KERNEL_PATH . '/db/db_load_balancer.php');
$this->registerClass('kDBItem', KERNEL_PATH . '/db/dbitem.php');
- $this->registerClass('kCatDBItem', KERNEL_PATH . '/db/cat_dbitem.php', null, 'kDBItem');
+ $this->registerClass('kCatDBItem', KERNEL_PATH . '/db/cat_dbitem.php');
$this->registerClass('kDBList', KERNEL_PATH . '/db/dblist.php');
- $this->registerClass('kCatDBList', KERNEL_PATH . '/db/cat_dblist.php', null, 'kDBList');
+ $this->registerClass('kCatDBList', KERNEL_PATH . '/db/cat_dblist.php');
$this->registerClass('kDBEventHandler', KERNEL_PATH . '/db/db_event_handler.php');
- $this->registerClass('kCatDBEventHandler', KERNEL_PATH . '/db/cat_event_handler.php', null, 'kDBEventHandler');
+ $this->registerClass('kCatDBEventHandler', KERNEL_PATH . '/db/cat_event_handler.php');
// email sending
- $this->registerClass('kEmailSendingHelper', KERNEL_PATH . '/utility/email_send.php', 'EmailSender', 'kHelper');
+ $this->registerClass('kEmailSendingHelper', KERNEL_PATH . '/utility/email_send.php', 'EmailSender');
$this->registerClass('kSocket', KERNEL_PATH . '/utility/socket.php', 'Socket');
// do not move to config - this helper is used before configs are read
$this->registerClass('kModulesHelper', KERNEL_PATH . self::MODULE_HELPER_PATH, 'ModulesHelper');
}
/**
* Registers default build events
*
* @return void
* @access protected
*/
protected function RegisterDefaultBuildEvents()
{
$this->EventManager->registerBuildEvent('kTempTablesHandler', 'OnTempHandlerBuild');
}
/**
* Returns cached category information by given cache name. All given category
* information is recached, when at least one of 4 caches is missing.
*
* @param int $category_id
* @param string $name cache name = {filenames, category_designs, category_tree}
* @return string
* @access public
*/
public function getCategoryCache($category_id, $name)
{
return $this->cacheManager->getCategoryCache($category_id, $name);
}
/**
* Returns caching type (none, memory, temporary)
*
* @param int $caching_type
* @return bool
* @access public
*/
public function isCachingType($caching_type)
{
return $this->cacheManager->isCachingType($caching_type);
}
/**
* Increments serial based on prefix and it's ID (optional)
*
* @param string $prefix
* @param int $id ID (value of IDField) or ForeignKeyField:ID
* @param bool $increment
* @return string
* @access public
*/
public function incrementCacheSerial($prefix, $id = null, $increment = true)
{
return $this->cacheManager->incrementCacheSerial($prefix, $id, $increment);
}
/**
* Returns cached $key value from cache named $cache_name
*
* @param int $key key name from cache
* @param bool $store_locally store data locally after retrieved
* @param int $max_rebuild_seconds
* @return mixed
* @access public
*/
public function getCache($key, $store_locally = true, $max_rebuild_seconds = 0)
{
return $this->cacheManager->getCache($key, $store_locally, $max_rebuild_seconds);
}
/**
* Adds new value to cache $cache_name and identified by key $key
*
* @param int $key key name to add to cache
* @param mixed $value value of cached record
* @param int $expiration when value expires (0 - doesn't expire)
* @return bool
* @access public
*/
public function setCache($key, $value, $expiration = 0)
{
return $this->cacheManager->setCache($key, $value, $expiration);
}
/**
* Sets rebuilding mode for given cache
*
* @param string $name
* @param int $mode
* @param int $max_rebuilding_time
* @return void
* @access public
*/
public function rebuildCache($name, $mode = null, $max_rebuilding_time = 0)
{
$this->cacheManager->rebuildCache($name, $mode, $max_rebuilding_time);
}
/**
* Deletes key from cache
*
* @param string $key
* @return void
* @access public
*/
public function deleteCache($key)
{
$this->cacheManager->deleteCache($key);
}
/**
* Reset's all memory cache at once
*
* @return void
* @access public
*/
public function resetCache()
{
$this->cacheManager->resetCache();
}
/**
* Returns value from database cache
*
* @param string $name key name
* @param int $max_rebuild_seconds
* @return mixed
* @access public
*/
public function getDBCache($name, $max_rebuild_seconds = 0)
{
return $this->cacheManager->getDBCache($name, $max_rebuild_seconds);
}
/**
* Sets value to database cache
*
* @param string $name
* @param mixed $value
* @param int|bool $expiration
* @return void
* @access public
*/
public function setDBCache($name, $value, $expiration = false)
{
$this->cacheManager->setDBCache($name, $value, $expiration);
}
/**
* Sets rebuilding mode for given cache
*
* @param string $name
* @param int $mode
* @param int $max_rebuilding_time
* @return void
* @access public
*/
public function rebuildDBCache($name, $mode = null, $max_rebuilding_time = 0)
{
$this->cacheManager->rebuildDBCache($name, $mode, $max_rebuilding_time);
}
/**
* Deletes key from database cache
*
* @param string $name
* @return void
* @access public
*/
public function deleteDBCache($name)
{
$this->cacheManager->deleteDBCache($name);
}
/**
* Registers each module specific constants if any found
*
* @return bool
* @access protected
*/
protected function registerModuleConstants()
{
if ( file_exists(KERNEL_PATH . '/constants.php') ) {
kUtil::includeOnce(KERNEL_PATH . '/constants.php');
}
if ( !$this->ModuleInfo ) {
return false;
}
foreach ($this->ModuleInfo as $module_info) {
$constants_file = FULL_PATH . '/' . $module_info['Path'] . 'constants.php';
if ( file_exists($constants_file) ) {
kUtil::includeOnce($constants_file);
}
}
return true;
}
/**
* Performs redirect to hard maintenance template
*
* @return void
* @access public
*/
public function redirectToMaintenance()
{
$maintenance_page = WRITEBALE_BASE . '/maintenance.html';
$query_string = ''; // $this->isAdmin ? '' : '?next_template=' . urlencode($_SERVER['REQUEST_URI']);
if ( file_exists(FULL_PATH . $maintenance_page) ) {
header('Location: ' . BASE_PATH . $maintenance_page . $query_string);
exit;
}
}
/**
* Actually runs the parser against current template and stores parsing result
*
* This method gets 't' variable passed to the script, loads the template given in 't' variable and
* parses it. The result is store in {@link $this->HTML} property.
*
* @return void
* @access public
*/
public function Run()
{
// process maintenance mode redirect: begin
$maintenance_mode = $this->getMaintenanceMode();
if ( $maintenance_mode == MaintenanceMode::HARD ) {
$this->redirectToMaintenance();
}
elseif ( $maintenance_mode == MaintenanceMode::SOFT ) {
$maintenance_template = $this->isAdmin ? 'login' : $this->ConfigValue('SoftMaintenanceTemplate');
if ( $this->GetVar('t') != $maintenance_template ) {
$redirect_params = Array ();
if ( !$this->isAdmin ) {
$redirect_params['next_template'] = urlencode($_SERVER['REQUEST_URI']);
}
$this->Redirect($maintenance_template, $redirect_params);
}
}
// process maintenance mode redirect: end
if ( defined('DEBUG_MODE') && $this->isDebugMode() && kUtil::constOn('DBG_PROFILE_MEMORY') ) {
$this->Debugger->appendMemoryUsage('Application before Run:');
}
if ( $this->isAdminUser ) {
// for permission checking in events & templates
$this->LinkVar('module'); // for common configuration templates
$this->LinkVar('module_key'); // for common search templates
$this->LinkVar('section'); // for common configuration templates
if ( $this->GetVar('m_opener') == 'p' ) {
$this->LinkVar('main_prefix'); // window prefix, that opened selector
$this->LinkVar('dst_field'); // field to set value choosed in selector
}
if ( $this->GetVar('ajax') == 'yes' && !$this->GetVar('debug_ajax') ) {
// hide debug output from ajax requests automatically
kUtil::safeDefine('DBG_SKIP_REPORTING', 1); // safeDefine, because debugger also defines it
}
}
elseif ( $this->GetVar('admin') ) {
$admin_session =& $this->recallObject('Session.admin');
/* @var $admin_session Session */
// store Admin Console User's ID to Front-End's session for cross-session permission checks
$this->StoreVar('admin_user_id', (int)$admin_session->RecallVar('user_id'));
if ( $this->CheckAdminPermission('CATEGORY.MODIFY', 0, $this->getBaseCategory()) ) {
// user can edit cms blocks (when viewing front-end through admin's frame)
$editing_mode = $this->GetVar('editing_mode');
define('EDITING_MODE', $editing_mode ? $editing_mode : EDITING_MODE_BROWSE);
}
}
kUtil::safeDefine('EDITING_MODE', ''); // user can't edit anything
$this->Phrases->setPhraseEditing();
$this->EventManager->ProcessRequest();
$this->InitParser();
$t = $this->GetVar('render_template', $this->GetVar('t'));
if ( !$this->TemplatesCache->TemplateExists($t) && !$this->isAdmin ) {
$cms_handler =& $this->recallObject('st_EventHandler');
/* @var $cms_handler CategoriesEventHandler */
$t = ltrim($cms_handler->GetDesignTemplate(), '/');
if ( defined('DEBUG_MODE') && $this->isDebugMode() ) {
$this->Debugger->appendHTML('<strong>Design Template</strong>: ' . $t . '; <strong>CategoryID</strong>: ' . $this->GetVar('m_cat_id'));
}
}
/*else {
$cms_handler->SetCatByTemplate();
}*/
if ( defined('DEBUG_MODE') && $this->isDebugMode() && kUtil::constOn('DBG_PROFILE_MEMORY') ) {
$this->Debugger->appendMemoryUsage('Application before Parsing:');
}
$this->HTML = $this->Parser->Run($t);
if ( defined('DEBUG_MODE') && $this->isDebugMode() && kUtil::constOn('DBG_PROFILE_MEMORY') ) {
$this->Debugger->appendMemoryUsage('Application after Parsing:');
}
}
/**
* Only renders template
*
* @see kDBEventHandler::_errorNotFound()
*/
public function QuickRun()
{
$this->InitParser();
$this->HTML = $this->ParseBlock(Array ('name' => $this->GetVar('t')));
}
/**
* Performs template parser/cache initialization
*
* @param bool|string $theme_name
* @return void
* @access public
*/
public function InitParser($theme_name = false)
{
if ( !is_object($this->Parser) ) {
$this->Parser =& $this->recallObject('NParser');
$this->TemplatesCache =& $this->recallObject('TemplatesCache');
}
$this->TemplatesCache->forceThemeName = $theme_name;
}
/**
* Send the parser results to browser
*
* Actually send everything stored in {@link $this->HTML}, to the browser by echoing it.
*
* @return void
* @access public
*/
public function Done()
{
$this->HandleEvent(new kEvent('adm:OnBeforeShutdown'));
$debug_mode = defined('DEBUG_MODE') && $this->isDebugMode();
if ( $debug_mode && kUtil::constOn('DBG_PROFILE_MEMORY') ) {
$this->Debugger->appendMemoryUsage('Application before Done:');
}
if ( $debug_mode ) {
$this->EventManager->runScheduledTasks();
$this->Session->SaveData();
if ( kUtil::constOn('DBG_CACHE') ) {
$this->cacheManager->printStatistics();
}
$this->HTML = ob_get_clean() . $this->HTML . $this->Debugger->printReport(true);
}
else {
// send "Set-Cookie" header before any output is made
$this->Session->SetSession();
$this->HTML = ob_get_clean() . $this->HTML;
}
$language =& $this->recallObject('lang.current');
/* @var $language LanguagesItem */
// don't replace header if some tag (e.g. XMLTemplate) already set it to something else
header('Content-type: text/html; charset=' . $language->GetDBField('Charset'), false);
if ( $this->UseOutputCompression() ) {
$compression_level = $this->ConfigValue('OutputCompressionLevel');
if ( !$compression_level || $compression_level < 0 || $compression_level > 9 ) {
$compression_level = 7;
}
header('Content-Encoding: gzip');
echo gzencode($this->HTML, $compression_level);
}
else {
echo $this->HTML;
}
$this->cacheManager->UpdateApplicationCache();
flush();
if ( !$debug_mode ) {
$this->EventManager->runScheduledTasks();
$this->Session->SaveData();
}
if ( defined('DBG_CAPTURE_STATISTICS') && DBG_CAPTURE_STATISTICS && !$this->isAdmin ) {
$this->_storeStatistics();
}
}
/**
* Stores script execution statistics to database
*
* @return void
* @access protected
*/
protected function _storeStatistics()
{
global $start;
$script_time = microtime(true) - $start;
$query_statistics = $this->Conn->getQueryStatistics(); // time & count
$sql = 'SELECT *
FROM ' . TABLE_PREFIX . 'StatisticsCapture
WHERE TemplateName = ' . $this->Conn->qstr($this->GetVar('t'));
$data = $this->Conn->GetRow($sql);
if ( $data ) {
$this->_updateAverageStatistics($data, 'ScriptTime', $script_time);
$this->_updateAverageStatistics($data, 'SqlTime', $query_statistics['time']);
$this->_updateAverageStatistics($data, 'SqlCount', $query_statistics['count']);
$data['Hits']++;
$data['LastHit'] = adodb_mktime();
$this->Conn->doUpdate($data, TABLE_PREFIX . 'StatisticsCapture', 'StatisticsId = ' . $data['StatisticsId']);
}
else {
$data['ScriptTimeMin'] = $data['ScriptTimeAvg'] = $data['ScriptTimeMax'] = $script_time;
$data['SqlTimeMin'] = $data['SqlTimeAvg'] = $data['SqlTimeMax'] = $query_statistics['time'];
$data['SqlCountMin'] = $data['SqlCountAvg'] = $data['SqlCountMax'] = $query_statistics['count'];
$data['TemplateName'] = $this->GetVar('t');
$data['Hits'] = 1;
$data['LastHit'] = adodb_mktime();
$this->Conn->doInsert($data, TABLE_PREFIX . 'StatisticsCapture');
}
}
/**
* Calculates average time for statistics
*
* @param Array $data
* @param string $field_prefix
* @param float $current_value
* @return void
* @access protected
*/
protected function _updateAverageStatistics(&$data, $field_prefix, $current_value)
{
$data[$field_prefix . 'Avg'] = (($data['Hits'] * $data[$field_prefix . 'Avg']) + $current_value) / ($data['Hits'] + 1);
if ( $current_value < $data[$field_prefix . 'Min'] ) {
$data[$field_prefix . 'Min'] = $current_value;
}
if ( $current_value > $data[$field_prefix . 'Max'] ) {
$data[$field_prefix . 'Max'] = $current_value;
}
}
/**
* Remembers slow query SQL and execution time into log
*
* @param string $slow_sql
* @param int $time
* @return void
* @access public
*/
public function logSlowQuery($slow_sql, $time)
{
$query_crc = crc32($slow_sql);
$sql = 'SELECT *
FROM ' . TABLE_PREFIX . 'SlowSqlCapture
WHERE QueryCrc = ' . $query_crc;
$data = $this->Conn->Query($sql, null, true);
if ( $data ) {
$this->_updateAverageStatistics($data, 'Time', $time);
$template_names = explode(',', $data['TemplateNames']);
array_push($template_names, $this->GetVar('t'));
$data['TemplateNames'] = implode(',', array_unique($template_names));
$data['Hits']++;
$data['LastHit'] = adodb_mktime();
$this->Conn->doUpdate($data, TABLE_PREFIX . 'SlowSqlCapture', 'CaptureId = ' . $data['CaptureId']);
}
else {
$data['TimeMin'] = $data['TimeAvg'] = $data['TimeMax'] = $time;
$data['SqlQuery'] = $slow_sql;
$data['QueryCrc'] = $query_crc;
$data['TemplateNames'] = $this->GetVar('t');
$data['Hits'] = 1;
$data['LastHit'] = adodb_mktime();
$this->Conn->doInsert($data, TABLE_PREFIX . 'SlowSqlCapture');
}
}
/**
* Checks if output compression options is available
*
* @return bool
* @access protected
*/
protected function UseOutputCompression()
{
if ( kUtil::constOn('IS_INSTALL') || kUtil::constOn('DBG_ZEND_PRESENT') || kUtil::constOn('SKIP_OUT_COMPRESSION') ) {
return false;
}
return $this->ConfigValue('UseOutputCompression') && function_exists('gzencode') && strstr($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip');
}
// Facade
/**
* Returns current session id (SID)
*
* @return int
* @access public
*/
public function GetSID()
{
$session =& $this->recallObject('Session');
/* @var $session Session */
return $session->GetID();
}
/**
* Destroys current session
*
* @return void
* @access public
* @see UserHelper::logoutUser()
*/
public function DestroySession()
{
$session =& $this->recallObject('Session');
/* @var $session Session */
$session->Destroy();
}
/**
* Returns variable passed to the script as GET/POST/COOKIE
*
* @param string $name Name of variable to retrieve
* @param mixed $default default value returned in case if variable not present
* @return mixed
* @access public
*/
public function GetVar($name, $default = false)
{
return isset($this->HttpQuery->_Params[$name]) ? $this->HttpQuery->_Params[$name] : $default;
}
/**
* Returns variable passed to the script as $type
*
* @param string $name Name of variable to retrieve
* @param string $type Get/Post/Cookie
* @param mixed $default default value returned in case if variable not present
* @return mixed
* @access public
*/
public function GetVarDirect($name, $type, $default = false)
{
// $type = ucfirst($type);
$array = $this->HttpQuery->$type;
return isset($array[$name]) ? $array[$name] : $default;
}
/**
* Returns ALL variables passed to the script as GET/POST/COOKIE
*
* @return Array
* @access public
* @deprecated
*/
public function GetVars()
{
return $this->HttpQuery->GetParams();
}
/**
* Set the variable 'as it was passed to the script through GET/POST/COOKIE'
*
* This could be useful to set the variable when you know that
* other objects would relay on variable passed from GET/POST/COOKIE
* or you could use SetVar() / GetVar() pairs to pass the values between different objects.<br>
*
* @param string $var Variable name to set
* @param mixed $val Variable value
* @return void
* @access public
*/
public function SetVar($var,$val)
{
$this->HttpQuery->Set($var, $val);
}
/**
* Deletes kHTTPQuery variable
*
* @param string $var
* @return void
* @todo Think about method name
*/
public function DeleteVar($var)
{
$this->HttpQuery->Remove($var);
}
/**
* Deletes Session variable
*
* @param string $var
* @return void
* @access public
*/
public function RemoveVar($var)
{
$this->Session->RemoveVar($var);
}
/**
* Removes variable from persistent session
*
* @param string $var
* @return void
* @access public
*/
public function RemovePersistentVar($var)
{
$this->Session->RemovePersistentVar($var);
}
/**
* Restores Session variable to it's db version
*
* @param string $var
* @return void
* @access public
*/
public function RestoreVar($var)
{
$this->Session->RestoreVar($var);
}
/**
* Returns session variable value
*
* Return value of $var variable stored in Session. An optional default value could be passed as second parameter.
*
* @param string $var Variable name
* @param mixed $default Default value to return if no $var variable found in session
* @return mixed
* @access public
* @see Session::RecallVar()
*/
public function RecallVar($var,$default=false)
{
return $this->Session->RecallVar($var,$default);
}
/**
* Returns variable value from persistent session
*
* @param string $var
* @param mixed $default
* @return mixed
* @access public
* @see Session::RecallPersistentVar()
*/
public function RecallPersistentVar($var, $default = false)
{
return $this->Session->RecallPersistentVar($var, $default);
}
/**
* Stores variable $val in session under name $var
*
* Use this method to store variable in session. Later this variable could be recalled.
*
* @param string $var Variable name
* @param mixed $val Variable value
* @param bool $optional
* @return void
* @access public
* @see kApplication::RecallVar()
*/
public function StoreVar($var, $val, $optional = false)
{
$session =& $this->recallObject('Session');
/* @var $session Session */
$this->Session->StoreVar($var, $val, $optional);
}
/**
* Stores variable to persistent session
*
* @param string $var
* @param mixed $val
* @param bool $optional
* @return void
* @access public
*/
public function StorePersistentVar($var, $val, $optional = false)
{
$this->Session->StorePersistentVar($var, $val, $optional);
}
/**
* Stores default value for session variable
*
* @param string $var
* @param string $val
* @param bool $optional
* @return void
* @access public
* @see Session::RecallVar()
* @see Session::StoreVar()
*/
public function StoreVarDefault($var, $val, $optional = false)
{
$session =& $this->recallObject('Session');
/* @var $session Session */
$this->Session->StoreVarDefault($var, $val, $optional);
}
/**
* Links HTTP Query variable with session variable
*
* If variable $var is passed in HTTP Query it is stored in session for later use. If it's not passed it's recalled from session.
* This method could be used for making sure that GetVar will return query or session value for given
* variable, when query variable should overwrite session (and be stored there for later use).<br>
* This could be used for passing item's ID into popup with multiple tab -
* in popup script you just need to call LinkVar('id', 'current_id') before first use of GetVar('id').
* After that you can be sure that GetVar('id') will return passed id or id passed earlier and stored in session
*
* @param string $var HTTP Query (GPC) variable name
* @param mixed $ses_var Session variable name
* @param mixed $default Default variable value
* @param bool $optional
* @return void
* @access public
*/
public function LinkVar($var, $ses_var = null, $default = '', $optional = false)
{
if ( !isset($ses_var) ) {
$ses_var = $var;
}
if ( $this->GetVar($var) !== false ) {
$this->StoreVar($ses_var, $this->GetVar($var), $optional);
}
else {
$this->SetVar($var, $this->RecallVar($ses_var, $default));
}
}
/**
* Returns variable from HTTP Query, or from session if not passed in HTTP Query
*
* The same as LinkVar, but also returns the variable value taken from HTTP Query if passed, or from session if not passed.
* Returns the default value if variable does not exist in session and was not passed in HTTP Query
*
* @param string $var HTTP Query (GPC) variable name
* @param mixed $ses_var Session variable name
* @param mixed $default Default variable value
* @return mixed
* @access public
* @see LinkVar
*/
public function GetLinkedVar($var, $ses_var = null, $default = '')
{
$this->LinkVar($var, $ses_var, $default);
return $this->GetVar($var);
}
/**
* Renders given tag and returns it's output
*
* @param string $prefix
* @param string $tag
* @param Array $params
* @return mixed
* @access public
* @see kApplication::InitParser()
*/
public function ProcessParsedTag($prefix, $tag, $params)
{
$processor = $this->Parser->GetProcessor($prefix);
/* @var $processor kDBTagProcessor */
return $processor->ProcessParsedTag($tag, $params, $prefix);
}
/**
* Return ADODB Connection object
*
* Returns ADODB Connection object already connected to the project database, configurable in config.php
*
* @return kDBConnection
* @access public
*/
public function &GetADODBConnection()
{
return $this->Conn;
}
/**
* Allows to parse given block name or include template
*
* @param Array $params Parameters to pass to block. Reserved parameter "name" used to specify block name.
* @param bool $pass_params Forces to pass current parser params to this block/template. Use with caution, because you can accidentally pass "block_no_data" parameter.
* @param bool $as_template
* @return string
* @access public
*/
public function ParseBlock($params, $pass_params = false, $as_template = false)
{
if ( substr($params['name'], 0, 5) == 'html:' ) {
return substr($params['name'], 5);
}
return $this->Parser->ParseBlock($params, $pass_params, $as_template);
}
/**
* Checks, that we have given block defined
*
* @param string $name
* @return bool
* @access public
*/
public function ParserBlockFound($name)
{
return $this->Parser->blockFound($name);
}
/**
* Allows to include template with a given name and given parameters
*
* @param Array $params Parameters to pass to template. Reserved parameter "name" used to specify template name.
* @return string
* @access public
*/
public function IncludeTemplate($params)
{
return $this->Parser->IncludeTemplate($params, isset($params['is_silent']) ? 1 : 0);
}
/**
* Return href for template
*
* @param string $t Template path
* @param string $prefix index.php prefix - could be blank, 'admin'
* @param Array $params
* @param string $index_file
* @return string
*/
public function HREF($t, $prefix = '', $params = Array (), $index_file = null)
{
return $this->UrlManager->HREF($t, $prefix, $params, $index_file);
}
/**
* Returns theme template filename and it's corresponding page_id based on given seo template
*
* @param string $seo_template
* @return string
* @access public
*/
public function getPhysicalTemplate($seo_template)
{
return $this->UrlManager->getPhysicalTemplate($seo_template);
}
/**
* Returns template name, that corresponds with given virtual (not physical) page id
*
* @param int $page_id
* @return string|bool
* @access public
*/
public function getVirtualPageTemplate($page_id)
{
return $this->UrlManager->getVirtualPageTemplate($page_id);
}
/**
* Returns variables with values that should be passed through with this link + variable list
*
* @param Array $params
* @return Array
* @access public
*/
public function getPassThroughVariables(&$params)
{
return $this->UrlManager->getPassThroughVariables($params);
}
/**
* Builds url
*
* @param string $t
* @param Array $params
* @param string $pass
* @param bool $pass_events
* @param bool $env_var
* @return string
* @access public
*/
public function BuildEnv($t, $params, $pass = 'all', $pass_events = false, $env_var = true)
{
return $this->UrlManager->plain->build($t, $params, $pass, $pass_events, $env_var);
}
/**
* Process QueryString only, create
* events, ids, based on config
* set template name and sid in
* desired application variables.
*
* @param string $env_var environment string value
* @param string $pass_name
* @return Array
* @access public
*/
public function processQueryString($env_var, $pass_name = 'passed')
{
return $this->UrlManager->plain->parse($env_var, $pass_name);
}
/**
* Returns base part of all urls, build on website
*
* @param string $prefix
* @param bool $ssl
* @param bool $add_port
* @return string
* @access public
*/
public function BaseURL($prefix = '', $ssl = null, $add_port = true)
{
if ( $ssl === null ) {
// stay on same encryption level
return PROTOCOL . SERVER_NAME . ($add_port && defined('PORT') ? ':' . PORT : '') . BASE_PATH . $prefix . '/';
}
if ( $ssl ) {
// going from http:// to https://
$base_url = $this->isAdmin ? $this->ConfigValue('AdminSSL_URL') : false;
if ( !$base_url ) {
$ssl_url = $this->siteDomainField('SSLUrl');
$base_url = $ssl_url !== false ? $ssl_url : $this->ConfigValue('SSL_URL');
}
return rtrim($base_url, '/') . $prefix . '/';
}
// going from https:// to http://
$domain = $this->siteDomainField('DomainName');
if ( $domain === false ) {
$domain = DOMAIN;
}
return 'http://' . $domain . ($add_port && defined('PORT') ? ':' . PORT : '') . BASE_PATH . $prefix . '/';
}
/**
* Redirects user to url, that's build based on given parameters
*
* @param string $t
* @param Array $params
* @param string $prefix
* @param string $index_file
* @return void
* @access public
*/
public function Redirect($t = '', $params = Array(), $prefix = '', $index_file = null)
{
$js_redirect = getArrayValue($params, 'js_redirect');
if ( $t == '' || $t === true ) {
$t = $this->GetVar('t');
}
// pass prefixes and special from previous url
if ( array_key_exists('js_redirect', $params) ) {
unset($params['js_redirect']);
}
// allows to send custom responce code along with redirect header
if ( array_key_exists('response_code', $params) ) {
$response_code = (int)$params['response_code'];
unset($params['response_code']);
}
else {
$response_code = 302; // Found
}
if ( !array_key_exists('pass', $params) ) {
$params['pass'] = 'all';
}
if ( $this->GetVar('ajax') == 'yes' && $t == $this->GetVar('t') ) {
// redirects to the same template as current
$params['ajax'] = 'yes';
}
$params['__URLENCODE__'] = 1;
$location = $this->HREF($t, $prefix, $params, $index_file);
if ( $this->isDebugMode() && (kUtil::constOn('DBG_REDIRECT') || (kUtil::constOn('DBG_RAISE_ON_WARNINGS') && $this->Debugger->WarningCount)) ) {
$this->Debugger->appendTrace();
echo '<strong>Debug output above !!!</strong><br/>' . "\n";
if ( array_key_exists('HTTP_REFERER', $_SERVER) ) {
echo 'Referer: <strong>' . $_SERVER['HTTP_REFERER'] . '</strong><br/>' . "\n";
}
echo "Proceed to redirect: <a href=\"{$location}\">{$location}</a><br/>\n";
}
else {
if ( $js_redirect ) {
// show "redirect" template instead of redirecting,
// because "Set-Cookie" header won't work, when "Location"
// header is used later
$this->SetVar('t', 'redirect');
$this->SetVar('redirect_to', $location);
// make all additional parameters available on "redirect" template too
foreach ($params as $name => $value) {
$this->SetVar($name, $value);
}
return;
}
else {
if ( $this->GetVar('ajax') == 'yes' && $t != $this->GetVar('t') ) {
// redirection to other then current template during ajax request
kUtil::safeDefine('DBG_SKIP_REPORTING', 1);
echo '#redirect#' . $location;
}
elseif ( headers_sent() != '' ) {
// some output occurred -> redirect using javascript
echo '<script type="text/javascript">window.location.href = \'' . $location . '\';</script>';
}
else {
// no output before -> redirect using HTTP header
// header('HTTP/1.1 302 Found');
header('Location: ' . $location, true, $response_code);
}
}
}
// session expiration is called from session initialization,
// that's why $this->Session may be not defined here
$session =& $this->recallObject('Session');
/* @var $session Session */
$this->HandleEvent(new kEvent('adm:OnBeforeShutdown'));
$session->SaveData();
ob_end_flush();
exit;
}
/**
* Returns translation of given label
*
* @param string $label
* @param bool $allow_editing return translation link, when translation is missing on current language
* @param bool $use_admin use current Admin Console language to translate phrase
* @return string
* @access public
*/
public function Phrase($label, $allow_editing = true, $use_admin = false)
{
return $this->Phrases->GetPhrase($label, $allow_editing, $use_admin);
}
/**
* Replace language tags in exclamation marks found in text
*
* @param string $text
* @param bool $force_escape force escaping, not escaping of resulting string
* @return string
* @access public
*/
public function ReplaceLanguageTags($text, $force_escape = null)
{
return $this->Phrases->ReplaceLanguageTags($text, $force_escape);
}
/**
* Checks if user is logged in, and creates
* user object if so. User object can be recalled
* later using "u.current" prefix_special. Also you may
* get user id by getting "u.current_id" variable.
*
* @return void
* @access protected
*/
protected function ValidateLogin()
{
$session =& $this->recallObject('Session');
/* @var $session Session */
$user_id = $session->GetField('PortalUserId');
if ( !$user_id && $user_id != USER_ROOT ) {
$user_id = USER_GUEST;
}
$this->SetVar('u.current_id', $user_id);
if ( !$this->isAdmin ) {
// needed for "profile edit", "registration" forms ON FRONT ONLY
$this->SetVar('u_id', $user_id);
}
$this->StoreVar('user_id', $user_id, $user_id == USER_GUEST); // storing Guest user_id (-2) is optional
$this->isAdminUser = $this->isAdmin && $this->LoggedIn();
if ( $this->GetVar('expired') == 1 ) {
// this parameter is set only from admin
$user =& $this->recallObject('u.login-admin', null, Array ('form_name' => 'login'));
/* @var $user UsersItem */
$user->SetError('UserLogin', 'session_expired', 'la_text_sess_expired');
}
if ( ($user_id != USER_GUEST) && defined('DBG_REQUREST_LOG') && DBG_REQUREST_LOG ) {
$this->HttpQuery->writeRequestLog(DBG_REQUREST_LOG);
}
if ( $user_id != USER_GUEST ) {
// normal users + root
$this->LoadPersistentVars();
}
$user_timezone = $this->Session->GetField('TimeZone');
if ( $user_timezone ) {
putenv('TZ=' . $user_timezone);
}
}
/**
* Loads current user persistent session data
*
* @return void
* @access public
*/
public function LoadPersistentVars()
{
$this->Session->LoadPersistentVars();
}
/**
* Returns configuration option value by name
*
* @param string $name
* @return string
* @access public
*/
public function ConfigValue($name)
{
return $this->cacheManager->ConfigValue($name);
}
/**
* Changes value of individual configuration variable (+resets cache, when needed)
*
* @param string $name
* @param string $value
* @param bool $local_cache_only
* @return string
* @access public
*/
public function SetConfigValue($name, $value, $local_cache_only = false)
{
return $this->cacheManager->SetConfigValue($name, $value, $local_cache_only);
}
/**
* Allows to process any type of event
*
* @param kEvent $event
* @param Array $params
* @param Array $specific_params
* @access public
*/
- public function HandleEvent(&$event, $params = null, $specific_params = null)
+ public function HandleEvent($event, $params = null, $specific_params = null)
{
if ( isset($params) ) {
$event = new kEvent($params, $specific_params);
}
$this->EventManager->HandleEvent($event);
}
/**
* Registers new class in the factory
*
* @param string $real_class Real name of class as in class declaration
* @param string $file Filename in what $real_class is declared
* @param string $pseudo_class Name under this class object will be accessed using getObject method
- * @param Array $dependencies List of classes required for this class functioning
* @return void
* @access public
*/
- public function registerClass($real_class, $file, $pseudo_class = null, $dependencies = Array() )
+ public function registerClass($real_class, $file, $pseudo_class = null)
{
- $this->Factory->registerClass($real_class, $file, $pseudo_class, $dependencies);
+ $this->Factory->registerClass($real_class, $file, $pseudo_class);
}
/**
* Unregisters existing class from factory
*
* @param string $real_class Real name of class as in class declaration
* @param string $pseudo_class Name under this class object is accessed using getObject method
* @return void
* @access public
*/
public function unregisterClass($real_class, $pseudo_class = null)
{
$this->Factory->unregisterClass($real_class, $pseudo_class);
}
/**
- * Add $class_name to required classes list for $depended_class class.
- * All required class files are included before $depended_class file is included
- *
- * @param string $depended_class
- * @param string $class_name
- * @return void
- * @access public
- */
- public function registerDependency($depended_class, $class_name)
- {
- $this->Factory->registerDependency($depended_class, $class_name);
- }
-
- /**
* Add new scheduled task
*
* @param string $short_name name to be used to store last maintenance run info
* @param string $event_string
* @param int $run_interval run interval in seconds
* @param int $status
* @access public
*/
public function registerScheduledTask($short_name, $event_string, $run_interval, $status = STATUS_ACTIVE)
{
$this->EventManager->registerScheduledTask($short_name, $event_string, $run_interval, $status);
}
/**
* Registers Hook from subprefix event to master prefix event
*
* Pattern: Observer
*
* @param string $hook_event
* @param string $do_event
* @param int $mode
* @param bool $conditional
* @access public
*/
public function registerHook($hook_event, $do_event, $mode = hAFTER, $conditional = false)
{
$this->EventManager->registerHook($hook_event, $do_event, $mode, $conditional);
}
/**
* Registers build event for given pseudo class
*
* @param string $pseudo_class
* @param string $event_name
* @access public
*/
public function registerBuildEvent($pseudo_class, $event_name)
{
$this->EventManager->registerBuildEvent($pseudo_class, $event_name);
}
/**
* Allows one TagProcessor tag act as other TagProcessor tag
*
* @param Array $tag_info
* @return void
* @access public
*/
public function registerAggregateTag($tag_info)
{
$aggregator =& $this->recallObject('TagsAggregator', 'kArray');
/* @var $aggregator kArray */
$tag_data = Array (
$tag_info['LocalPrefix'],
$tag_info['LocalTagName'],
getArrayValue($tag_info, 'LocalSpecial')
);
$aggregator->SetArrayValue($tag_info['AggregateTo'], $tag_info['AggregatedTagName'], $tag_data);
}
/**
* Returns object using params specified, creates it if is required
*
* @param string $name
* @param string $pseudo_class
* @param Array $event_params
* @param Array $arguments
* @return kBase
*/
public function &recallObject($name, $pseudo_class = null, $event_params = Array(), $arguments = Array ())
{
/*if ( !$this->hasObject($name) && $this->isDebugMode() && ($name == '_prefix_here_') ) {
// first time, when object with "_prefix_here_" prefix is accessed
$this->Debugger->appendTrace();
}*/
$result =& $this->Factory->getObject($name, $pseudo_class, $event_params, $arguments);
return $result;
}
/**
* Returns tag processor for prefix specified
*
* @param string $prefix
* @return kDBTagProcessor
* @access public
*/
public function &recallTagProcessor($prefix)
{
$this->InitParser(); // because kDBTagProcesor is in NParser dependencies
$result =& $this->recallObject($prefix . '_TagProcessor');
return $result;
}
/**
* Checks if object with prefix passes was already created in factory
*
* @param string $name object pseudo_class, prefix
* @return bool
* @access public
*/
public function hasObject($name)
{
- return isset($this->Factory->Storage[$name]);
+ return $this->Factory->hasObject($name);
}
/**
* Removes object from storage by given name
*
* @param string $name Object's name in the Storage
* @return void
* @access public
*/
public function removeObject($name)
{
$this->Factory->DestroyObject($name);
}
/**
* Get's real class name for pseudo class, includes class file and creates class instance
*
* Pattern: Factory Method
*
* @param string $pseudo_class
* @param Array $arguments
* @return kBase
* @access public
*/
public function &makeClass($pseudo_class, $arguments = Array ())
{
$result =& $this->Factory->makeClass($pseudo_class, $arguments);
return $result;
}
/**
* Checks if application is in debug mode
*
* @param bool $check_debugger check if kApplication debugger is initialized too, not only for defined DEBUG_MODE constant
* @return bool
* @author Alex
* @access public
*/
public function isDebugMode($check_debugger = true)
{
$debug_mode = defined('DEBUG_MODE') && DEBUG_MODE;
if ($check_debugger) {
$debug_mode = $debug_mode && is_object($this->Debugger);
}
return $debug_mode;
}
/**
* Apply url rewriting used by mod_rewrite or not
*
* @param bool|null $ssl Force ssl link to be build
* @return bool
* @access public
*/
public function RewriteURLs($ssl = false)
{
// case #1,#4:
// we want to create https link from http mode
// we want to create https link from https mode
// conditions: ($ssl || PROTOCOL == 'https://') && $this->ConfigValue('UseModRewriteWithSSL')
// case #2,#3:
// we want to create http link from https mode
// we want to create http link from http mode
// conditions: !$ssl && (PROTOCOL == 'https://' || PROTOCOL == 'http://')
$allow_rewriting =
(!$ssl && (PROTOCOL == 'https://' || PROTOCOL == 'http://')) // always allow mod_rewrite for http
|| // or allow rewriting for redirect TO httpS or when already in httpS
(($ssl || PROTOCOL == 'https://') && $this->ConfigValue('UseModRewriteWithSSL')); // but only if it's allowed in config!
return kUtil::constOn('MOD_REWRITE') && $allow_rewriting;
}
/**
* Reads unit (specified by $prefix)
* option specified by $option
*
* @param string $prefix
* @param string $option
* @param mixed $default
* @return string
* @access public
*/
public function getUnitOption($prefix, $option, $default = false)
{
return $this->UnitConfigReader->getUnitOption($prefix, $option, $default);
}
/**
* Set's new unit option value
*
* @param string $prefix
* @param string $option
* @param string $value
* @access public
*/
public function setUnitOption($prefix, $option, $value)
{
$this->UnitConfigReader->setUnitOption($prefix,$option,$value);
}
/**
* Read all unit with $prefix options
*
* @param string $prefix
* @return Array
* @access public
*/
public function getUnitOptions($prefix)
{
return $this->UnitConfigReader->getUnitOptions($prefix);
}
/**
* Returns true if config exists and is allowed for reading
*
* @param string $prefix
* @return bool
*/
public function prefixRegistred($prefix)
{
return $this->UnitConfigReader->prefixRegistred($prefix);
}
/**
* Splits any mixing of prefix and
* special into correct ones
*
* @param string $prefix_special
* @return Array
* @access public
*/
public function processPrefix($prefix_special)
{
return $this->Factory->processPrefix($prefix_special);
}
/**
* Set's new event for $prefix_special
* passed
*
* @param string $prefix_special
* @param string $event_name
* @return void
* @access public
*/
public function setEvent($prefix_special, $event_name)
{
$this->EventManager->setEvent($prefix_special, $event_name);
}
/**
* SQL Error Handler
*
* @param int $code
* @param string $msg
* @param string $sql
* @return bool
* @access public
*/
public function handleSQLError($code, $msg, $sql)
{
if ( isset($this->Debugger) ) {
$long_error_msg = '<span class="debug_error">' . $msg . ' (' . $code . ')</span><br/><a href="javascript:$Debugger.SetClipboard(\'' . htmlspecialchars($sql) . '\');"><strong>SQL</strong></a>: ' . $this->Debugger->formatSQL($sql);
$long_id = $this->Debugger->mapLongError($long_error_msg);
$error_msg = mb_substr($msg . ' (' . $code . ') [' . $sql . ']', 0, 1000) . ' #' . $long_id;
if ( kUtil::constOn('DBG_SQL_FAILURE') && !defined('IS_INSTALL') ) {
throw new Exception($error_msg);
}
else {
$this->Debugger->appendTrace();
}
}
else {
// when not debug mode, then fatal database query won't break anything
$error_msg = '<strong>SQL Error</strong> in sql: ' . $sql . ', code <strong>' . $code . '</strong> (' . $msg . ')';
}
trigger_error($error_msg, E_USER_WARNING);
return true;
}
/**
* Default error handler
*
* @param int $errno
* @param string $errstr
* @param string $errfile
* @param int $errline
* @param Array $errcontext
* @return bool
* @access public
*/
public function handleError($errno, $errstr, $errfile = null, $errline = null, $errcontext = Array ())
{
$this->errorLogSilent($errno, $errstr, $errfile, $errline);
$debug_mode = defined('DEBUG_MODE') && DEBUG_MODE;
$skip_reporting = defined('DBG_SKIP_REPORTING') && DBG_SKIP_REPORTING;
if ( !$this->errorHandlers || ($debug_mode && $skip_reporting) ) {
// when debugger absent OR it's present, but we actually can't see it's error report (e.g. during ajax request)
if ( $errno == E_USER_ERROR ) {
$this->errorDisplayFatal('<strong>Fatal Error: </strong>' . "{$errstr} in {$errfile} on line {$errline}");
}
if ( !$this->errorHandlers ) {
return true;
}
}
$res = false;
/* @var $handler Closure */
foreach ($this->errorHandlers as $handler) {
if ( is_array($handler) ) {
$object =& $handler[0];
$method = $handler[1];
$res = $object->$method($errno, $errstr, $errfile, $errline, $errcontext);
}
else {
$res = $handler($errno, $errstr, $errfile, $errline, $errcontext);
}
}
return $res;
}
/**
* Handles exception
*
* @param Exception $exception
* @return bool
* @access public
*/
public function handleException($exception)
{
// transform exception to regular error (no need to rewrite existing error handlers)
$errno = $exception->getCode();
$errstr = $exception->getMessage();
$errfile = $exception->getFile();
$errline = $exception->getLine();
$this->errorLogSilent($errno, $errstr, $errfile, $errline);
$debug_mode = defined('DEBUG_MODE') && DEBUG_MODE;
$skip_reporting = defined('DBG_SKIP_REPORTING') && DBG_SKIP_REPORTING;
if ( !$this->exceptionHandlers || ($debug_mode && $skip_reporting) ) {
// when debugger absent OR it's present, but we actually can't see it's error report (e.g. during ajax request)
$this->errorDisplayFatal('<strong>' . get_class($exception) . ': </strong>' . "{$errstr} in {$errfile} on line {$errline}");
if ( !$this->exceptionHandlers ) {
return true;
}
}
$res = false;
/* @var $handler Closure */
foreach ($this->exceptionHandlers as $handler) {
if ( is_array($handler) ) {
$object =& $handler[0];
$method = $handler[1];
$res = $object->$method($exception);
}
else {
$res = $handler($exception);
}
}
return $res;
}
/**
* Silently saves each given error message to "silent_log.txt" file, when silent log mode is enabled
* @param int $errno
* @param string $errstr
* @param string $errfile
* @param int $errline
* @return void
* @access protected
*/
protected function errorLogSilent($errno, $errstr = '', $errfile = '', $errline = null)
{
if ( !defined('SILENT_LOG') || !SILENT_LOG ) {
return;
}
if ( !(defined('DBG_IGNORE_STRICT_ERRORS') && DBG_IGNORE_STRICT_ERRORS && defined('E_STRICT') && ($errno == E_STRICT)) ) {
$time = adodb_date('d/m/Y H:i:s');
$fp = fopen((defined('RESTRICTED') ? RESTRICTED : FULL_PATH) . '/silent_log.txt', 'a');
fwrite($fp, '[' . $time . '] #' . $errno . ': ' . strip_tags($errstr) . ' in [' . $errfile . '] on line ' . $errline . "\n");
fclose($fp);
}
}
/**
* Displays div with given error message
*
* @param string $msg
* @return void
* @access protected
*/
protected function errorDisplayFatal($msg)
{
$margin = $this->isAdmin ? '8px' : 'auto';
echo '<div style="background-color: #FEFFBF; margin: ' . $margin . '; padding: 10px; border: 2px solid red; text-align: center">' . $msg . '</div>';
exit;
}
/**
* Prints trace, when debug mode is not available
*
* @param bool $return_result
* @param int $skip_levels
* @return string
* @access public
*/
public function printTrace($return_result = false, $skip_levels = 1)
{
$ret = Array ();
$trace = debug_backtrace(false);
for ($i = 0; $i < $skip_levels; $i++) {
array_shift($trace);
}
foreach ($trace as $level => $trace_info) {
if ( isset($trace_info['class']) ) {
$object = $trace_info['class'];
}
elseif ( isset($trace_info['object']) ) {
$object = get_class($trace_info['object']);
}
else {
$object = '';
}
$args = '';
$type = isset($trace_info['type']) ? $trace_info['type'] : '';
if ( isset($trace_info['args']) ) {
foreach ($trace_info['args'] as $argument) {
if ( is_object($argument) ) {
$args .= get_class($argument) . ' instance, ';
}
else {
$args .= is_array($argument) ? 'Array' : substr($argument, 0, 10) . ' ..., ';
}
}
$args = substr($args, 0, -2);
}
$ret[] = '#' . $level . ' ' . $object . $type . $trace_info['function'] . '(' . $args . ') called at [' . $trace_info['file'] . ':' . $trace_info['line'] . ']';
}
if ( $return_result ) {
return implode("\n", $ret);
}
echo implode("\n", $ret);
return '';
}
/**
* Returns & blocks next ResourceId available in system
*
* @return int
* @access public
*/
public function NextResourceId()
{
$table_name = TABLE_PREFIX . 'IdGenerator';
$this->Conn->Query('LOCK TABLES ' . $table_name . ' WRITE');
$this->Conn->Query('UPDATE ' . $table_name . ' SET lastid = lastid + 1');
$id = $this->Conn->GetOne('SELECT lastid FROM ' . $table_name);
if ( $id === false ) {
$this->Conn->Query('INSERT INTO ' . $table_name . ' (lastid) VALUES (2)');
$id = 2;
}
$this->Conn->Query('UNLOCK TABLES');
return $id - 1;
}
/**
* Returns genealogical main prefix for sub-table prefix passes
* OR prefix, that has been found in REQUEST and some how is parent of passed sub-table prefix
*
* @param string $current_prefix
* @param bool $real_top if set to true will return real topmost prefix, regardless of its id is passed or not
* @return string
* @access public
*/
public function GetTopmostPrefix($current_prefix, $real_top = false)
{
// 1. get genealogical tree of $current_prefix
$prefixes = Array ($current_prefix);
while ($parent_prefix = $this->getUnitOption($current_prefix, 'ParentPrefix')) {
if ( !$this->prefixRegistred($parent_prefix) ) {
// stop searching, when parent prefix is not registered
break;
}
$current_prefix = $parent_prefix;
array_unshift($prefixes, $current_prefix);
}
if ( $real_top ) {
return $current_prefix;
}
// 2. find what if parent is passed
$passed = explode(',', $this->GetVar('all_passed'));
foreach ($prefixes as $a_prefix) {
if ( in_array($a_prefix, $passed) ) {
return $a_prefix;
}
}
return $current_prefix;
}
/**
* Triggers email event of type Admin
*
* @param string $email_event_name
* @param int $to_user_id
* @param array $send_params associative array of direct send params, possible keys: to_email, to_name, from_email, from_name, message, message_text
* @return kEvent
* @access public
*/
public function &EmailEventAdmin($email_event_name, $to_user_id = null, $send_params = Array ())
{
$event =& $this->EmailEvent($email_event_name, EmailEvent::EVENT_TYPE_ADMIN, $to_user_id, $send_params);
return $event;
}
/**
* Triggers email event of type User
*
* @param string $email_event_name
* @param int $to_user_id
* @param array $send_params associative array of direct send params, possible keys: to_email, to_name, from_email, from_name, message, message_text
* @return kEvent
* @access public
*/
public function &EmailEventUser($email_event_name, $to_user_id = null, $send_params = Array ())
{
$event =& $this->EmailEvent($email_event_name, EmailEvent::EVENT_TYPE_FRONTEND, $to_user_id, $send_params);
return $event;
}
/**
* Triggers general email event
*
* @param string $email_event_name
* @param int $email_event_type (0 for User, 1 for Admin)
* @param int $to_user_id
* @param array $send_params associative array of direct send params,
* possible keys: to_email, to_name, from_email, from_name, message, message_text
* @return kEvent
* @access protected
*/
protected function &EmailEvent($email_event_name, $email_event_type, $to_user_id = null, $send_params = Array ())
{
$params = Array (
'EmailEventName' => $email_event_name,
'EmailEventToUserId' => $to_user_id,
'EmailEventType' => $email_event_type,
'DirectSendParams' => $send_params,
);
if ( array_key_exists('use_special', $send_params) ) {
$event_str = 'emailevents.' . $send_params['use_special'] . ':OnEmailEvent';
}
else {
$event_str = 'emailevents:OnEmailEvent';
}
- $this->HandleEvent($event, $event_str, $params);
+ $event = new kEvent($event_str, $params);
+ $this->HandleEvent($event);
return $event;
}
/**
* Allows to check if user in this session is logged in or not
*
* @return bool
* @access public
*/
public function LoggedIn()
{
// no session during expiration process
return is_null($this->Session) ? false : $this->Session->LoggedIn();
}
/**
* Check current user permissions based on it's group permissions in specified category
*
* @param string $name permission name
* @param int $cat_id category id, current used if not specified
* @param int $type permission type {1 - system, 0 - per category}
* @return int
* @access public
*/
public function CheckPermission($name, $type = 1, $cat_id = null)
{
$perm_helper =& $this->recallObject('PermissionsHelper');
/* @var $perm_helper kPermissionsHelper */
return $perm_helper->CheckPermission($name, $type, $cat_id);
}
/**
* Check current admin permissions based on it's group permissions in specified category
*
* @param string $name permission name
* @param int $cat_id category id, current used if not specified
* @param int $type permission type {1 - system, 0 - per category}
* @return int
* @access public
*/
public function CheckAdminPermission($name, $type = 1, $cat_id = null)
{
$perm_helper =& $this->recallObject('PermissionsHelper');
/* @var $perm_helper kPermissionsHelper */
return $perm_helper->CheckAdminPermission($name, $type, $cat_id);
}
/**
* Set's any field of current visit
*
* @param string $field
* @param mixed $value
* @return void
* @access public
* @todo move to separate module
*/
public function setVisitField($field, $value)
{
if ( $this->isAdmin || !$this->ConfigValue('UseVisitorTracking') ) {
// admin logins are not registered in visits list
return;
}
$visit =& $this->recallObject('visits', null, Array ('raise_warnings' => 0));
/* @var $visit kDBItem */
if ( $visit->isLoaded() ) {
$visit->SetDBField($field, $value);
$visit->Update();
}
}
/**
* Allows to check if in-portal is installed
*
* @return bool
* @access public
*/
public function isInstalled()
{
return $this->InitDone && (count($this->ModuleInfo) > 0);
}
/**
* Allows to determine if module is installed & enabled
*
* @param string $module_name
* @return bool
* @access public
*/
public function isModuleEnabled($module_name)
{
return $this->findModule('Name', $module_name) !== false;
}
/**
* Returns Window ID of passed prefix main prefix (in edit mode)
*
* @param string $prefix
* @return int
* @access public
*/
public function GetTopmostWid($prefix)
{
$top_prefix = $this->GetTopmostPrefix($prefix);
$mode = $this->GetVar($top_prefix . '_mode');
return $mode != '' ? substr($mode, 1) : '';
}
/**
* Get temp table name
*
* @param string $table
* @param mixed $wid
* @return string
* @access public
*/
public function GetTempName($table, $wid = '')
{
return $this->GetTempTablePrefix($wid) . $table;
}
/**
* Builds temporary table prefix based on given window id
*
* @param string $wid
* @return string
* @access public
*/
public function GetTempTablePrefix($wid = '')
{
if ( preg_match('/prefix:(.*)/', $wid, $regs) ) {
$wid = $this->GetTopmostWid($regs[1]);
}
return TABLE_PREFIX . 'ses_' . $this->GetSID() . ($wid ? '_' . $wid : '') . '_edit_';
}
/**
* Checks if given table is a temporary table
*
* @param string $table
* @return bool
* @access public
*/
public function IsTempTable($table)
{
static $cache = Array ();
if ( !array_key_exists($table, $cache) ) {
$cache[$table] = preg_match('/' . TABLE_PREFIX . 'ses_' . $this->GetSID() . '(_[\d]+){0,1}_edit_(.*)/', $table);
}
return (bool)$cache[$table];
}
/**
* Checks, that given prefix is in temp mode
*
* @param string $prefix
* @param string $special
* @return bool
* @access public
*/
public function IsTempMode($prefix, $special = '')
{
$top_prefix = $this->GetTopmostPrefix($prefix);
$var_names = Array (
$top_prefix,
rtrim($top_prefix . '_' . $special, '_'), // from post
rtrim($top_prefix . '.' . $special, '.'), // assembled locally
);
$var_names = array_unique($var_names);
$temp_mode = false;
foreach ($var_names as $var_name) {
$value = $this->GetVar($var_name . '_mode');
if ( $value && (substr($value, 0, 1) == 't') ) {
$temp_mode = true;
break;
}
}
return $temp_mode;
}
/**
* Return live table name based on temp table name
*
* @param string $temp_table
* @return string
*/
public function GetLiveName($temp_table)
{
if ( preg_match('/' . TABLE_PREFIX . 'ses_' . $this->GetSID() . '(_[\d]+){0,1}_edit_(.*)/', $temp_table, $rets) ) {
// cut wid from table end if any
return $rets[2];
}
else {
return $temp_table;
}
}
/**
* Stops processing of user request and displays given message
*
* @param string $message
* @access public
*/
public function ApplicationDie($message = '')
{
$message = ob_get_clean() . $message;
if ( $this->isDebugMode() ) {
$message .= $this->Debugger->printReport(true);
}
echo $this->UseOutputCompression() ? gzencode($message, DBG_COMPRESSION_LEVEL) : $message;
exit;
}
/**
* Returns comma-separated list of groups from given user
*
* @param int $user_id
* @return string
*/
public function getUserGroups($user_id)
{
switch ($user_id) {
case USER_ROOT:
$user_groups = $this->ConfigValue('User_LoggedInGroup');
break;
case USER_GUEST:
$user_groups = $this->ConfigValue('User_LoggedInGroup') . ',' . $this->ConfigValue('User_GuestGroup');
break;
default:
$sql = 'SELECT GroupId
FROM ' . TABLE_PREFIX . 'UserGroupRelations
WHERE PortalUserId = ' . (int)$user_id;
$res = $this->Conn->GetCol($sql);
$user_groups = Array ($this->ConfigValue('User_LoggedInGroup'));
if ( $res ) {
$user_groups = array_merge($user_groups, $res);
}
$user_groups = implode(',', $user_groups);
}
return $user_groups;
}
/**
* Allows to detect if page is browsed by spider (293 scheduled_tasks supported)
*
* @return bool
* @access public
*/
/*public function IsSpider()
{
static $is_spider = null;
if ( !isset($is_spider) ) {
$user_agent = trim($_SERVER['HTTP_USER_AGENT']);
$robots = file(FULL_PATH . '/core/robots_list.txt');
foreach ($robots as $robot_info) {
$robot_info = explode("\t", $robot_info, 3);
if ( $user_agent == trim($robot_info[2]) ) {
$is_spider = true;
break;
}
}
}
return $is_spider;
}*/
/**
* Allows to detect table's presence in database
*
* @param string $table_name
* @param bool $force
* @return bool
* @access public
*/
public function TableFound($table_name, $force = false)
{
return $this->Conn->TableFound($table_name, $force);
}
/**
* Returns counter value
*
* @param string $name counter name
* @param Array $params counter parameters
* @param string $query_name specify query name directly (don't generate from parameters)
* @param bool $multiple_results
* @return mixed
* @access public
*/
public function getCounter($name, $params = Array (), $query_name = null, $multiple_results = false)
{
$count_helper =& $this->recallObject('CountHelper');
/* @var $count_helper kCountHelper */
return $count_helper->getCounter($name, $params, $query_name, $multiple_results);
}
/**
* Resets counter, which are affected by one of specified tables
*
* @param string $tables comma separated tables list used in counting sqls
* @return void
* @access public
*/
public function resetCounters($tables)
{
if ( kUtil::constOn('IS_INSTALL') ) {
return;
}
$count_helper =& $this->recallObject('CountHelper');
/* @var $count_helper kCountHelper */
$count_helper->resetCounters($tables);
}
/**
* Sends XML header + optionally displays xml heading
*
* @param string|bool $xml_version
* @return string
* @access public
* @author Alex
*/
public function XMLHeader($xml_version = false)
{
$lang =& $this->recallObject('lang.current');
/* @var $lang LanguagesItem */
header('Content-type: text/xml; charset=' . $lang->GetDBField('Charset'));
return $xml_version ? '<?xml version="' . $xml_version . '" encoding="' . $lang->GetDBField('Charset') . '"?>' : '';
}
/**
* Returns category tree
*
* @param int $category_id
* @return Array
* @access public
*/
public function getTreeIndex($category_id)
{
$tree_index = $this->getCategoryCache($category_id, 'category_tree');
if ( $tree_index ) {
$ret = Array ();
list ($ret['TreeLeft'], $ret['TreeRight']) = explode(';', $tree_index);
return $ret;
}
return false;
}
/**
* Base category of all categories
* Usually replaced category, with ID = 0 in category-related operations.
*
* @return int
* @access public
*/
public function getBaseCategory()
{
// same, what $this->findModule('Name', 'Core', 'RootCat') does
// don't cache while IS_INSTALL, because of kInstallToolkit::createModuleCategory and upgrade
return $this->ModuleInfo['Core']['RootCat'];
}
/**
* Deletes all data, that was cached during unit config parsing (excluding unit config locations)
*
* @param Array $config_variables
* @access public
*/
public function DeleteUnitCache($config_variables = null)
{
$this->cacheManager->DeleteUnitCache($config_variables);
}
/**
* Deletes cached section tree, used during permission checking and admin console tree display
*
* @return void
* @access public
*/
public function DeleteSectionCache()
{
$this->cacheManager->DeleteSectionCache();
}
/**
* Sets data from cache to object
*
* @param Array $data
* @access public
*/
public function setFromCache(&$data)
{
$this->Factory->setFromCache($data);
$this->UnitConfigReader->setFromCache($data);
$this->EventManager->setFromCache($data);
$this->ReplacementTemplates = $data['Application.ReplacementTemplates'];
$this->RewriteListeners = $data['Application.RewriteListeners'];
$this->ModuleInfo = $data['Application.ModuleInfo'];
}
/**
* Gets object data for caching
* The following caches should be reset based on admin interaction (adjusting config, enabling modules etc)
*
* @access public
* @return Array
*/
public function getToCache()
{
return array_merge(
$this->Factory->getToCache(),
$this->UnitConfigReader->getToCache(),
$this->EventManager->getToCache(),
Array (
'Application.ReplacementTemplates' => $this->ReplacementTemplates,
'Application.RewriteListeners' => $this->RewriteListeners,
'Application.ModuleInfo' => $this->ModuleInfo,
)
);
}
public function delayUnitProcessing($method, $params)
{
$this->cacheManager->delayUnitProcessing($method, $params);
}
/**
* Returns current maintenance mode state
*
* @param bool $check_ips
* @return int
* @access public
*/
public function getMaintenanceMode($check_ips = true)
{
$exception_ips = defined('MAINTENANCE_MODE_IPS') ? MAINTENANCE_MODE_IPS : '';
$setting_name = $this->isAdmin ? 'MAINTENANCE_MODE_ADMIN' : 'MAINTENANCE_MODE_FRONT';
if ( defined($setting_name) && constant($setting_name) > MaintenanceMode::NONE ) {
$exception_ip = $check_ips ? kUtil::ipMatch($exception_ips) : false;
if ( !$exception_ip ) {
return constant($setting_name);
}
}
return MaintenanceMode::NONE;
}
}
\ No newline at end of file
Index: branches/5.2.x/core/kernel/managers/hook_manager.php
===================================================================
--- branches/5.2.x/core/kernel/managers/hook_manager.php (revision 15129)
+++ branches/5.2.x/core/kernel/managers/hook_manager.php (revision 15130)
@@ -1,185 +1,185 @@
<?php
/**
* @version $Id$
* @package In-Portal
* @copyright Copyright (C) 1997 - 2010 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 kHookManager extends kBase implements kiCacheable {
/**
* Holds before hooks
* key - prefix.event (to link to)
* value - hooked event info
*
* @var Array
* @access protected
*/
protected $beforeHooks = Array ();
/**
* Holds after hooks
* key - prefix.event (to link to)
* value - hooked event info
*
* @var Array
* @access protected
*/
protected $afterHooks = Array ();
/**
* Sets data from cache to object
*
* @param Array $data
* @access public
*/
public function setFromCache(&$data)
{
$this->beforeHooks = $data['EventManager.beforeHooks'];
$this->afterHooks = $data['EventManager.afterHooks'];
}
/**
* Gets object data for caching
*
* @return Array
* @access public
*/
public function getToCache()
{
return Array (
'EventManager.beforeHooks' => $this->beforeHooks,
'EventManager.afterHooks' => $this->afterHooks
);
}
/**
* Returns hooks by mode
*
* @param int $mode
* @return Array
* @access protected
*/
protected function &getHooksByMode($mode)
{
if ($mode == hBEFORE) {
return $this->beforeHooks;
}
return $this->afterHooks;
}
/**
* Registers Hook from subprefix event to master prefix event
*
* @param string $hook_event
* @param string $do_event
* @param int $mode
* @param bool $conditional
* @access public
*/
public function registerHook($hook_event, $do_event, $mode = hAFTER, $conditional = false)
{
$hook_event = new kEvent($hook_event);
$do_event = new kEvent($do_event);
if ( ($hook_event->Prefix != '*') && !$this->Application->prefixRegistred($hook_event->Prefix) ) {
if ($this->Application->isDebugMode()) {
trigger_error('Prefix <strong>' . $hook_event->Prefix . '</strong> doesn\'t exist when trying to hook from <strong>' . (string)$do_event . '</strong>', E_USER_WARNING);
}
return;
}
$hooks =& $this->getHooksByMode($mode);
$hook_key = str_replace(':', '.', (string)$hook_event);
$hooks[ strtolower($hook_key) ][] = Array (
'DoPrefix' => $do_event->Prefix,
'DoSpecial' => $do_event->Special,
'DoEvent' => $do_event->Name,
'Conditional' => $conditional,
);
}
/**
* Runs hooks for given event
*
* @param kEvent $event
* @param int $mode hBEFORE or hAFTER
* @access public
*/
- public function runHooks(&$event, $mode)
+ public function runHooks($event, $mode)
{
// * - get hooks that are valid with any special of given prefix
$hooks = array_merge(
// given prefix, any special
$this->_getHooks($event, $mode, $event->Prefix.'.*'),
// given special, given special
$this->_getHooks($event, $mode),
// any prefix, any special
$this->_getHooks($event, $mode, '*.*'),
// any prefix, given special
$this->_getHooks($event, $mode, rtrim('*.' . $event->Special, '.'))
);
if (!$hooks) {
return ;
}
foreach ($hooks as $hook) {
if ($hook['DoSpecial'] == '*') {
// use same special as master event
$hook['DoSpecial'] = $event->Special;
}
$prefix_special = rtrim($hook['DoPrefix'].'_'.$hook['DoSpecial'], '_');
if ( $hook['Conditional'] && !$this->Application->GetVar($prefix_special) ) {
continue;
}
if ( $this->Application->prefixRegistred($hook['DoPrefix']) ) {
// run hook only, when it's config is found
$hook_event = new kEvent($hook['DoPrefix'] . '.' . $hook['DoSpecial'] . ':' . $hook['DoEvent']);
$hook_event->MasterEvent =& $event;
$this->Application->HandleEvent($hook_event);
}
}
}
/**
* Returns hooks for given event
*
* @param kEvent $event
* @param int $mode hBEFORE or hAFTER
* @param string $event_key
* @return Array
* @access protected
*/
- protected function &_getHooks(&$event, $mode, $event_key = null)
+ protected function &_getHooks($event, $mode, $event_key = null)
{
$hooks =& $this->getHooksByMode($mode);
$event_key = isset($event_key) ? $event_key : $event->getPrefixSpecial();
if (!isset($hooks[strtolower($event_key.'.'.$event->Name)])) {
$ret = Array ();
return $ret;
}
return $hooks[ strtolower($event_key.'.'.$event->Name) ];
}
}
\ No newline at end of file
Index: branches/5.2.x/core/kernel/managers/cache_manager.php
===================================================================
--- branches/5.2.x/core/kernel/managers/cache_manager.php (revision 15129)
+++ branches/5.2.x/core/kernel/managers/cache_manager.php (revision 15130)
@@ -1,813 +1,812 @@
<?php
/**
* @version $Id$
* @package In-Portal
* @copyright Copyright (C) 1997 - 2011 Intechnic. All rights reserved.
* @license GNU/GPL
* In-Portal is Open Source software.
* This means that this software may have been modified pursuant
* the GNU General Public License, and as distributed it includes
* or is derivative of works licensed under the GNU General Public License
* or other free or open source software licenses.
* See http://www.in-portal.org/license for copyright notices and details.
*/
defined('FULL_PATH') or die('restricted access!');
class kCacheManager extends kBase implements kiCacheable {
/**
* Used variables from SystemSettings table
*
* @var Array
* @access protected
*/
protected $configVariables = Array();
/**
* Used variables from SystemSettings table retrieved from unit cache
*
* @var Array
* @access protected
*/
protected $originalConfigVariables = Array ();
/**
* IDs of config variables used in current run (for caching)
*
* @var Array
* @access protected
*/
protected $configIDs = Array ();
/**
* IDs of config variables retrieved from unit cache
*
* @var Array
* @access protected
*/
protected $originalConfigIDs = Array ();
/**
* Object of memory caching class
*
* @var kCache
* @access protected
*/
protected $cacheHandler = null;
protected $temporaryCache = Array (
'registerAggregateTag' => Array (),
'registerScheduledTask' => Array (),
'registerHook' => Array (),
'registerBuildEvent' => Array (),
'registerAggregateTag' => Array (),
);
/**
* Name of database table, where configuration settings are stored
*
* @var string
* @access protected
*/
protected $settingTableName = '';
/**
* Set's references to kApplication and kDBConnection class instances
*
- * @param kApplication $application
* @access public
*/
- public function __construct($application = null)
+ public function __construct()
{
- parent::__construct($application);
+ parent::__construct();
$this->settingTableName = TABLE_PREFIX . 'SystemSettings';
if ( defined('IS_INSTALL') && IS_INSTALL ) {
// table substitution required, so "root" can perform login to upgrade to 5.2.0, where setting table was renamed
if ( !$this->Application->TableFound(TABLE_PREFIX . 'SystemSettings') ) {
$this->settingTableName = TABLE_PREFIX . 'ConfigurationValues';
}
}
}
/**
* Creates caching manager instance
*
* @access public
*/
public function InitCache()
{
$this->cacheHandler =& $this->Application->makeClass('kCache');
}
/**
* Returns cache key, used to cache phrase and configuration variable IDs used on current page
*
* @return string
* @access protected
*/
protected function getCacheKey()
{
// TODO: maybe language part isn't required, since same phrase from different languages have one ID now
return $this->Application->GetVar('t') . $this->Application->GetVar('m_theme') . $this->Application->GetVar('m_lang') . $this->Application->isAdmin;
}
/**
* Loads phrases and configuration variables, that were used on this template last time
*
* @access public
*/
public function LoadApplicationCache()
{
$phrase_ids = $config_ids = Array ();
$sql = 'SELECT PhraseList, ConfigVariables
FROM ' . TABLE_PREFIX . 'PhraseCache
WHERE Template = ' . $this->Conn->qstr( md5($this->getCacheKey()) );
$res = $this->Conn->GetRow($sql);
if ($res) {
if ( $res['PhraseList'] ) {
$phrase_ids = explode(',', $res['PhraseList']);
}
if ( $res['ConfigVariables'] ) {
$config_ids = array_diff( explode(',', $res['ConfigVariables']), $this->originalConfigIDs);
}
}
$this->Application->Phrases->Init('phrases', '', null, $phrase_ids);
$this->configIDs = $this->originalConfigIDs = $config_ids;
$this->InitConfig();
}
/**
* Updates phrases and configuration variables, that were used on this template
*
* @access public
*/
public function UpdateApplicationCache()
{
$update = false;
//something changed
$update = $update || $this->Application->Phrases->NeedsCacheUpdate();
$update = $update || (count($this->configIDs) && $this->configIDs != $this->originalConfigIDs);
if ($update) {
$fields_hash = Array (
'PhraseList' => implode(',', $this->Application->Phrases->Ids),
'CacheDate' => adodb_mktime(),
'Template' => md5( $this->getCacheKey() ),
'ConfigVariables' => implode(',', array_unique($this->configIDs)),
);
$this->Conn->doInsert($fields_hash, TABLE_PREFIX . 'PhraseCache', 'REPLACE');
}
}
/**
* Loads configuration variables, that were used on this template last time
*
* @access protected
*/
protected function InitConfig()
{
if (!$this->originalConfigIDs) {
return ;
}
$sql = 'SELECT VariableValue, VariableName
FROM ' . $this->settingTableName . '
WHERE VariableId IN (' . implode(',', $this->originalConfigIDs) . ')';
$config_variables = $this->Conn->GetCol($sql, 'VariableName');
$this->configVariables = array_merge($this->configVariables, $config_variables);
}
/**
* Returns configuration option value by name
*
* @param string $name
* @return string
* @access public
*/
public function ConfigValue($name)
{
$site_domain_override = Array (
'DefaultEmailSender' => 'AdminEmail',
'DefaultEmailRecipients' => 'DefaultEmailRecipients',
);
if ( isset($site_domain_override[$name]) ) {
$res = $this->Application->siteDomainField($site_domain_override[$name]);
if ( $res ) {
return $res;
}
}
if ( array_key_exists($name, $this->configVariables) ) {
return $this->configVariables[$name];
}
if ( defined('IS_INSTALL') && IS_INSTALL && !$this->Application->TableFound($this->settingTableName, true) ) {
return false;
}
$this->Conn->nextQueryCachable = true;
$sql = 'SELECT VariableId, VariableValue
FROM ' . $this->settingTableName . '
WHERE VariableName = ' . $this->Conn->qstr($name);
$res = $this->Conn->GetRow($sql);
if ( $res !== false ) {
$this->configIDs[] = $res['VariableId'];
$this->configVariables[$name] = $res['VariableValue'];
return $res['VariableValue'];
}
trigger_error('Usage of undefined configuration variable "<strong>' . $name . '</strong>"', E_USER_NOTICE);
return false;
}
/**
* Changes value of individual configuration variable (+resets cache, when needed)
*
* @param string $name
* @param string $value
* @param bool $local_cache_only
* @return string
* @access public
*/
public function SetConfigValue($name, $value, $local_cache_only = false)
{
$this->configVariables[$name] = $value;
if ( $local_cache_only ) {
return;
}
$fields_hash = Array ('VariableValue' => $value);
$this->Conn->doUpdate($fields_hash, $this->settingTableName, 'VariableName = ' . $this->Conn->qstr($name));
if ( array_key_exists($name, $this->originalConfigVariables) && $value != $this->originalConfigVariables[$name] ) {
$this->DeleteUnitCache();
}
}
/**
* Loads data, that was cached during unit config parsing
*
* @return bool
* @access public
*/
public function LoadUnitCache()
{
if ( $this->Application->isCachingType(CACHING_TYPE_MEMORY) ) {
$data = $this->Application->getCache('master:configs_parsed', false, CacheSettings::$unitCacheRebuildTime);
}
else {
$data = $this->Application->getDBCache('configs_parsed', CacheSettings::$unitCacheRebuildTime);
}
if ( $data ) {
$cache = unserialize($data); // 126 KB all modules
unset($data);
$this->Application->InitManagers();
$this->Application->setFromCache($cache);
$aggregator =& $this->Application->recallObject('TagsAggregator', 'kArray');
/* @var $aggregator kArray */
$aggregator->setFromCache($cache);
$this->setFromCache($cache);
unset($cache);
return true;
}
if ( $this->Application->isCachingType(CACHING_TYPE_MEMORY) ) {
$this->Application->rebuildCache('master:configs_parsed', kCache::REBUILD_NOW, CacheSettings::$unitCacheRebuildTime);
}
else {
$this->Application->rebuildDBCache('configs_parsed', kCache::REBUILD_NOW, CacheSettings::$unitCacheRebuildTime);
}
return false;
}
/**
* Empties factory and event manager cache (without storing changes)
*/
public function EmptyUnitCache()
{
// maybe discover keys automatically from corresponding classes
$cache_keys = Array (
- 'Factory.Files', 'Factory.realClasses', 'Factory.Dependencies',
+ 'Factory.Files', 'Factory.realClasses',
'ConfigReader.prefixFiles',
'EventManager.beforeHooks', 'EventManager.afterHooks', 'EventManager.scheduledTasks', 'EventManager.buildEvents',
'Application.ReplacementTemplates', 'Application.RewriteListeners', 'Application.ModuleInfo',
'Application.ConfigHash', 'Application.ConfigCacheIds',
);
$empty_cache = Array ();
foreach ($cache_keys as $cache_key) {
$empty_cache[$cache_key] = Array ();
}
$this->Application->setFromCache($empty_cache);
$this->setFromCache($empty_cache);
// otherwise ModulesHelper indirectly used from includeConfigFiles won't work
$this->Application->RegisterDefaultClasses();
}
/**
* Updates data, that was parsed from unit configs this time
*
* @access public
*/
public function UpdateUnitCache()
{
$aggregator =& $this->Application->recallObject('TagsAggregator', 'kArray');
/* @var $aggregator kArray */
$this->preloadConfigVars(); // preloading will put to cache
$cache = array_merge(
$this->Application->getToCache(),
$aggregator->getToCache(),
$this->getToCache()
);
$cache_rebuild_by = SERVER_NAME . ' (' . getenv('REMOTE_ADDR') . ') - ' . adodb_date('d/m/Y H:i:s');
if ($this->Application->isCachingType(CACHING_TYPE_MEMORY)) {
$this->Application->setCache('master:configs_parsed', serialize($cache));
$this->Application->setCache('master:last_cache_rebuild', $cache_rebuild_by);
}
else {
$this->Application->setDBCache('configs_parsed', serialize($cache));
$this->Application->setDBCache('last_cache_rebuild', $cache_rebuild_by);
}
}
public function delayUnitProcessing($method, $params)
{
if ($this->Application->InitDone) {
// init already done -> call immediately (happens during installation)
$function = Array (&$this->Application, $method);
call_user_func_array($function, $params);
return ;
}
$this->temporaryCache[$method][] = $params;
}
public function applyDelayedUnitProcessing()
{
foreach ($this->temporaryCache as $method => $method_calls) {
$function = Array (&$this->Application, $method);
foreach ($method_calls as $method_call) {
call_user_func_array($function, $method_call);
}
$this->temporaryCache[$method] = Array ();
}
}
/**
* Deletes all data, that was cached during unit config parsing (excluding unit config locations)
*
* @param Array $config_variables
* @access public
*/
public function DeleteUnitCache($config_variables = null)
{
if ( isset($config_variables) && !array_intersect(array_keys($this->originalConfigVariables), $config_variables) ) {
// prevent cache reset, when given config variables are not in unit cache
return;
}
if ( $this->Application->isCachingType(CACHING_TYPE_MEMORY) ) {
$this->Application->rebuildCache('master:configs_parsed', kCache::REBUILD_LATER, CacheSettings::$unitCacheRebuildTime);
}
else {
$this->Application->rebuildDBCache('configs_parsed', kCache::REBUILD_LATER, CacheSettings::$unitCacheRebuildTime);
}
}
/**
* Deletes cached section tree, used during permission checking and admin console tree display
*
* @return void
* @access public
*/
public function DeleteSectionCache()
{
if ( $this->Application->isCachingType(CACHING_TYPE_MEMORY) ) {
$this->Application->rebuildCache('master:sections_parsed', kCache::REBUILD_LATER, CacheSettings::$sectionsParsedRebuildTime);
}
else {
$this->Application->rebuildDBCache('sections_parsed', kCache::REBUILD_LATER, CacheSettings::$sectionsParsedRebuildTime);
}
}
/**
* Preloads 21 widely used configuration variables, so they will get to cache for sure
*
* @access protected
*/
protected function preloadConfigVars()
{
$config_vars = Array (
// session related
'SessionTimeout', 'SessionCookieName', 'SessionCookieDomains', 'SessionBrowserSignatureCheck',
'SessionIPAddressCheck', 'CookieSessions', 'KeepSessionOnBrowserClose', 'User_GuestGroup',
'User_LoggedInGroup', 'RegistrationUsernameRequired',
// output related
'UseModRewrite', 'UseContentLanguageNegotiation', 'UseOutputCompression', 'OutputCompressionLevel',
'Config_Site_Time', 'SystemTagCache', 'DefaultGridPerPage',
// tracking related
'UseChangeLog', 'UseVisitorTracking', 'ModRewriteUrlEnding', 'ForceModRewriteUrlEnding',
'RunScheduledTasksFromCron',
);
$escaped_config_vars = $this->Conn->qstrArray($config_vars);
$sql = 'SELECT VariableId, VariableName, VariableValue
FROM ' . $this->settingTableName . '
WHERE VariableName IN (' . implode(',', $escaped_config_vars) . ')';
$data = $this->Conn->Query($sql, 'VariableId');
foreach ($data as $variable_id => $variable_info) {
$this->configIDs[] = $variable_id;
$this->configVariables[ $variable_info['VariableName'] ] = $variable_info['VariableValue'];
}
}
/**
* Sets data from cache to object
*
* Used for cases, when ConfigValue is called before LoadApplicationCache method (e.g. session init, url engine init)
*
* @param Array $data
* @access public
*/
public function setFromCache(&$data)
{
$this->configVariables = $this->originalConfigVariables = $data['Application.ConfigHash'];
$this->configIDs = $this->originalConfigIDs = $data['Application.ConfigCacheIds'];
}
/**
* Gets object data for caching
* The following caches should be reset based on admin interaction (adjusting config, enabling modules etc)
*
* @access public
* @return Array
*/
public function getToCache()
{
return Array (
'Application.ConfigHash' => $this->configVariables,
'Application.ConfigCacheIds' => $this->configIDs,
// not in use, since it only represents template specific values, not global ones
// 'Application.Caches.ConfigVariables' => $this->originalConfigIDs,
);
}
/**
* Returns caching type (none, memory, temporary)
*
* @param int $caching_type
* @return bool
* @access public
*/
public function isCachingType($caching_type)
{
return $this->cacheHandler->getCachingType() == $caching_type;
}
/**
* Prints caching statistics
*
* @access public
*/
public function printStatistics()
{
$this->cacheHandler->printStatistics();
}
/**
* Returns cached $key value from cache named $cache_name
*
* @param int $key key name from cache
* @param bool $store_locally store data locally after retrieved
* @param int $max_rebuild_seconds
* @return mixed
* @access public
*/
public function getCache($key, $store_locally = true, $max_rebuild_seconds = 0)
{
return $this->cacheHandler->getCache($key, $store_locally, $max_rebuild_seconds);
}
/**
* Adds new value to cache $cache_name and identified by key $key
*
* @param int $key key name to add to cache
* @param mixed $value value of cached record
* @param int $expiration when value expires (0 - doesn't expire)
* @return bool
* @access public
*/
public function setCache($key, $value, $expiration = 0)
{
return $this->cacheHandler->setCache($key, $value, $expiration);
}
/**
* Sets rebuilding mode for given cache
*
* @param string $name
* @param int $mode
* @param int $max_rebuilding_time
* @return void
* @access public
*/
public function rebuildCache($name, $mode = null, $max_rebuilding_time = 0)
{
$this->cacheHandler->rebuildCache($name, $mode, $max_rebuilding_time);
}
/**
* Deletes key from cache
*
* @param string $key
* @return void
* @access public
*/
public function deleteCache($key)
{
$this->cacheHandler->delete($key);
}
/**
* Reset's all memory cache at once
*
* @return void
* @access public
*/
public function resetCache()
{
$this->cacheHandler->reset();
}
/**
* Returns value from database cache
*
* @param string $name key name
* @param int $max_rebuild_seconds
* @return mixed
* @access public
*/
public function getDBCache($name, $max_rebuild_seconds = 0)
{
// no serials in cache key OR cache is outdated
$wait_seconds = $max_rebuild_seconds;
while (true) {
$cached_data = $this->_getDBCache(Array ($name, $name . '_rebuilding', $name . '_rebuild'));
if ( $cached_data[$name . '_rebuild'] ) {
// cache rebuild requested -> rebuild now
$this->deleteDBCache($name . '_rebuild');
return false;
}
$cache = $cached_data[$name];
$rebuilding = $cached_data[$name . '_rebuilding'];
if ( ($cache === false) && (!$rebuilding || $wait_seconds == 0) ) {
// cache missing and nobody rebuilding it -> rebuild; enough waiting for cache to be ready
return false;
}
elseif ( $cache !== false ) {
// cache present -> return it
return $cache;
}
$wait_seconds -= kCache::WAIT_STEP;
sleep(kCache::WAIT_STEP);
}
return false;
}
/**
* Returns value from database cache
*
* @param string|Array $names key name
* @return mixed
* @access protected
*/
protected function _getDBCache($names)
{
$res = Array ();
$names = (array)$names;
$this->Conn->nextQueryCachable = true;
$sql = 'SELECT Data, Cached, LifeTime, VarName
FROM ' . TABLE_PREFIX . 'SystemCache
WHERE VarName IN (' . implode(',', $this->Conn->qstrArray($names)) . ')';
$cached_data = $this->Conn->Query($sql, 'VarName');
foreach ($names as $name) {
if ( !isset($cached_data[$name]) ) {
$res[$name] = false;
continue;
}
$lifetime = (int)$cached_data[$name]['LifeTime']; // in seconds
if ( ($lifetime > 0) && ($cached_data[$name]['Cached'] + $lifetime < adodb_mktime()) ) {
// delete expired
$this->Conn->nextQueryCachable = true;
$sql = 'DELETE FROM ' . TABLE_PREFIX . 'SystemCache
WHERE VarName = ' . $this->Conn->qstr($name);
$this->Conn->Query($sql);
$res[$name] = false;
continue;
}
$res[$name] = $cached_data[$name]['Data'];
}
return count($res) == 1 ? array_pop($res) : $res;
}
/**
* Sets value to database cache
*
* @param string $name
* @param mixed $value
* @param int|bool $expiration
* @return void
* @access public
*/
public function setDBCache($name, $value, $expiration = false)
{
$this->deleteDBCache($name . '_rebuilding');
$this->_setDBCache($name, $value, $expiration);
}
/**
* Sets value to database cache
*
* @param string $name
* @param mixed $value
* @param int|bool $expiration
* @access protected
*/
protected function _setDBCache($name, $value, $expiration = false)
{
if ((int)$expiration <= 0) {
$expiration = -1;
}
$fields_hash = Array (
'VarName' => $name,
'Data' => &$value,
'Cached' => adodb_mktime(),
'LifeTime' => (int)$expiration,
);
$this->Conn->nextQueryCachable = true;
$this->Conn->doInsert($fields_hash, TABLE_PREFIX . 'SystemCache', 'REPLACE');
}
/**
* Sets rebuilding mode for given cache
*
* @param string $name
* @param int $mode
* @param int $max_rebuilding_time
* @return void
* @access public
*/
public function rebuildDBCache($name, $mode = null, $max_rebuilding_time = 0)
{
if ( !isset($mode) || $mode == kCache::REBUILD_NOW ) {
$this->_setDBCache($name . '_rebuilding', 1, $max_rebuilding_time);
$this->deleteDBCache($name . '_rebuild');
}
elseif ( $mode == kCache::REBUILD_LATER ) {
$this->_setDBCache($name . '_rebuild', 1, 0);
$this->deleteDBCache($name . '_rebuilding');
}
}
/**
* Deletes key from database cache
*
* @param string $name
* @return void
* @access public
*/
public function deleteDBCache($name)
{
$sql = 'DELETE FROM ' . TABLE_PREFIX . 'SystemCache
WHERE VarName = ' . $this->Conn->qstr($name);
$this->Conn->Query($sql);
}
/**
* Increments serial based on prefix and it's ID (optional)
*
* @param string $prefix
* @param int $id ID (value of IDField) or ForeignKeyField:ID
* @param bool $increment
* @return string
* @access public
*/
public function incrementCacheSerial($prefix, $id = null, $increment = true)
{
$pascal_case_prefix = implode('', array_map('ucfirst', explode('-', $prefix)));
$serial_name = $pascal_case_prefix . (isset($id) ? 'IDSerial:' . $id : 'Serial');
if ($increment) {
if (defined('DEBUG_MODE') && DEBUG_MODE && $this->Application->isDebugMode()) {
$this->Application->Debugger->appendHTML('Incrementing serial: <strong>' . $serial_name . '</strong>.');
}
$this->setCache($serial_name, (int)$this->getCache($serial_name) + 1);
if (!defined('IS_INSTALL') || !IS_INSTALL) {
// delete cached mod-rewrite urls related to given prefix and id
$delete_clause = isset($id) ? $prefix . ':' . $id : $prefix;
$sql = 'DELETE FROM ' . TABLE_PREFIX . 'CachedUrls
WHERE Prefixes LIKE ' . $this->Conn->qstr('%|' . $delete_clause . '|%');
$this->Conn->Query($sql);
}
}
return $serial_name;
}
/**
* Returns cached category informaton by given cache name. All given category
* information is recached, when at least one of 4 caches is missing.
*
* @param int $category_id
* @param string $name cache name = {filenames, category_designs, category_tree}
* @return string
* @access public
*/
public function getCategoryCache($category_id, $name)
{
$serial_name = '[%CIDSerial:' . $category_id . '%]';
$cache_key = $name . $serial_name;
$ret = $this->getCache($cache_key);
if ($ret === false) {
if (!$category_id) {
// don't query database for "Home" category (ID = 0), because it doesn't exist in database
return false;
}
// this allows to save 2 sql queries for each category
$this->Conn->nextQueryCachable = true;
$sql = 'SELECT NamedParentPath, CachedTemplate, TreeLeft, TreeRight
FROM ' . TABLE_PREFIX . 'Categories
WHERE CategoryId = ' . (int)$category_id;
$category_data = $this->Conn->GetRow($sql);
if ($category_data !== false) {
// only direct links to category pages work (symlinks, container pages and so on won't work)
$this->setCache('filenames' . $serial_name, $category_data['NamedParentPath']);
$this->setCache('category_designs' . $serial_name, ltrim($category_data['CachedTemplate'], '/'));
$this->setCache('category_tree' . $serial_name, $category_data['TreeLeft'] . ';' . $category_data['TreeRight']);
}
}
return $this->getCache($cache_key);
}
}
\ No newline at end of file
Index: branches/5.2.x/core/kernel/managers/request_manager.php
===================================================================
--- branches/5.2.x/core/kernel/managers/request_manager.php (revision 15129)
+++ branches/5.2.x/core/kernel/managers/request_manager.php (revision 15130)
@@ -1,483 +1,483 @@
<?php
/**
* @version $Id$
* @package In-Portal
* @copyright Copyright (C) 1997 - 2010 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 kRequestManager extends kBase {
/**
* Prevents request from being proceeded twice
*
* @var bool
* @access protected
*/
protected $processed = false;
/**
* Processes request
*
* @access public
*/
public function process()
{
if ( $this->processed ) {
return;
}
$this->dumpRequest();
$this->processOpener();
$events = $this->getEvents();
$all_passed = $this->getAllPassed($events);
// set "all_passed" before kApplication::GetTopmostPrefix method call !
$this->Application->SetVar('all_passed', implode(',', $all_passed));
foreach ($events as $prefix_special => $event_name) {
$event =& $this->runEvent($prefix_special, $event_name);
if ( $event->status == kEvent::erSTOP ) {
// event requested to stop processing at this point
kUtil::safeDefine('DBG_SKIP_REPORTING', 1);
$this->Application->Session->SaveData();
exit;
}
if ( $event->status == kEvent::erPERM_FAIL ) {
$this->processPermissionError($event);
}
if ( ($event->status == kEvent::erSUCCESS || $event->status == kEvent::erPERM_FAIL) && $this->canRedirect($event) ) {
$this->performRedirect($event);
}
}
$this->Application->SetVar('events', $events);
$this->Application->SetVar('passed', implode(',', $all_passed));
$this->processed = true;
}
/**
* Dumps user request to debugger (only when enabled)
*
* @return void
* @access protected
*/
protected function dumpRequest()
{
if ( defined('DEBUG_MODE') && $this->Application->isDebugMode() && kUtil::constOn('DBG_SHOW_HTTPQUERY') ) {
$this->Application->Debugger->appendHTML('HTTPQuery:');
$this->Application->Debugger->dumpVars($this->Application->HttpQuery->_Params);
}
}
/**
* Returns event names, given in request (post, get)
*
* @return Array
* @access protected
*/
protected function getEvents()
{
$post_events = $this->getEventsFromPost();
return $post_events ? $post_events : $this->getEventsFromGet();
}
/**
* Get all passed prefixes
*
* @param Array $events
* @return Array
* @access protected
*/
protected function getAllPassed($events)
{
$ret = explode(',', $this->Application->GetVar('passed'));
foreach ($events as $prefix_special => $event_name) {
if (!$event_name) {
continue;
}
if ($this->Application->isAdmin) {
array_push($ret, $prefix_special);
}
else {
// don't add special on Front-end because of category item list special is autogenerated
$prefix_special = explode('.', $prefix_special);
array_push($ret, $prefix_special[0]);
}
}
return $ret;
}
/**
* Creates and runs event. Returns false, when prefix of given event isn't registered
*
* @param string $prefix_special
* @param string $event_name
*
* @return kEvent|false
* @access protected
*/
protected function &runEvent($prefix_special, $event_name)
{
$event = new kEvent($prefix_special . ':' . $event_name);
if ( preg_match('/(.*?)-(.*)/', $event->Prefix, $regs) && $this->Application->prefixRegistred($regs[1]) ) {
// this is event from cloned config -> load parent config to create valid clone
$this->Application->UnitConfigReader->loadConfig($regs[1]);
$this->Application->UnitConfigReader->runAfterConfigRead($regs[1]);
}
if ( !$this->Application->EventManager->verifyEventPrefix($event, true) ) {
$false = false;
return $false;
}
$event->SetRedirectParam('opener', 's'); // stay on same page after event is called
$event->setEventParam('top_prefix', $this->Application->GetTopmostPrefix($event->Prefix, true));
$event_handler =& $this->Application->recallObject($event->Prefix . '_EventHandler');
/* @var $event_handler kEventHandler */
if ( ($this->Application->RecallVar('user_id') == USER_ROOT) || $event_handler->CheckPermission($event) ) {
$this->Application->HandleEvent($event);
}
return $event;
}
/**
* Processes case, when event finished with permission error
*
* @param kEvent $event
* @access protected
*/
- protected function processPermissionError(&$event)
+ protected function processPermissionError($event)
{
// should do redirect but to no_permissions template
$event->redirect = $this->Application->isAdmin ? 'no_permission' : $this->Application->ConfigValue('NoPermissionTemplate');
$event->SetRedirectParam('pass', 'm');
$themes_helper =& $this->Application->recallObject('ThemesHelper');
/* @var $themes_helper kThemesHelper */
$event->SetRedirectParam( 'm_cat_id', $themes_helper->getPageByTemplate($event->redirect) );
// restore stuff, that processOpener() changed
$wid = $this->Application->GetVar('m_wid');
$this->Application->RestoreVar( rtrim('opener_stack_' . $wid, '_') );
// don't save last_template, because no_permission template does js history.back and could cause invalid opener_stack content
$this->Application->SetVar('skip_last_template', 1);
}
/**
* Performs redirect after event execution
*
* @param kEvent $event
* @access protected
*/
- protected function performRedirect(&$event)
+ protected function performRedirect($event)
{
// we need to pass category if the action was submitted to self-template, with the category passed
// and it has not explicitly set redirect template or pass_category param
if ( $this->samePageRedirect($event) && ($event->getEventParam('pass_category') === false) && $this->Application->GetVar('m_cat_id') ) {
$event->SetRedirectParam('pass_category', 1);
}
$wid = $this->Application->GetVar('m_wid');
$redirect_params = $event->getRedirectParams();
if ( $wid && $event->getRedirectParam('opener') == 'u' ) {
// update last element in current opener stack
unset($redirect_params['opener']);
$redirect_template = is_string($event->redirect) ? $event->redirect : null;
$this->openerStackChange($redirect_template, $redirect_params);
// reset opener, because kApplication::HREF will react differently when 'opener' => 'u'
$event->SetRedirectParam('opener', 's');
$event->redirect = defined('CLOSE_POPUP_TPL') ? CLOSE_POPUP_TPL : 'incs/close_popup';
}
if ( $event->getRedirectParam('pass') === false ) {
// pass all discovered units to redirected page unless developer decided otherwise
$event->SetRedirectParam('pass', 'all');
}
$this->Application->Redirect($event->redirect, $event->getRedirectParams(), '', $event->redirectScript);
}
/**
* Checks, if redirect can be made
*
* @param kEvent $event
* @return bool
* @access protected
*/
- protected function canRedirect(&$event)
+ protected function canRedirect($event)
{
return $this->samePageRedirect($event) || strlen($event->redirect) > 0;
}
/**
* Checks, that current template will be displayed after redirect
*
* @param kEvent $event
* @return bool
* @access protected
*/
- protected function samePageRedirect(&$event)
+ protected function samePageRedirect($event)
{
return $event->redirect === true || $event->redirect == $this->Application->GetVar('t');
}
/**
* Returns event names given in GET
*
* @return Array
* @access protected
*/
protected function getEventsFromGet()
{
$events = Array ();
$discovered_units = $this->Application->HttpQuery->getDiscoveredUnits(false);
foreach ($discovered_units as $prefix_special => $query_string) {
$query_string = array_flip($query_string);
if ( !isset($query_string['event']) ) {
continue;
}
$event_name = $this->Application->GetVar($prefix_special . '_event');
// we need to check for pre 5.1.0 url format, because of "PerPage"
// query string part (that was added in place of "event" query
// string part) is available only since 5.1.0 version
if ($event_name && !is_numeric($event_name)) {
$events[$prefix_special] = $event_name;
}
}
return $events;
}
/**
* Returns event names given in POST
*
* @return Array
* @access protected
*/
protected function getEventsFromPost()
{
$ret = Array ();
$events = $this->Application->GetVar('events');
if (!$events) {
return Array ();
}
foreach ($events as $prefix_special => $event_name) {
if (!$event_name) {
continue;
}
if ( is_array($event_name) ) {
// HTML-input names like "events[prefix.special][event_name]", input value don't matter
$event_name = key($event_name);
$this->Application->SetVar($prefix_special . '_event', $event_name);
}
// HTML-input names like "events[prefix.special]", input value is event name
$ret[$prefix_special] = $event_name;
}
return $ret;
}
/**
* Processes window opener stack
*
* @access protected
*/
protected function processOpener()
{
$opener_stack =& $this->Application->makeClass('kOpenerStack');
/* @var $opener_stack kOpenerStack */
switch ( $this->Application->GetVar('m_opener') ) {
case 'r':
$opener_stack->reset();
break;
case 'd':
// "down/push" new template to opener stack, deeplevel++
if ( $this->Application->GetVar('front') ) {
$front_session =& $this->Application->recallObject('Session.front');
/* @var $front_session Session */
$opener_stack->pushRaw( '../' . $front_session->RecallVar('last_template') );
}
else {
$opener_stack->pushRaw( $this->Application->RecallVar('last_template') );
}
break;
case 'u':
// "up/pop" last template from opener stack, deeplevel--
$opener_stack->pop();
break;
case 'p':
// pop-up - generate new wid
$parent_wid = $this->Application->GetVar('m_wid'); // window_id of popup's parent window
$popup_wid = (int)$this->Application->RecallVar('last_wid') + 1;
$this->Application->StoreVar('last_wid', $popup_wid);
$this->Application->SetVar('m_wid', $popup_wid);
$popup_opener_stack =& $this->Application->makeClass('kOpenerStack', Array ($popup_wid));
/* @var $popup_opener_stack kOpenerStack */
$popup_opener_stack->pushRaw( $this->getLastTemplate($parent_wid) );
$popup_opener_stack->save();
$this->Application->SetVar('m_opener', 's');
/*// store window relations
$window_relations = $this->Application->RecallVar('window_relations');
$window_relations = $window_relations ? unserialize($window_relations) : Array ();
$window_relations[$popup_wid] = $parent_wid;
$this->Application->StoreVar('window_relations', serialize($window_relations));*/
return;
break;
default:
// "s/0," stay on same deep level
break;
}
$this->Application->SetVar('m_opener', 's');
$opener_stack->save();
}
/**
* Returns last template from window with given id
*
* @param int $window_id
* @return string
* @access protected
*/
protected function getLastTemplate($window_id)
{
if ( $this->Application->GetVar('front') ) {
$front_session =& $this->Application->recallObject('Session.front');
/* @var $front_session Session */
return '../' . $front_session->RecallVar( rtrim('last_template_popup_' . $window_id, '_') );
}
if ( $this->Application->GetVar('merge_opener_stack') ) {
// get last template from parent (that was closed) window opener stack
$parent_opener_stack =& $this->Application->makeClass('kOpenerStack', Array ($window_id));
/* @var $parent_opener_stack kOpenerStack */
$last_template = $parent_opener_stack->pop(true);
$parent_opener_stack->save(true);
}
else {
$last_template = $this->Application->RecallVar( rtrim('last_template_popup_' . $window_id, '_') );
}
return $last_template;
}
/**
* Allows to add new element to opener stack
*
* @param string $template
* @param Array $params
* @param int $wid
* @access public
*/
public function openerStackPush($template = '', $params = Array (), $wid = null)
{
if ( !isset($params['pass']) ) {
$params['pass'] = 'all';
}
/*// get parent window wid, when this was popup
$window_relations = $this->Application->RecallVar('window_relations');
$window_relations = $window_relations ? unserialize($window_relations) : Array ();
$wid = isset($window_relations[$wid]) ? $window_relations[$wid] : false;*/
$opener_stack =& $this->Application->makeClass('kOpenerStack', Array ($wid));
/* @var $opener_stack kOpenerStack */
// change opener stack
$default_params = Array ('m_opener' => 'u', '__URLENCODE__' => 1);
if ( !$this->Application->ConfigValue('UsePopups') && $opener_stack->getWindowID() ) {
// remove wid to show combined header block in editing window
$default_params['m_wid'] = '';
list ($last_template, $last_params, ) = $opener_stack->get(kOpenerStack::LAST_ELEMENT);
// move last popup's opener stack element to main window's opener stack
if ( $last_params ) {
$last_params = array_merge($last_params, $default_params);
$this->openerStackPush($last_template, $last_params, '');
}
}
$params = array_merge($default_params, $params);
$opener_stack->push($template, $params, 'index.php');
$opener_stack->save();
}
/**
* Allows to change last element in opener stack
*
* @param string $new_template
* @param Array $new_params
* @access protected
*/
protected function openerStackChange($new_template = null, $new_params = null)
{
$opener_stack =& $this->Application->makeClass('kOpenerStack');
/* @var $opener_stack kOpenerStack */
list ($template, $params, $index_file) = $opener_stack->pop();
if ( isset($new_template) ) {
$template = $new_template;
}
if ( isset($new_params) ) {
$params = array_merge($params, $new_params);
}
if ( !isset($params['pass_events']) ) {
// don't pass events, unless requested
$params['pass_events'] = false;
}
$opener_stack->push($template, $params, $index_file);
$opener_stack->save();
}
}
\ No newline at end of file
Index: branches/5.2.x/core/kernel/event_manager.php
===================================================================
--- branches/5.2.x/core/kernel/event_manager.php (revision 15129)
+++ branches/5.2.x/core/kernel/event_manager.php (revision 15130)
@@ -1,353 +1,353 @@
<?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 kEventManager extends kBase implements kiCacheable {
/**
* Instance of hook manager
*
* @var kHookManager
* @access protected
*/
protected $Hooks = null;
/**
* Instance of scheduled task manager
*
* @var kScheduledTaskManager
* @access protected
*/
protected $ScheduledTasks = null;
/**
* Instance of request manager
*
* @var kRequestManager
* @access protected
*/
protected $Request = null;
/**
* Build events registred for pseudo classes.
* key - pseudo class, value - event name
*
* @var Array
* @access protected
*/
protected $buildEvents = Array ();
/**
* Event recursion tracking stack
*
* @var Array
* @access protected
*/
protected $recursionStack = Array ();
/**
* Creates new instance of kEventManager class
*
*/
public function __construct()
{
parent::__construct();
$this->Hooks =& $this->Application->makeClass('kHookManager');
$this->ScheduledTasks =& $this->Application->makeClass('kScheduledTaskManager');
$this->Request =& $this->Application->makeClass('kRequestManager');
}
/**
* Sets data from cache to object
*
* @param Array $data
* @access public
*/
public function setFromCache(&$data)
{
$this->Hooks->setFromCache($data);
$this->ScheduledTasks->setFromCache($data);
$this->buildEvents = $data['EventManager.buildEvents'];
}
/**
* Gets object data for caching
*
* @return Array
* @access public
*/
public function getToCache()
{
return array_merge(
$this->Hooks->getToCache(),
$this->ScheduledTasks->getToCache(),
Array (
'EventManager.buildEvents' => $this->buildEvents,
)
);
}
/**
* Returns information about registered scheduled tasks
*
* @param bool $from_cache
* @return Array
* @access public
*/
public function getScheduledTasks($from_cache = false)
{
return $this->ScheduledTasks->getAll($from_cache);
}
/**
* Add new scheduled task
*
* @param string $short_name name to be used to store last maintenance run info
* @param string $event_string
* @param int $run_interval run interval in seconds
* @param int $status
* @access public
*/
public function registerScheduledTask($short_name, $event_string, $run_interval, $status = STATUS_ACTIVE)
{
$this->ScheduledTasks->add($short_name, $event_string, $run_interval, $status);
}
/**
* Run registered scheduled tasks with specified event type
*
* @param bool $from_cron
* @access public
*/
public function runScheduledTasks($from_cron = false)
{
$this->ScheduledTasks->runAll($from_cron);
}
/**
* Runs scheduled task based on given data
*
* @param Array $scheduled_task_data
* @return bool
* @access public
*/
public function runScheduledTask($scheduled_task_data)
{
return $this->ScheduledTasks->run($scheduled_task_data);
}
/**
* Registers Hook from sub-prefix event to master prefix event
*
* Pattern: Observer
*
* @param string $hook_event
* @param string $do_event
* @param int $mode
* @param bool $conditional
* @access public
*/
public function registerHook($hook_event, $do_event, $mode = hAFTER, $conditional = false)
{
$this->Hooks->registerHook($hook_event, $do_event, $mode, $conditional);
}
/**
* Registers build event for given pseudo class
*
* @param string $pseudo_class
* @param string $event_name
* @access public
*/
public function registerBuildEvent($pseudo_class, $event_name)
{
$this->buildEvents[$pseudo_class] = $event_name;
}
/**
* Runs build event for given $pseudo_class instance, when defined
*
* @param string $prefix_special
* @param string $pseudo_class
* @param Array $event_params
* @access public
*/
public function runBuildEvent($prefix_special, $pseudo_class, $event_params)
{
if ( !isset($this->buildEvents[$pseudo_class]) ) {
return ;
}
$event = new kEvent($prefix_special . ':' . $this->buildEvents[$pseudo_class], $event_params);
$this->HandleEvent($event);
}
/**
* Check if event is called twice, that causes recursion
*
* @param kEvent $event
* @return bool
* @access protected
*/
- protected function isRecursion(&$event)
+ protected function isRecursion($event)
{
$event_key = $event->getPrefixSpecial() . ':' . $event->Name;
return in_array($event_key, $this->recursionStack);
}
/**
* Adds event to recursion stack
*
* @param kEvent $event
* @access protected
*/
- protected function pushEvent(&$event)
+ protected function pushEvent($event)
{
$event_key = $event->getPrefixSpecial() . ':' . $event->Name;
array_push($this->recursionStack, $event_key);
}
/**
* Removes event from recursion stack
*
* @access protected
*/
protected function popEvent()
{
array_pop($this->recursionStack);
}
/**
* Allows to process any type of event
*
* @param kEvent $event
* @access public
*/
- public function HandleEvent(&$event)
+ public function HandleEvent($event)
{
if ( $this->isRecursion($event) || !$this->verifyEventPrefix($event) ) {
return;
}
$this->pushEvent($event);
if ( !$event->SkipBeforeHooks ) {
$this->Hooks->runHooks($event, hBEFORE);
if ( $event->status == kEvent::erFATAL ) {
return;
}
}
$event_handler =& $this->Application->recallObject($event->Prefix . '_EventHandler');
/* @var $event_handler kEventHandler */
$event_handler->processEvent($event);
if ( $event->status == kEvent::erFATAL ) {
return;
}
if ( !$event->SkipAfterHooks ) {
$this->Hooks->runHooks($event, hAFTER);
}
$this->popEvent();
}
/**
* Checks if event prefix is valid
*
* @param kEvent $event
* @param bool $is_fatal
* @return string
* @access public
*/
- public function verifyEventPrefix(&$event, $is_fatal = false)
+ public function verifyEventPrefix($event, $is_fatal = false)
{
if ( !$this->Application->prefixRegistred($event->Prefix) ) {
$this->Application->UnitConfigReader->loadConfig($event->Prefix);
if ( !$this->Application->prefixRegistred($event->Prefix) ) {
$error_msg = 'Prefix <strong>' . $event->Prefix . '</strong> not registred (requested event <strong>' . $event->Name . '</strong>)';
if ($is_fatal) {
throw new Exception($error_msg);
}
else {
trigger_error($error_msg, E_USER_WARNING);
}
return false;
}
}
return true;
}
/**
* Processes request
*
* @access public
*/
public function ProcessRequest()
{
$this->Request->process();
}
/**
* Allows to add new element to opener stack
*
* @param string $template
* @param Array $params
* @access public
*/
public function openerStackPush($template = '', $params = Array ())
{
$this->Request->openerStackPush($template, $params);
}
/**
* Set's new event for $prefix_special
* passed
*
* @param string $prefix_special
* @param string $event_name
* @access public
*/
public function setEvent($prefix_special,$event_name)
{
$actions =& $this->Application->recallObject('kActions');
/* @var $actions Params */
$actions->Set('events[' . $prefix_special . ']', $event_name);
}
/**
* Allows to determine, that required event is beeing processed right now
*
* @param string $event_key Event name in format prefix[.special]:event_name
* @return bool
* @access public
*/
public function eventRunning($event_key)
{
return array_search($event_key, $this->recursionStack) !== false;
}
}
\ No newline at end of file
Index: branches/5.2.x/core/kernel/utility/debugger/debugger.js
===================================================================
--- branches/5.2.x/core/kernel/utility/debugger/debugger.js (revision 15129)
+++ branches/5.2.x/core/kernel/utility/debugger/debugger.js (revision 15130)
@@ -1,518 +1,530 @@
function DebugReq() {}
DebugReq.timeout = 5 * 60 * 1000; // 5 minutes
DebugReq.makeRequest = function(p_url, p_busyReq, p_progId, p_successCallBack, p_errorCallBack, p_pass, p_object) {
//p_url: the web service url
//p_busyReq: is a request for this object currently in progress?
//p_progId: element id where progress HTML should be shown
//p_successCallBack: callback function for successful response
//p_errorCallBack: callback function for erroneous response
//p_pass: string of params to pass to callback functions
//p_object: object of params to pass to callback functions
if (p_busyReq) {
return;
}
var req = DebugReq.getRequest();
if (req != null) {
p_busyReq = true;
DebugReq.showProgress(p_progId);
req.onreadystatechange = function() {
if (req.readyState == 4) {
p_busyReq = false;
window.clearTimeout(toId);
if (req.status == 200) {
p_successCallBack(req,p_pass,p_object);
} else {
p_errorCallBack(req,p_pass,p_object);
}
}
}
var $ajax_mark = (p_url.indexOf('?') ? '&' : '?') + 'ajax=yes';
req.open('GET', p_url + $ajax_mark, true);
req.setRequestHeader('If-Modified-Since', 'Sat, 1 Jan 2000 00:00:00 GMT');
req.send(null);
var toId = window.setTimeout( function() {if (p_busyReq) req.abort();}, DebugReq.timeout );
}
}
DebugReq.getRequest = function() {
var xmlHttp;
try { xmlHttp = new ActiveXObject('MSXML2.XMLHTTP'); return xmlHttp; } catch (e) {}
try { xmlHttp = new ActiveXObject('Microsoft.XMLHTTP'); return xmlHttp; } catch (e) {}
try { xmlHttp = new XMLHttpRequest(); return xmlHttp; } catch(e) {}
return null;
}
DebugReq.showProgress = function(p_id) {
$Debugger.AppendRow(DebugReq.getProgressHtml());
}
DebugReq.getProgressHtml = function() {
return 'Loading ...';
}
DebugReq.getErrorHtml = function(p_req) {
//TODO: implement accepted way to handle request error
return "<p>" + "(" + p_req.status + ") " + p_req.statusText + "</p>"
}
// Debugger
-function Debugger($row_separator, $errors_count, $fatal_error, $sql_count) {
- this.RowSeparator = $row_separator;
- this.IsFatalError = $fatal_error;
- this.ErrorsCount = parseInt($errors_count);
- this.SQLCount = parseInt($sql_count);
+function Debugger($params) {
+ this.RowSeparator = '';
+ this.IsFatalError = false;
+ this.ErrorsCount = 0;
+ this.SQLCount = 0;
+ this.SQLTime = 0;
+ this.ScriptTime = 0;
+ this.ScriptMemory = 0;
+
+ for (var $param_name in $params) {
+ this[$param_name] = $params[$param_name];
+ }
+
this.IsQueried = false;
this.IsVisible = false;
this.DebuggerDIV = document.getElementById('debug_layer');
this.DebuggerTable = document.getElementById('debug_table');
this.RowCount = 0;
this.busyRequest = false;
this.DragObject = null;
this.LastDragObject = null;
this.MouseOffset = [0,0];
this.ResizeHappening = false;
this.ResizeTimer = null;
this.InitialPos = null;
// window.$Debugger = this; // this should be uncommented in case if debugger variable is not $Debugger
this.AddEvent(window, 'scroll', function (ev) { window.$Debugger.Resize(ev); });
this.AddEvent(window, 'resize', function (ev) { window.$Debugger.Resize(ev); });
this.AddEvent(document, 'keydown', function (ev) { window.$Debugger.KeyDown(ev); }); // don't work in IE
}
Debugger.prototype.createEnvironment = function($outer_width, $inner_width) {
if (!this.DebuggerDIV) {
// when debugger wasn't added already
var $container = document.createElement('DIV');
$container.id = 'debug_layer';
$container.className = 'debug_layer_container';
$container.style.display = 'none';
$container.style.width = $outer_width + 'px';
var $debug_layer = document.createElement('DIV');
$debug_layer.className = 'debug_layer';
$debug_layer.style.width = $inner_width + 'px';
$container.insertBefore($debug_layer, $container.firstChild);
var $table = document.createElement('TABLE');
$table.style.width = '100%';
$table.className = 'debug_layer_table';
$table.style.width = $inner_width + 'px';
$debug_layer.insertBefore($table, $debug_layer.firstChild);
var $tbody = document.createElement('TBODY');
$tbody.id = 'debug_table';
$table.insertBefore($tbody, $table.firstChild);
var $body = document.getElementsByTagName('BODY')[0];
$body.insertBefore($container, $body.lastChild);
this.DebuggerDIV = document.getElementById('debug_layer');
this.DebuggerTable = document.getElementById('debug_table');
}
else {
this.Clear();
}
}
Debugger.prototype.SetOpacity = function(opacity)
{
this.DebuggerToolbar.style.opacity = (opacity / 100);
this.DebuggerToolbar.style.MozOpacity = (opacity / 100);
this.DebuggerToolbar.style.KhtmlOpacity = (opacity / 100);
this.DebuggerToolbar.style.filter = "alpha(opacity=" + opacity + ")";
}
Debugger.prototype.ToolbarClick = function ($button) {
switch ($button.id) {
case 'dbg_ReloadFrame':
self.location.reload();
break;
case 'dbg_ShowDebugger':
this.Toggle();
break;
case 'dbg_TurnOff':
var $exdate = new Date();
$exdate.setDate( $exdate.getDate() + 365 );
document.cookie = 'debug_off=1; expires=' + $exdate.toUTCString() + '; path=' + this.BasePath + '/';
self.location.reload();
break;
}
}
Debugger.prototype.jQueryFound = function () {
return typeof jQuery == 'function';
}
Debugger.prototype.AddToolbar = function($var_name) {
if (document.getElementById('debug_toolbar_span')) {
// toolbar was already created before
if (this.jQueryFound()) {
$('#debug_toolbar_span').remove();
}
else {
return ;
}
}
var $span = document.createElement('SPAN');
$span.style.position = 'absolute';
$span.style.zIndex= 99;
$span.style.top = '0px';
$span.style.left = '0px';
$span.id = 'debug_toolbar_span';
document.body.style.textAlign = 'left';
var $toolbar_content = '<td class="dbg-button" id="dbg_ReloadFrame" onclick="' + $var_name + '.ToolbarClick(this);">Reload Frame</td>';
if (this.ErrorsCount > 0) {
$toolbar_content += '<td class="dbg-separator"></td><td class="dbg-button debug_error" style="font-weight: bold;" id="dbg_ShowDebugger" onclick="' + $var_name + '.ToolbarClick(this);">Show Debugger (' + this.ErrorsCount + ' errors)</td>';
}
else {
$toolbar_content += '<td class="dbg-button" id="dbg_ShowDebugger" onclick="' + $var_name + '.ToolbarClick(this);">Show Debugger</td>';
}
$toolbar_content += '<td class="dbg-button" id="dbg_TurnOff" onclick="' + $var_name + '.ToolbarClick(this);">Turn Off</td>';
if (this.SQLCount > 0) {
- $toolbar_content += '<td class="dbg-separator"></td><td style="cursor: move">' + this.SQLCount + ' sqls</td>';
+ $toolbar_content += '<td class="dbg-separator"></td><td style="cursor: move"><strong>' + this.SQLCount + '</strong> sqls (' + this.SQLTime + ' s)</td>';
+ }
+
+ if (this.ScriptTime > 0) {
+ $toolbar_content += '<td class="dbg-separator"></td><td style="cursor: move">' + this.ScriptTime + ' s (' + this.ScriptMemory + ')</td>';
}
$span.innerHTML = '<table style="height: 30px" cellpadding="0" cellspacing="3" class="dbg-toolbar"><tr>' + $toolbar_content + '</tr></table>';
this.DebuggerToolbar = $span;
this.SetOpacity(20);
$span.onmouseover = function() {
$Debugger.SetOpacity(100);
}
$span.onmouseout = function() {
$Debugger.SetOpacity(20);
}
var $body = document.getElementsByTagName('BODY')[0];
$body.insertBefore($span, $body.firstChild);
// alert($span.offsetWidth)
this.MakeDragable('debug_toolbar_span', function() {}, function() {}, function() {});
}
Debugger.prototype.AppendRow = function($html) {
this.RowCount++;
var $tr = document.createElement('TR');
this.DebuggerTable.appendChild($tr);
$tr.className = 'debug_row_' + (this.RowCount % 2 ? 'odd' : 'even');
$tr.id = 'debug_row_' + this.RowCount;
var $td = document.createElement('TD');
$td.className = 'debug_cell';
$td.innerHTML = $html;
$tr.appendChild($td);
}
Debugger.prototype.RemoveRow = function($row_index) {
this.DebuggerTable.deleteRow($row_index);
this.RowCount--;
}
Debugger.prototype.Clear = function() {
if (!this.IsQueried) return false;
while (this.DebuggerTable.rows.length) {
this.RemoveRow(0);
}
this.Toggle(27);
this.IsQueried = false;
}
Debugger.prototype.KeyDown = function($e) {
var $KeyCode = this.GetKeyCode($e);
if ($KeyCode == 123 || $KeyCode == 27) {// F12 or ESC
this.Toggle($KeyCode);
this.StopEvent($e);
}
}
Debugger.prototype.OpenDOMViewer = function() {
var $value = document.getElementById('dbg_domviewer').value;
DOMViewerObj = ($value.indexOf('"') != -1) ? document.getElementById( $value.substring(1,$value.length-1) ) : eval($value);
window.open(this.DOMViewerURL);
return false;
}
Debugger.prototype.GetKeyCode = function($e) {
$e = ($e) ? $e : event;
var target = ($e.target) ? $e.target : $e.scrElement;
var charCode = ($e.charCode) ? $e.charCode : (($e.which) ? $e.which : $e.keyCode);
return charCode;
}
Debugger.prototype.StopEvent = function($e) {
$e = ($e) ? $e : event;
$e.cancelBubble = true;
if ($e.stopPropagation) $e.stopPropagation();
}
Debugger.prototype.Toggle = function($KeyCode) {
if(!this.DebuggerDIV) return false;
this.IsVisible = this.DebuggerDIV.style.display == 'none' ? false : true;
if (!this.IsVisible && $KeyCode == 27) {
return false;
}
this.Resize(null);
if (!this.IsQueried) {
this.Query();
}
this.DebuggerDIV.style.display = this.IsVisible ? 'none' : 'block';
}
Debugger.prototype.Query = function() {
DebugReq.makeRequest(this.DebugURL, this.busyRequest, '', this.successCallback, this.errorCallback, '', this);
}
Debugger.prototype.successCallback = function(p_req, p_pass, p_object) {
if (p_pass == 'resetCache') {
alert('Requested action performed.');
return ;
}
var contents = p_req.responseText;
contents = contents.split(p_object.RowSeparator);
if (contents.length == 1) {
alert('error: '+p_req.responseText);
p_object.IsQueried = true;
return ;
}
for (var $i = 0; $i < contents.length - 1; $i++) {
p_object.AppendRow(contents[$i]);
}
if ( p_object.jQueryFound() ) {
var $stats_table = $('.dbg_stats_table:first').clone();
var $statistics_html = $( $('<div></div>').html($stats_table) ).html();
if ($statistics_html) {
$('.dbg_stats_table:first').remove();
p_object.AppendRow($statistics_html);
}
}
p_object.Refresh();
}
Debugger.prototype.errorCallback = function(p_req, p_pass, p_object) {
alert('AJAX ERROR: '+DebugReq.getErrorHtml(p_req));
p_object.Refresh();
}
Debugger.prototype.Refresh = function() {
// progress mether row
this.RemoveRow(0);
this.IsQueried = true;
this.DebuggerDIV.scrollTop = this.IsFatalError ? 10000000 : 0;
this.DebuggerDIV.scrollLeft = 0;
}
Debugger.prototype.Resize = function($e) {
if (!this.DebuggerDIV) return false;
var $pageTop = document.all ? document.body.offsetTop + document.body.scrollTop : window.scrollY;
this.DebuggerDIV.style.top = $pageTop + 'px';
this.DebuggerDIV.style.height = GetWindowHeight() + 'px';
return true;
}
function GetWindowHeight() {
var currWinHeight;
// if (document.body.clientHeight) {
// currWinHeight = document.body.clientHeight;
if (window.innerHeight) {//FireFox with correction for status bar at bottom of window
currWinHeight = window.innerHeight;
} else if (document.documentElement.clientHeight) {//IE 7 with correction for address bar
currWinHeight = document.documentElement.clientHeight;
} else if (document.body.offsetHeight) {//IE 4+
currWinHeight = document.body.offsetHeight + 10;
}
return currWinHeight - 10; // 10 - horizontal scrollbar height
}
/*function GetWinHeight() {
if (window.innerHeight) return window.innerHeight;
else if (document.documentElement.clientHeight) return document.documentElement.clientHeight;
else if (document.body.offsetHeight) return document.body.offsetHeight;
else return _winHeight;
}*/
Debugger.prototype.SetClipboard = function(copyText) {
if (window.clipboardData) {
// IE send-to-clipboard method.
window.clipboardData.setData('Text', copyText);
}
else if (window.netscape) {
// You have to sign the code to enable this or allow the action in about:config by changing user_pref("signed.applets.codebase_principal_support", true);
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
// Store support string in an object.
var str = Components.classes['@mozilla.org/supports-string;1'].createInstance(Components.interfaces.nsISupportsString);
if (!str) {
return false;
}
str.data = copyText;
// Make transferable.
var trans = Components.classes['@mozilla.org/widget/transferable;1'].createInstance(Components.interfaces.nsITransferable);
if (!trans) {
return false;
}
// Specify what datatypes we want to obtain, which is text in this case.
trans.addDataFlavor('text/unicode');
trans.setTransferData('text/unicode', str, copyText.length * 2);
var clipid = Components.interfaces.nsIClipboard;
var clip = Components.classes['@mozilla.org/widget/clipboard;1'].getService(clipid);
if (!clip) {
return false;
}
clip.setData(trans, null, clipid.kGlobalClipboard);
}
}
Debugger.prototype.ShowProps = function($Obj, $Name) {
var $ret = '';
for ($Prop in $Obj) {
$ret += $Name + '.' + $Prop + ' = ' + $Obj[$Prop] + "\n";
}
return alert($ret);
}
Debugger.prototype.editFile = function($fileName, $lineNo) {
if (!document.all) {
alert('Only works in IE');
return;
}
if (!this.EditorPath) {
alert('Editor path not defined!');
return;
}
var $launch_object = new ActiveXObject('LaunchinIE.Launch');
var $editor_path = this.EditorPath;
$editor_path = $editor_path.replace('%F', $fileName);
$editor_path = $editor_path.replace('%L',$lineNo);
$launch_object.LaunchApplication($editor_path);
}
Debugger.prototype.ToggleTraceArgs = function($arguments_layer_id) {
var $arguments_layer = document.getElementById($arguments_layer_id);
$arguments_layer.style.display = ($arguments_layer.style.display == 'none') ? 'block' : 'none';
}
Debugger.prototype.AddEvent = function (el, evname, func) {
var $status = false;
if (document.all) {
$status = el.attachEvent('on' + evname, func);
} else {
$status = el.addEventListener(evname, func, true);
}
}
Debugger.prototype.resetCache = function ($event_source) {
var $events = document.getElementById($event_source);
var $event = $events.options[$events.selectedIndex].value;
if (!$event) {
alert('Please select action to perform first!');
}
else if (confirm('Really perform "' + $events.options[$events.selectedIndex].innerHTML + '"?')) {
DebugReq.makeRequest(this.EventURL + '&' + $event, this.busyRequest, '', this.successCallback, this.errorCallback, 'resetCache', this);
}
}
Debugger.prototype.mouseCoords = function(ev)
{
if(ev.pageX || ev.pageY){
var res = {x:ev.pageX, y:ev.pageY};
}
else {
var res = {
x:ev.clientX + document.body.scrollLeft - document.body.clientLeft,
y:ev.clientY + document.body.scrollTop - document.body.clientTop
};
}
return res;
}
Debugger.prototype.MakeDragable = function(object_id, startCallback, moveCallback, endCallback, options)
{
var drag_object = document.getElementById(object_id);
var cur_options = {'VerticalDrag': 1, 'HorizontalDrag': 1};
if (options) {
for(var i in options) {
cur_options[i] = options[i];
}
}
var the_debugger = this;
this.AddEvent(drag_object, 'mousedown', function(ev){
ev = ev || window.event;
the_debugger.InitialPos = dbg_findPos(drag_object);
var coords = the_debugger.mouseCoords(ev);
var pos = dbg_findPos(drag_object);
the_debugger.MouseOffset = [coords.x - pos[0], coords.y - pos[1]];
the_debugger.DragObject = drag_object;
the_debugger.LastDragObject = drag_object;
the_debugger.DragObject.style.position = 'absolute';
the_debugger.Options = cur_options;
startCallback(drag_object);
});
this.AddEvent(document, 'mousemove', function(ev) {
// window.status = 'mouse at: '+coords.x+','+coords.y;
if(the_debugger.DragObject){
ev = ev || window.event;
var coords = the_debugger.mouseCoords(ev);
if (the_debugger.Options.VerticalDrag) {
the_debugger.DragObject.style.top = (coords.y - the_debugger.MouseOffset[1] ) + 'px' // ;
}
if (the_debugger.Options.HorizontalDrag) {
the_debugger.DragObject.style.left = (coords.x - the_debugger.MouseOffset[0] ) + 'px' // ;
}
moveCallback(drag_object, coords)
return false;
}
});
this.AddEvent(document, 'mouseup', function(ev){
var tmp = the_debugger.DragObject;
the_debugger.DragObject = null;
if(tmp){
endCallback(tmp);
}
var pos = dbg_findPos(drag_object);
});
}
function dbg_findPos(obj) {
var curleft = curtop = 0;
if (obj.offsetParent) {
curleft = obj.offsetLeft
curtop = obj.offsetTop
while (obj = obj.offsetParent) {
curleft += obj.offsetLeft
curtop += obj.offsetTop
}
}
return [curleft,curtop];
}
\ No newline at end of file
Index: branches/5.2.x/core/kernel/utility/formatters/formatters_config.php
===================================================================
--- branches/5.2.x/core/kernel/utility/formatters/formatters_config.php (revision 15129)
+++ branches/5.2.x/core/kernel/utility/formatters/formatters_config.php (revision 15130)
@@ -1,37 +1,37 @@
<?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!');
$config = Array(
'Prefix' => 'formatters',
'EventHandlerClass' => Array('class' => 'kEventHandler', 'file' => '', 'build_event' => 'OnBuild'),
'RegisterClasses' => Array(
- Array('pseudo'=>'kFormatter','class'=>'kFormatter','file'=>'formatter.php','build_event'=>'','require_classes'=>''),
- Array('pseudo'=>'kOptionsFormatter','class'=>'kOptionsFormatter','file'=>'options_formatter.php','build_event'=>'','require_classes'=>'kFormatter'),
- Array('pseudo'=>'kLEFTFormatter','class'=>'kLEFTFormatter','file'=>'left_formatter.php','build_event'=>'','require_classes'=>'kFormatter'),
- Array('pseudo'=>'kDateFormatter','class'=>'kDateFormatter','file'=>'date_formatter.php','build_event'=>'','require_classes'=>'kFormatter'),
- Array('pseudo'=>'kUploadFormatter','class'=>'kUploadFormatter','file'=>'upload_formatter.php','build_event'=>'','require_classes'=>'kFormatter'),
- Array('pseudo'=>'kPictureFormatter','class'=>'kPictureFormatter','file'=>'upload_formatter.php','build_event'=>'','require_classes'=>'kUploadFormatter'),
- Array('pseudo'=>'kMultiLanguage','class'=>'kMultiLanguage','file'=>'multilang_formatter.php','build_event'=>'','require_classes'=>'kFormatter'),
- Array('pseudo'=>'kPasswordFormatter','class'=>'kPasswordFormatter','file'=>'password_formatter.php','build_event'=>'','require_classes'=>'kFormatter'),
- Array('pseudo'=>'kCCDateFormatter','class'=>'kCCDateFormatter','file'=>'ccdate_formatter.php','build_event'=>'','require_classes'=>'kFormatter'),
- Array('pseudo'=>'kUnitFormatter','class'=>'kUnitFormatter','file'=>'unit_formatter.php','build_event'=>'','require_classes'=>'kFormatter'),
- Array('pseudo'=>'kFilesizeFormatter','class'=>'kFilesizeFormatter','file'=>'filesize_formatter.php','build_event'=>'','require_classes'=>'kFormatter'),
- Array('pseudo'=>'kSerializedFormatter','class'=>'kSerializedFormatter','file'=>'serialized_formatter.php','build_event'=>'','require_classes'=>'kFormatter'),
- Array('pseudo'=>'kCustomFieldFormatter','class'=>'kCustomFieldFormatter','file'=>'customfield_formatter.php','build_event'=>'','require_classes'=>'kFormatter'),
+ Array('pseudo'=>'kFormatter','class'=>'kFormatter','file'=>'formatter.php','build_event'=>''),
+ Array('pseudo'=>'kOptionsFormatter','class'=>'kOptionsFormatter','file'=>'options_formatter.php','build_event'=>''),
+ Array('pseudo'=>'kLEFTFormatter','class'=>'kLEFTFormatter','file'=>'left_formatter.php','build_event'=>''),
+ Array('pseudo'=>'kDateFormatter','class'=>'kDateFormatter','file'=>'date_formatter.php','build_event'=>''),
+ Array('pseudo'=>'kUploadFormatter','class'=>'kUploadFormatter','file'=>'upload_formatter.php','build_event'=>''),
+ Array('pseudo'=>'kPictureFormatter','class'=>'kPictureFormatter','file'=>'upload_formatter.php','build_event'=>''),
+ Array('pseudo'=>'kMultiLanguage','class'=>'kMultiLanguage','file'=>'multilang_formatter.php','build_event'=>''),
+ Array('pseudo'=>'kPasswordFormatter','class'=>'kPasswordFormatter','file'=>'password_formatter.php','build_event'=>''),
+ Array('pseudo'=>'kCCDateFormatter','class'=>'kCCDateFormatter','file'=>'ccdate_formatter.php','build_event'=>''),
+ Array('pseudo'=>'kUnitFormatter','class'=>'kUnitFormatter','file'=>'unit_formatter.php','build_event'=>''),
+ Array('pseudo'=>'kFilesizeFormatter','class'=>'kFilesizeFormatter','file'=>'filesize_formatter.php','build_event'=>''),
+ Array('pseudo'=>'kSerializedFormatter','class'=>'kSerializedFormatter','file'=>'serialized_formatter.php','build_event'=>''),
+ Array('pseudo'=>'kCustomFieldFormatter','class'=>'kCustomFieldFormatter','file'=>'customfield_formatter.php','build_event'=>''),
),
);
Index: branches/5.2.x/core/kernel/utility/temp_handler.php
===================================================================
--- branches/5.2.x/core/kernel/utility/temp_handler.php (revision 15129)
+++ branches/5.2.x/core/kernel/utility/temp_handler.php (revision 15130)
@@ -1,1055 +1,1055 @@
<?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 kTempTablesHandler extends kBase {
var $Tables = Array();
/**
* Master table name for temp handler
*
* @var string
* @access private
*/
var $MasterTable = '';
/**
* IDs from master table
*
* @var Array
* @access private
*/
var $MasterIDs = Array();
var $AlreadyProcessed = Array();
var $DroppedTables = Array();
var $FinalRefs = Array();
var $TableIdCounter = 0;
var $CopiedTables = Array();
/**
* Foreign key cache
*
* @var Array
*/
var $FKeysCache = Array ();
/**
* IDs of newly cloned items (key - prefix.special, value - array of ids)
*
* @var Array
*/
var $savedIDs = Array();
/**
* Window ID of current window
*
* @var mixed
*/
var $WindowID = '';
/**
* Event, that was used to create this object
*
* @var kEvent
* @access protected
*/
protected $parentEvent = null;
/**
* Sets new parent event to the object
*
* @param kEvent $event
* @return void
* @access public
*/
- public function setParentEvent(&$event)
+ public function setParentEvent($event)
{
$this->parentEvent =& $event;
}
function SetTables($tables)
{
// set table name as key for tables array
$this->Tables = $tables;
$this->MasterTable = $tables['TableName'];
}
function saveID($prefix, $special = '', $id = null)
{
if (!isset($this->savedIDs[$prefix.($special ? '.' : '').$special])) {
$this->savedIDs[$prefix.($special ? '.' : '').$special] = array();
}
if (is_array($id)) {
foreach ($id as $tmp_id => $live_id) {
$this->savedIDs[$prefix.($special ? '.' : '').$special][$tmp_id] = $live_id;
}
}
else {
$this->savedIDs[$prefix.($special ? '.' : '').$special][] = $id;
}
}
/**
* Get temp table name
*
* @param string $table
* @return string
*/
function GetTempName($table)
{
return $this->Application->GetTempName($table, $this->WindowID);
}
function GetTempTablePrefix()
{
return $this->Application->GetTempTablePrefix($this->WindowID);
}
/**
* Return live table name based on temp table name
*
* @param string $temp_table
* @return string
*/
function GetLiveName($temp_table)
{
return $this->Application->GetLiveName($temp_table);
}
function IsTempTable($table)
{
return $this->Application->IsTempTable($table);
}
/**
* Return temporary table name for master table
*
* @return string
* @access public
*/
function GetMasterTempName()
{
return $this->GetTempName($this->MasterTable);
}
function CreateTempTable($table)
{
$sql = 'CREATE TABLE ' . $this->GetTempName($table) . '
SELECT *
FROM ' . $table . '
WHERE 0';
$this->Conn->Query($sql);
}
function BuildTables($prefix, $ids)
{
$this->WindowID = $this->Application->GetVar('m_wid');
$this->TableIdCounter = 0;
$tables = Array(
'TableName' => $this->Application->getUnitOption($prefix, 'TableName'),
'IdField' => $this->Application->getUnitOption($prefix, 'IDField'),
'IDs' => $ids,
'Prefix' => $prefix,
'TableId' => $this->TableIdCounter++,
);
/*$parent_prefix = $this->Application->getUnitOption($prefix, 'ParentPrefix');
if ($parent_prefix) {
$tables['ForeignKey'] = $this->Application->getUnitOption($prefix, 'ForeignKey');
$tables['ParentPrefix'] = $parent_prefix;
$tables['ParentTableKey'] = $this->Application->getUnitOption($prefix, 'ParentTableKey');
}*/
$this->FinalRefs[ $tables['TableName'] ] = $tables['TableId']; // don't forget to add main table to FinalRefs too
$sub_items = $this->Application->getUnitOption($prefix, 'SubItems', Array ());
/* @var $sub_items Array */
if ( is_array($sub_items) ) {
foreach ($sub_items as $prefix) {
$this->AddTables($prefix, $tables);
}
}
$this->SetTables($tables);
}
/**
* Searches through TempHandler tables info for required prefix
*
* @param string $prefix
* @param Array $master
* @return mixed
*/
function SearchTable($prefix, $master = null)
{
if (is_null($master)) {
$master = $this->Tables;
}
if ($master['Prefix'] == $prefix) {
return $master;
}
if (isset($master['SubTables'])) {
foreach ($master['SubTables'] as $sub_table) {
$found = $this->SearchTable($prefix, $sub_table);
if ($found !== false) {
return $found;
}
}
}
return false;
}
function AddTables($prefix, &$tables)
{
if ( !$this->Application->prefixRegistred($prefix) ) {
// allows to skip subitem processing if subitem module not enabled/installed
return ;
}
$tmp = Array(
'TableName' => $this->Application->getUnitOption($prefix,'TableName'),
'IdField' => $this->Application->getUnitOption($prefix,'IDField'),
'ForeignKey' => $this->Application->getUnitOption($prefix,'ForeignKey'),
'ParentPrefix' => $this->Application->getUnitOption($prefix, 'ParentPrefix'),
'ParentTableKey' => $this->Application->getUnitOption($prefix,'ParentTableKey'),
'Prefix' => $prefix,
'AutoClone' => $this->Application->getUnitOption($prefix,'AutoClone'),
'AutoDelete' => $this->Application->getUnitOption($prefix,'AutoDelete'),
'TableId' => $this->TableIdCounter++,
);
$this->FinalRefs[ $tmp['TableName'] ] = $tmp['TableId'];
$constrain = $this->Application->getUnitOption($prefix, 'Constrain');
if ( $constrain ) {
$tmp['Constrain'] = $constrain;
$this->FinalRefs[ $tmp['TableName'] . $tmp['Constrain'] ] = $tmp['TableId'];
}
$sub_items = $this->Application->getUnitOption($prefix, 'SubItems', Array ());
/* @var $sub_items Array */
if ( is_array($sub_items) ) {
foreach ($sub_items as $prefix) {
$this->AddTables($prefix, $tmp);
}
}
if ( !is_array(getArrayValue($tables, 'SubTables')) ) {
$tables['SubTables'] = Array ();
}
$tables['SubTables'][] = $tmp;
}
function CloneItems($prefix, $special, $ids, $master = null, $foreign_key = null, $parent_prefix = null, $skip_filenames = false)
{
if (!isset($master)) $master = $this->Tables;
// recalling by different name, because we may get kDBList, if we recall just by prefix
if (!preg_match('/(.*)-item$/', $special)) {
$special .= '-item';
}
$object =& $this->Application->recallObject($prefix.'.'.$special, $prefix, Array('skip_autoload' => true, 'parent_event' => &$this->parentEvent));
/* @var $object kCatDBItem */
$object->PopulateMultiLangFields();
foreach ($ids as $id) {
$mode = 'create';
$cloned_ids = getArrayValue($this->AlreadyProcessed, $master['TableName']);
if ( $cloned_ids ) {
// if we have already cloned the id, replace it with cloned id and set mode to update
// update mode is needed to update second ForeignKey for items cloned by first ForeignKey
if ( getArrayValue($cloned_ids, $id) ) {
$id = $cloned_ids[$id];
$mode = 'update';
}
}
$object->Load($id);
$original_values = $object->GetFieldValues();
if (!$skip_filenames) {
$object->NameCopy($master, $foreign_key);
}
elseif ($master['TableName'] == $this->MasterTable) {
// kCatDBItem class only has this attribute
$object->useFilenames = false;
}
if (isset($foreign_key)) {
$master_foreign_key_field = is_array($master['ForeignKey']) ? $master['ForeignKey'][$parent_prefix] : $master['ForeignKey'];
$object->SetDBField($master_foreign_key_field, $foreign_key);
}
if ($mode == 'create') {
$this->RaiseEvent('OnBeforeClone', $master['Prefix'], $special, Array($object->GetId()), $foreign_key);
}
$object->inCloning = true;
$res = $mode == 'update' ? $object->Update() : $object->Create();
$object->inCloning = false;
if ($res)
{
if ( $mode == 'create' && is_array( getArrayValue($master, 'ForeignKey')) ) {
// remember original => clone mapping for dual ForeignKey updating
$this->AlreadyProcessed[$master['TableName']][$id] = $object->GetId();
}
if ($mode == 'create') {
$this->RaiseEvent('OnAfterClone', $master['Prefix'], $special, Array($object->GetId()), $foreign_key, array('original_id' => $id) );
$this->saveID($master['Prefix'], $special, $object->GetID());
}
if ( is_array(getArrayValue($master, 'SubTables')) ) {
foreach($master['SubTables'] as $sub_table) {
if (!getArrayValue($sub_table, 'AutoClone')) continue;
$sub_TableName = $object->IsTempTable() ? $this->GetTempName($sub_table['TableName']) : $sub_table['TableName'];
$foreign_key_field = is_array($sub_table['ForeignKey']) ? $sub_table['ForeignKey'][$master['Prefix']] : $sub_table['ForeignKey'];
$parent_key_field = is_array($sub_table['ParentTableKey']) ? $sub_table['ParentTableKey'][$master['Prefix']] : $sub_table['ParentTableKey'];
if (!$foreign_key_field || !$parent_key_field) continue;
$query = 'SELECT '.$sub_table['IdField'].' FROM '.$sub_TableName.'
WHERE '.$foreign_key_field.' = '.$original_values[$parent_key_field];
if (isset($sub_table['Constrain'])) $query .= ' AND '.$sub_table['Constrain'];
$sub_ids = $this->Conn->GetCol($query);
if ( is_array(getArrayValue($sub_table, 'ForeignKey')) ) {
// $sub_ids could containt newly cloned items, we need to remove it here
// to escape double cloning
$cloned_ids = getArrayValue($this->AlreadyProcessed, $sub_table['TableName']);
if ( !$cloned_ids ) $cloned_ids = Array();
$new_ids = array_values($cloned_ids);
$sub_ids = array_diff($sub_ids, $new_ids);
}
$parent_key = $object->GetDBField($parent_key_field);
$this->CloneItems($sub_table['Prefix'], $special, $sub_ids, $sub_table, $parent_key, $master['Prefix']);
}
}
}
}
if (!$ids) {
$this->savedIDs[$prefix.($special ? '.' : '').$special] = Array();
}
return $this->savedIDs[$prefix.($special ? '.' : '').$special];
}
function DeleteItems($prefix, $special, $ids, $master=null, $foreign_key=null)
{
if ( !$ids ) {
return;
}
if ( !isset($master) ) {
$master = $this->Tables;
}
if ( strpos($prefix, '.') !== false ) {
list($prefix, $special) = explode('.', $prefix, 2);
}
$prefix_special = rtrim($prefix . '.' . $special, '.');
//recalling by different name, because we may get kDBList, if we recall just by prefix
$recall_prefix = $prefix_special . ($special ? '' : '.') . '-item';
$object =& $this->Application->recallObject($recall_prefix, $prefix, Array ('skip_autoload' => true, 'parent_event' => &$this->parentEvent));
/* @var $object kDBItem */
foreach ($ids as $id) {
$object->Load($id);
$original_values = $object->GetFieldValues();
if ( !$object->Delete($id) ) {
continue;
}
if ( is_array(getArrayValue($master, 'SubTables')) ) {
foreach ($master['SubTables'] as $sub_table) {
if ( !getArrayValue($sub_table, 'AutoDelete') ) {
continue;
}
$sub_TableName = $object->IsTempTable() ? $this->GetTempName($sub_table['TableName']) : $sub_table['TableName'];
$foreign_key_field = is_array($sub_table['ForeignKey']) ? getArrayValue($sub_table, 'ForeignKey', $master['Prefix']) : $sub_table['ForeignKey'];
$parent_key_field = is_array($sub_table['ParentTableKey']) ? getArrayValue($sub_table, 'ParentTableKey', $master['Prefix']) : $sub_table['ParentTableKey'];
if ( !$foreign_key_field || !$parent_key_field ) {
continue;
}
$sql = 'SELECT ' . $sub_table['IdField'] . '
FROM ' . $sub_TableName . '
WHERE ' . $foreign_key_field . ' = ' . $original_values[$parent_key_field];
$sub_ids = $this->Conn->GetCol($sql);
$parent_key = $object->GetDBField(is_array($sub_table['ParentTableKey']) ? $sub_table['ParentTableKey'][$prefix] : $sub_table['ParentTableKey']);
$this->DeleteItems($sub_table['Prefix'], $special, $sub_ids, $sub_table, $parent_key);
}
}
}
}
function DoCopyLiveToTemp($master, $ids, $parent_prefix=null)
{
// when two tables refers the same table as sub-sub-table, and ForeignKey and ParentTableKey are arrays
// the table will be first copied by first sub-table, then dropped and copied over by last ForeignKey in the array
// this should not do any problems :)
if ( !preg_match("/.*\.[0-9]+/", $master['Prefix']) ) {
if( $this->DropTempTable($master['TableName']) )
{
$this->CreateTempTable($master['TableName']);
}
}
if (is_array($ids)) {
$ids = join(',', $ids);
}
$table_sig = $master['TableName'].(isset($master['Constrain']) ? $master['Constrain'] : '');
if ($ids != '' && !in_array($table_sig, $this->CopiedTables)) {
if ( getArrayValue($master, 'ForeignKey') ) {
if ( is_array($master['ForeignKey']) ) {
$key_field = $master['ForeignKey'][$parent_prefix];
}
else {
$key_field = $master['ForeignKey'];
}
}
else {
$key_field = $master['IdField'];
}
$query = 'INSERT INTO '.$this->GetTempName($master['TableName']).'
SELECT * FROM '.$master['TableName'].'
WHERE '.$key_field.' IN ('.$ids.')';
if (isset($master['Constrain'])) $query .= ' AND '.$master['Constrain'];
$this->Conn->Query($query);
$this->CopiedTables[] = $table_sig;
$query = 'SELECT '.$master['IdField'].' FROM '.$master['TableName'].'
WHERE '.$key_field.' IN ('.$ids.')';
if (isset($master['Constrain'])) $query .= ' AND '.$master['Constrain'];
$this->RaiseEvent( 'OnAfterCopyToTemp', $master['Prefix'], '', $this->Conn->GetCol($query) );
}
if ( getArrayValue($master, 'SubTables') ) {
foreach ($master['SubTables'] as $sub_table) {
$parent_key = is_array($sub_table['ParentTableKey']) ? $sub_table['ParentTableKey'][$master['Prefix']] : $sub_table['ParentTableKey'];
if (!$parent_key) continue;
if ( $ids != '' && $parent_key != $key_field ) {
$query = 'SELECT '.$parent_key.' FROM '.$master['TableName'].'
WHERE '.$key_field.' IN ('.$ids.')';
$sub_foreign_keys = join(',', $this->Conn->GetCol($query));
}
else {
$sub_foreign_keys = $ids;
}
$this->DoCopyLiveToTemp($sub_table, $sub_foreign_keys, $master['Prefix']);
}
}
}
function GetForeignKeys($master, $sub_table, $live_id, $temp_id=null)
{
$mode = 1; //multi
if (!is_array($live_id)) {
$live_id = Array($live_id);
$mode = 2; //single
}
if (isset($temp_id) && !is_array($temp_id)) $temp_id = Array($temp_id);
if ( isset($sub_table['ParentTableKey']) ) {
if ( is_array($sub_table['ParentTableKey']) ) {
$parent_key_field = $sub_table['ParentTableKey'][$master['Prefix']];
}
else {
$parent_key_field = $sub_table['ParentTableKey'];
}
}
else {
$parent_key_field = $master['IdField'];
}
$cached = getArrayValue($this->FKeysCache, $master['TableName'].'.'.$parent_key_field);
if ( $cached ) {
if ( array_key_exists(serialize($live_id), $cached) ) {
list($live_foreign_key, $temp_foreign_key) = $cached[serialize($live_id)];
if ($mode == 1) {
return $live_foreign_key;
}
else {
return Array($live_foreign_key[0], $temp_foreign_key[0]);
}
}
}
if ($parent_key_field != $master['IdField']) {
$query = 'SELECT '.$parent_key_field.' FROM '.$master['TableName'].'
WHERE '.$master['IdField'].' IN ('.join(',', $live_id).')';
$live_foreign_key = $this->Conn->GetCol($query);
if (isset($temp_id)) {
// because DoCopyTempToOriginal resets negative IDs to 0 in temp table (one by one) before copying to live
$temp_key = $temp_id < 0 ? 0 : $temp_id;
$query = 'SELECT '.$parent_key_field.' FROM '.$this->GetTempName($master['TableName']).'
WHERE '.$master['IdField'].' IN ('.join(',', $temp_key).')';
$temp_foreign_key = $this->Conn->GetCol($query);
}
else {
$temp_foreign_key = Array();
}
}
else {
$live_foreign_key = $live_id;
$temp_foreign_key = $temp_id;
}
$this->FKeysCache[$master['TableName'].'.'.$parent_key_field][serialize($live_id)] = Array($live_foreign_key, $temp_foreign_key);
if ($mode == 1) {
return $live_foreign_key;
}
else {
return Array($live_foreign_key[0], $temp_foreign_key[0]);
}
}
/**
* Copies data from temp to live table and returns IDs of copied records
*
* @param Array $master
* @param string $parent_prefix
* @param Array $current_ids
* @return Array
* @access public
*/
public function DoCopyTempToOriginal($master, $parent_prefix = null, $current_ids = Array())
{
if ( !$current_ids ) {
$query = 'SELECT ' . $master['IdField'] . ' FROM ' . $this->GetTempName($master['TableName']);
if ( isset($master['Constrain']) ) {
$query .= ' WHERE ' . $master['Constrain'];
}
$current_ids = $this->Conn->GetCol($query);
}
$table_sig = $master['TableName'] . (isset($master['Constrain']) ? $master['Constrain'] : '');
if ($current_ids) {
// delete all ids from live table - for MasterTable ONLY!
// because items from Sub Tables get deteleted in CopySubTablesToLive !BY ForeignKey!
if ( $master['TableName'] == $this->MasterTable ) {
$this->RaiseEvent('OnBeforeDeleteFromLive', $master['Prefix'], '', $current_ids);
$query = 'DELETE FROM ' . $master['TableName'] . ' WHERE ' . $master['IdField'] . ' IN (' . join(',', $current_ids) . ')';
$this->Conn->Query($query);
}
if ( getArrayValue($master, 'SubTables') ) {
if ( in_array($table_sig, $this->CopiedTables) || $this->FinalRefs[$table_sig] != $master['TableId'] ) {
return Array ();
}
foreach ($current_ids AS $id) {
$this->RaiseEvent('OnBeforeCopyToLive', $master['Prefix'], '', Array ($id));
//reset negative ids to 0, so autoincrement in live table works fine
if ( $id < 0 ) {
$query = ' UPDATE ' . $this->GetTempName($master['TableName']) . '
SET ' . $master['IdField'] . ' = 0
WHERE ' . $master['IdField'] . ' = ' . $id;
if ( isset($master['Constrain']) ) {
$query .= ' AND ' . $master['Constrain'];
}
$this->Conn->Query($query);
$id_to_copy = 0;
}
else {
$id_to_copy = $id;
}
//copy current id_to_copy (0 for new or real id) to live table
$query = ' INSERT INTO ' . $master['TableName'] . '
SELECT * FROM ' . $this->GetTempName($master['TableName']) . '
WHERE ' . $master['IdField'] . ' = ' . $id_to_copy;
$this->Conn->Query($query);
$insert_id = $id_to_copy == 0 ? $this->Conn->getInsertID() : $id_to_copy;
$this->saveID($master['Prefix'], '', array ($id => $insert_id));
$this->RaiseEvent('OnAfterCopyToLive', $master['Prefix'], '', Array ($insert_id), null, Array ('temp_id' => $id));
$this->UpdateForeignKeys($master, $insert_id, $id);
//delete already copied record from master temp table
$query = ' DELETE FROM ' . $this->GetTempName($master['TableName']) . '
WHERE ' . $master['IdField'] . ' = ' . $id_to_copy;
if ( isset($master['Constrain']) ) {
$query .= ' AND ' . $master['Constrain'];
}
$this->Conn->Query($query);
}
$this->CopiedTables[] = $table_sig;
// when all of ids in current master has been processed, copy all sub-tables data
$this->CopySubTablesToLive($master, $current_ids);
}
elseif ( !in_array($table_sig, $this->CopiedTables) && ($this->FinalRefs[$table_sig] == $master['TableId']) ) { //If current master doesn't have sub-tables - we could use mass operations
// We don't need to delete items from live here, as it get deleted in the beginning of the method for MasterTable
// or in parent table processing for sub-tables
$live_ids = Array ();
$this->RaiseEvent('OnBeforeCopyToLive', $master['Prefix'], '', $current_ids);
foreach ($current_ids as $an_id) {
if ( $an_id > 0 ) {
$live_ids[$an_id] = $an_id;
// positive (already live) IDs will be copied in on query all togather below,
// so we just store it here
continue;
}
else { // zero or negative ids should be copied one by one to get their InsertId
// resetting to 0 so it get inserted into live table with autoincrement
$query = ' UPDATE ' . $this->GetTempName($master['TableName']) . '
SET ' . $master['IdField'] . ' = 0
WHERE ' . $master['IdField'] . ' = ' . $an_id;
// constrain is not needed here because ID is already unique
$this->Conn->Query($query);
// copying
$query = ' INSERT INTO ' . $master['TableName'] . '
SELECT * FROM ' . $this->GetTempName($master['TableName']) . '
WHERE ' . $master['IdField'] . ' = 0';
$this->Conn->Query($query);
$live_ids[$an_id] = $this->Conn->getInsertID(); //storing newly created live id
//delete already copied record from master temp table
$query = ' DELETE FROM ' . $this->GetTempName($master['TableName']) . '
WHERE ' . $master['IdField'] . ' = 0';
$this->Conn->Query($query);
$this->UpdateChangeLogForeignKeys($master, $live_ids[$an_id], $an_id);
}
}
// copy ALL records to live table
$query = ' INSERT INTO ' . $master['TableName'] . '
SELECT * FROM ' . $this->GetTempName($master['TableName']);
if ( isset($master['Constrain']) ) {
$query .= ' WHERE ' . $master['Constrain'];
}
$this->Conn->Query($query);
$this->CopiedTables[] = $table_sig;
$this->RaiseEvent('OnAfterCopyToLive', $master['Prefix'], '', $live_ids);
$this->saveID($master['Prefix'], '', $live_ids);
// no need to clear temp table - it will be dropped by next statement
}
}
if ( $this->FinalRefs[ $master['TableName'] ] != $master['TableId'] ) {
return Array ();
}
/*if ( is_array(getArrayValue($master, 'ForeignKey')) ) { //if multiple ForeignKeys
if ( $master['ForeignKey'][$parent_prefix] != end($master['ForeignKey']) ) {
return; // Do not delete temp table if not all ForeignKeys have been processed (current is not the last)
}
}*/
$this->DropTempTable($master['TableName']);
$this->Application->resetCounters($master['TableName']);
if ( !isset($this->savedIDs[ $master['Prefix'] ]) ) {
$this->savedIDs[ $master['Prefix'] ] = Array ();
}
return $this->savedIDs[ $master['Prefix'] ];
}
/**
* Create separate connection for locking purposes
*
* @return kDBConnection
*/
function &_getSeparateConnection()
{
static $connection = null;
if (!isset($connection)) {
$connection =& $this->Application->makeClass( 'kDBConnection', Array (SQL_TYPE, Array (&$this->Application, 'handleSQLError')) );
/* @var $connection kDBConnection */
$connection->debugMode = $this->Application->isDebugMode();
$connection->Connect(SQL_SERVER, SQL_USER, SQL_PASS, SQL_DB, true);
}
return $connection;
}
function UpdateChangeLogForeignKeys($master, $live_id, $temp_id)
{
if ($live_id == $temp_id) {
return ;
}
$prefix = $master['Prefix'];
$main_prefix = $this->Application->GetTopmostPrefix($prefix);
$ses_var_name = $main_prefix . '_changes_' . $this->Application->GetTopmostWid($this->Prefix);
$changes = $this->Application->RecallVar($ses_var_name);
$changes = $changes ? unserialize($changes) : Array ();
foreach ($changes as $key => $rec) {
if ($rec['Prefix'] == $prefix && $rec['ItemId'] == $temp_id) {
// main item change log record
$changes[$key]['ItemId'] = $live_id;
}
if ($rec['MasterPrefix'] == $prefix && $rec['MasterId'] == $temp_id) {
// sub item change log record
$changes[$key]['MasterId'] = $live_id;
}
if (in_array($prefix, $rec['ParentPrefix']) && $rec['ParentId'][$prefix] == $temp_id) {
// parent item change log record
$changes[$key]['ParentId'][$prefix] = $live_id;
if (array_key_exists('DependentFields', $rec)) {
// these are fields from table of $rec['Prefix'] table!
// when one of dependent fields goes into idfield of it's parent item, that was changed
$parent_table_key = $this->Application->getUnitOption($rec['Prefix'], 'ParentTableKey');
$parent_table_key = is_array($parent_table_key) ? $parent_table_key[$prefix] : $parent_table_key;
if ($parent_table_key == $master['IdField']) {
$foreign_key = $this->Application->getUnitOption($rec['Prefix'], 'ForeignKey');
$foreign_key = is_array($foreign_key) ? $foreign_key[$prefix] : $foreign_key;
$changes[$key]['DependentFields'][$foreign_key] = $live_id;
}
}
}
}
$this->Application->StoreVar($ses_var_name, serialize($changes));
}
function UpdateForeignKeys($master, $live_id, $temp_id)
{
$this->UpdateChangeLogForeignKeys($master, $live_id, $temp_id);
foreach ($master['SubTables'] as $sub_table) {
$foreign_key_field = is_array($sub_table['ForeignKey']) ? getArrayValue($sub_table, 'ForeignKey', $master['Prefix']) : $sub_table['ForeignKey'];
if (!$foreign_key_field) {
continue;
}
list ($live_foreign_key, $temp_foreign_key) = $this->GetForeignKeys($master, $sub_table, $live_id, $temp_id);
//Update ForeignKey in sub TEMP table
if ($live_foreign_key != $temp_foreign_key) {
$query = 'UPDATE '.$this->GetTempName($sub_table['TableName']).'
SET '.$foreign_key_field.' = '.$live_foreign_key.'
WHERE '.$foreign_key_field.' = '.$temp_foreign_key;
if (isset($sub_table['Constrain'])) $query .= ' AND '.$sub_table['Constrain'];
$this->Conn->Query($query);
}
}
}
function CopySubTablesToLive($master, $current_ids) {
foreach ($master['SubTables'] as $sub_table) {
$table_sig = $sub_table['TableName'].(isset($sub_table['Constrain']) ? $sub_table['Constrain'] : '');
// delete records from live table by foreign key, so that records deleted from temp table
// get deleted from live
if (count($current_ids) > 0 && !in_array($table_sig, $this->CopiedTables) ) {
$foreign_key_field = is_array($sub_table['ForeignKey']) ? getArrayValue($sub_table, 'ForeignKey', $master['Prefix']) : $sub_table['ForeignKey'];
if (!$foreign_key_field) continue;
$foreign_keys = $this->GetForeignKeys($master, $sub_table, $current_ids);
if (count($foreign_keys) > 0) {
$query = 'SELECT '.$sub_table['IdField'].' FROM '.$sub_table['TableName'].'
WHERE '.$foreign_key_field.' IN ('.join(',', $foreign_keys).')';
if (isset($sub_table['Constrain'])) $query .= ' AND '.$sub_table['Constrain'];
if ( $this->RaiseEvent( 'OnBeforeDeleteFromLive', $sub_table['Prefix'], '', $this->Conn->GetCol($query), $foreign_keys ) ){
$query = 'DELETE FROM '.$sub_table['TableName'].'
WHERE '.$foreign_key_field.' IN ('.join(',', $foreign_keys).')';
if (isset($sub_table['Constrain'])) $query .= ' AND '.$sub_table['Constrain'];
$this->Conn->Query($query);
}
}
}
//sub_table passed here becomes master in the method, and recursively updated and copy its sub tables
$this->DoCopyTempToOriginal($sub_table, $master['Prefix']);
}
}
/**
* Raises event using IDs, that are currently being processed in temp handler
*
* @param string $name
* @param string $prefix
* @param string $special
* @param Array $ids
* @param string $foreign_key
* @param Array $add_params
* @return bool
* @access protected
*/
protected function RaiseEvent($name, $prefix, $special, $ids, $foreign_key = null, $add_params = null)
{
if ( !is_array($ids) ) {
return true;
}
$event_key = $prefix . ($special ? '.' : '') . $special . ':' . $name;
$event = new kEvent($event_key);
if ( isset($foreign_key) ) {
$event->setEventParam('foreign_key', $foreign_key);
}
$set_temp_id = ($name == 'OnAfterCopyToLive') && (!is_array($add_params) || !array_key_exists('temp_id', $add_params));
foreach ($ids as $index => $id) {
$event->setEventParam('id', $id);
if ( $set_temp_id ) {
$event->setEventParam('temp_id', $index);
}
if ( is_array($add_params) ) {
foreach ($add_params as $name => $val) {
$event->setEventParam($name, $val);
}
}
$this->Application->HandleEvent($event);
}
return $event->status == kEvent::erSUCCESS;
}
function DropTempTable($table)
{
if ( in_array($table, $this->DroppedTables) ) {
return false;
}
$query = 'DROP TABLE IF EXISTS ' . $this->GetTempName($table);
array_push($this->DroppedTables, $table);
$this->DroppedTables = array_unique($this->DroppedTables);
$this->Conn->Query($query);
return true;
}
function PrepareEdit()
{
$this->DoCopyLiveToTemp($this->Tables, $this->Tables['IDs']);
if ($this->Application->getUnitOption($this->Tables['Prefix'],'CheckSimulatniousEdit')) {
$this->CheckSimultaniousEdit();
}
}
function SaveEdit($master_ids = Array())
{
// SessionKey field is required for deleting records from expired sessions
$conn =& $this->_getSeparateConnection();
$sleep_count = 0;
do {
// acquire lock
$conn->ChangeQuery('LOCK TABLES '.TABLE_PREFIX.'Semaphores WRITE');
$sql = 'SELECT SessionKey
FROM ' . TABLE_PREFIX . 'Semaphores
WHERE (MainPrefix = ' . $conn->qstr($this->Tables['Prefix']) . ')';
$another_coping_active = $conn->GetOne($sql);
if ($another_coping_active) {
// another user is coping data from temp table to live -> release lock and try again after 1 second
$conn->ChangeQuery('UNLOCK TABLES');
$sleep_count++;
sleep(1);
}
} while ($another_coping_active && ($sleep_count <= 30));
if ($sleep_count > 30) {
// another coping process failed to finished in 30 seconds
$error_message = $this->Application->Phrase('la_error_TemporaryTableCopyingFailed');
$this->Application->SetVar('_temp_table_message', $error_message);
return false;
}
// mark, that we are coping from temp to live right now, so other similar attempt (from another script) will fail
$fields_hash = Array (
'SessionKey' => $this->Application->GetSID(),
'Timestamp' => adodb_mktime(),
'MainPrefix' => $this->Tables['Prefix'],
);
$conn->doInsert($fields_hash, TABLE_PREFIX.'Semaphores');
$semaphore_id = $conn->getInsertID();
// unlock table now to prevent permanent lock in case, when coping will end with SQL error in the middle
$conn->ChangeQuery('UNLOCK TABLES');
$ids = $this->DoCopyTempToOriginal($this->Tables, null, $master_ids);
// remove mark, that we are coping from temp to live
$conn->Query('LOCK TABLES '.TABLE_PREFIX.'Semaphores WRITE');
$sql = 'DELETE FROM ' . TABLE_PREFIX . 'Semaphores
WHERE SemaphoreId = ' . $semaphore_id;
$conn->ChangeQuery($sql);
$conn->ChangeQuery('UNLOCK TABLES');
return $ids;
}
function CancelEdit($master=null)
{
if (!isset($master)) $master = $this->Tables;
$this->DropTempTable($master['TableName']);
if ( getArrayValue($master, 'SubTables') ) {
foreach ($master['SubTables'] as $sub_table) {
$this->CancelEdit($sub_table);
}
}
}
/**
* Checks, that someone is editing selected records and returns true, when no one.
*
* @param Array $ids
*
* @return bool
*/
function CheckSimultaniousEdit($ids = null)
{
$tables = $this->Conn->GetCol('SHOW TABLES');
$mask_edit_table = '/' . TABLE_PREFIX . 'ses_(.*)_edit_' . $this->MasterTable . '$/';
$my_sid = $this->Application->GetSID();
$my_wid = $this->Application->GetVar('m_wid');
$ids = implode(',', isset($ids) ? $ids : $this->Tables['IDs']);
$sids = Array ();
if (!$ids) {
return true;
}
foreach ($tables as $table) {
if ( preg_match($mask_edit_table, $table, $rets) ) {
$sid = preg_replace('/(.*)_(.*)/', '\\1', $rets[1]); // remove popup's wid from sid
if ($sid == $my_sid) {
if ($my_wid) {
// using popups for editing
if (preg_replace('/(.*)_(.*)/', '\\2', $rets[1]) == $my_wid) {
// don't count window, that is being opened right now
continue;
}
}
else {
// not using popups for editing -> don't count my session tables
continue;
}
}
$sql = 'SELECT COUNT(' . $this->Tables['IdField'] . ')
FROM ' . $table . '
WHERE ' . $this->Tables['IdField'] . ' IN (' . $ids . ')';
$found = $this->Conn->GetOne($sql);
if (!$found || in_array($sid, $sids)) {
continue;
}
$sids[] = $sid;
}
}
if ($sids) {
// detect who is it
$sql = 'SELECT
CONCAT(IF (s.PortalUserId = ' . USER_ROOT . ', \'root\',
IF (s.PortalUserId = ' . USER_GUEST . ', \'Guest\',
CONCAT(u.FirstName, \' \', u.LastName, \' (\', u.Username, \')\')
)
), \' IP: \', s.IpAddress, \'\') FROM ' . TABLE_PREFIX . 'UserSessions AS s
LEFT JOIN ' . TABLE_PREFIX . 'Users AS u
ON u.PortalUserId = s.PortalUserId
WHERE s.SessionKey IN (' . implode(',', $sids) . ')';
$users = $this->Conn->GetCol($sql);
if ($users) {
$this->Application->SetVar('_simultanious_edit_message',
sprintf($this->Application->Phrase('la_record_being_edited_by'), join(",\n", $users))
);
return false;
}
}
return true;
}
}
\ No newline at end of file
Index: branches/5.2.x/core/kernel/utility/factory.php
===================================================================
--- branches/5.2.x/core/kernel/utility/factory.php (revision 15129)
+++ branches/5.2.x/core/kernel/utility/factory.php (revision 15130)
@@ -1,340 +1,291 @@
<?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!');
+defined('FULL_PATH') or die('restricted access!');
- class kFactory extends kBase implements kiCacheable {
+class kFactory extends kBase implements kiCacheable {
- /**
- * Where all created objects are stored
- *
- * @var Array
- * @access private
- */
- var $Storage = Array ();
-
- /**
- * Map between class name and file name
- * where class definition can be found.
- * File path absolute!
- *
- * @var Array
- * @access private
- */
- var $Files = Array ();
-
- /**
- * Map class names to their pseudo
- * class names, e.g. key=pseudo_class,
- * value=real_class_name
- *
- * @var Array
- * @access private
- */
- var $realClasses = Array ();
-
- /**
- * class name vs other classnames it's require for existing
- *
- * @var Array
- */
- var $Dependencies = Array ();
-
- /**
- * Sets data from cache to object
- *
- * @param Array $data
- * @access public
- */
- public function setFromCache(&$data)
- {
- $this->Files = $data['Factory.Files'];
- $this->realClasses = $data['Factory.realClasses'];
- $this->Dependencies = $data['Factory.Dependencies'];
- }
-
- /**
- * Gets object data for caching
- *
- * @access public
- * @return Array
- */
- public function getToCache()
- {
- return Array (
- 'Factory.Files' => $this->Files,
- 'Factory.realClasses' => $this->realClasses,
- 'Factory.Dependencies' => $this->Dependencies,
- );
- }
-
- /**
- * Splits any mixing of prefix and
- * special into correct ones
- *
- * @param string $prefix_special
- * @return Array
- * @access public
- */
- function processPrefix($prefix_special)
- {
- // l.pick, l, m.test_TagProcessor
-
- //preg_match("/(.*)\.*(.*)(_*)(.*)/", $prefix_special, $regs);
- //return Array('prefix'=>$regs[1].$regs[3].$regs[4], 'special'=>$regs[2]);
-
- $tmp=explode('_',$prefix_special,2);
- $tmp[0]=explode('.',$tmp[0]);
-
- $prefix=$tmp[0][0];
- $prefix_special=$prefix; // new1
- if( isset($tmp[1]) )
- {
- $prefix.='_'.$tmp[1];
- }
- $special= isset($tmp[0][1]) ? $tmp[0][1] : '';
- $prefix_special.='.'.$special; // new2
-
- return Array('prefix'=>$prefix,'special'=>$special,'prefix_special'=>$prefix_special);
+ /**
+ * Where all created objects are stored
+ *
+ * @var Array
+ * @access protected
+ */
+ protected $Storage = Array ();
+
+ /**
+ * Mapping between class name and file name
+ * where class definition can be found.
+ * File path absolute!
+ *
+ * @var Array
+ * @access protected
+ */
+ protected $Files = Array ();
+
+ /**
+ * Map class names to their pseudo
+ * class names, e.g. key=pseudo_class,
+ * value=real_class_name
+ *
+ * @var Array
+ * @access protected
+ */
+ protected $realClasses = Array ();
+
+ public function __construct()
+ {
+ parent::__construct();
+
+ spl_autoload_register(Array (&$this, 'autoload'));
+ }
+
+ /**
+ * Sets data from cache to object
+ *
+ * @param Array $data
+ * @return void
+ * @access public
+ */
+ public function setFromCache(&$data)
+ {
+ $this->Files = $data['Factory.Files'];
+ $this->realClasses = $data['Factory.realClasses'];
+ }
+
+ /**
+ * Performs automatic loading of classes registered with the factory
+ *
+ * @param string $class_name
+ * @return void
+ * @throws Exception
+ * @access public
+ */
+ public function autoload($class_name)
+ {
+ if ( !isset($this->Files[$class_name]) ) {
+ // class not from our factory -> let other autoloaders handle it
+ return;
}
+ if ( !file_exists(FULL_PATH . $this->Files[$class_name]) ) {
+ throw new Exception('File <strong>' . FULL_PATH . $this->Files[$class_name] . '</strong> containing class <strong>' . $class_name . '</strong> definition not found');
+ }
- /**
- * Returns object using params specified, creates it if is required
- *
- * @param string $name
- * @param string $pseudo_class
- * @param Array $event_params
- * @param Array $arguments
- * @return kBase
- */
- function &getObject($name, $pseudo_class = '', $event_params = Array (), $arguments = Array ())
- {
- $name = rtrim($name, '.');
-
- if ( isset($this->Storage[$name]) ) {
- return $this->Storage[$name];
- }
+ kUtil::includeOnce(FULL_PATH . $this->Files[$class_name]);
+ }
- $ret = $this->processPrefix($name);
+ /**
+ * Gets object data for caching
+ *
+ * @return Array
+ * @access public
+ */
+ public function getToCache()
+ {
+ return Array (
+ 'Factory.Files' => $this->Files,
+ 'Factory.realClasses' => $this->realClasses,
+ );
+ }
+
+ /**
+ * Splits any mixing of prefix and
+ * special into correct ones
+ *
+ * @param string $prefix_special
+ * @return Array
+ * @access public
+ */
+ public function processPrefix($prefix_special)
+ {
+ // l.pick, l, m.test_TagProcessor
+
+ //preg_match("/(.*)\.*(.*)(_*)(.*)/", $prefix_special, $regs);
+ //return Array('prefix'=>$regs[1].$regs[3].$regs[4], 'special'=>$regs[2]);
- if (!$pseudo_class) {
- $pseudo_class = $ret['prefix'];
- }
+ $tmp = explode('_', $prefix_special, 2);
+ $tmp[0] = explode('.', $tmp[0]);
- if ( !isset($this->realClasses[$pseudo_class]) ) {
- $error_msg = 'RealClass not defined for pseudo_class <strong>' . $pseudo_class . '</strong>';
+ $prefix = $tmp[0][0];
+ $prefix_special = $prefix; // new1
- if ( $this->Application->isInstalled() ) {
- throw new Exception($error_msg);
- }
- else {
- if ( $this->Application->isDebugMode() ) {
- $this->Application->Debugger->appendTrace();
- }
+ if ( isset($tmp[1]) ) {
+ $prefix .= '_' . $tmp[1];
+ }
- trigger_error($error_msg, E_USER_WARNING);
- }
+ $special = isset($tmp[0][1]) ? $tmp[0][1] : '';
+ $prefix_special .= '.' . $special; // new2
- $false = false;
- return $false;
- }
+ return Array ('prefix' => $prefix, 'special' => $special, 'prefix_special' => $prefix_special);
+ }
- if ( defined('DEBUG_MODE') && defined('DBG_FACTORY') && DBG_FACTORY && $this->Application->isDebugMode() ) {
- $this->Application->Debugger->appendHTML('<b>Creating object:</b> Pseudo class: '.$pseudo_class.' Prefix: '.$name);
- $this->Application->Debugger->appendTrace();
- }
- $this->Storage[$name] =& $this->makeClass($pseudo_class, $arguments);
- $this->Storage[$name]->Init($ret['prefix'], $ret['special']);
- $this->Application->EventManager->runBuildEvent($ret['prefix_special'], $pseudo_class, $event_params);
+ /**
+ * Returns object using params specified, creates it if is required
+ *
+ * @param string $name
+ * @param string $pseudo_class
+ * @param Array $event_params
+ * @param Array $arguments
+ * @return kBase
+ * @access public
+ */
+ public function &getObject($name, $pseudo_class = '', $event_params = Array (), $arguments = Array ())
+ {
+ $name = rtrim($name, '.');
+ if ( isset($this->Storage[$name]) ) {
return $this->Storage[$name];
}
- /**
- * Removes object from storage, so next time it could be created from scratch
- *
- * @param string $name Object's name in the Storage
- */
- function DestroyObject($name)
- {
- unset($this->Storage[$name]);
- }
-
- /**
- * Includes file containing class
- * definition for real class name
- *
- * @param string $real_class
- * @param string $pseudo_class
- * @access private
- */
- function includeClassFile($real_class, $pseudo_class = null)
- {
- if ( class_exists($real_class) ) {
- return;
- }
-
- if( !isset($this->Files[$real_class]) ) {
- throw new Exception('Real Class <strong>' . $real_class . '</strong> (for pseudo class <strong>' . $pseudo_class . '</strong>) is not registered with the Factory');
- }
+ $ret = $this->processPrefix($name);
- if( !file_exists(FULL_PATH . $this->Files[$real_class]) ) {
- throw new Exception('Include file for class <strong>' . $real_class . '</strong> (<strong>' . FULL_PATH . $this->Files[$real_class] . '</strong>) does not exists');
- }
-
- if( isset( $this->Dependencies[$real_class] ) )
- {
- foreach($this->Dependencies[$real_class] as $dep_class_name)
- {
- $this->includeClassFile($dep_class_name, $pseudo_class);
- }
- }
-
- kUtil::includeOnce(FULL_PATH.$this->Files[$real_class]);
+ if ( !$pseudo_class ) {
+ $pseudo_class = $ret['prefix'];
}
- /**
- * Get's real class name for pseudo class,
- * includes class file and creates class
- * instance.
- * All parameters except first one are passed to object constuctor
- * through mediator method makeClass that creates instance of class
- *
- * Pattern: Factory Method
- *
- * @param string $pseudo_class
- * @param Array $arguments
- * @return kBase
- * @access public
- */
- public function &makeClass($pseudo_class, $arguments = Array ())
- {
- $real_class = $this->realClasses[$pseudo_class];
-
- if ( !class_exists($real_class) ) {
- $this->includeClassFile($real_class, $pseudo_class);
- }
-
- $mem_before = memory_get_usage();
- $time_before = microtime(true);
+ if ( !isset($this->realClasses[$pseudo_class]) ) {
+ $error_msg = 'RealClass not defined for pseudo_class <strong>' . $pseudo_class . '</strong>';
- if ( !is_array($arguments) ) {
- // fallback for code, that doesn't know how to pass arguments
- $arguments = Array ($arguments);
- }
-
- if (!$arguments) {
- $class = new $real_class();
+ if ( $this->Application->isInstalled() ) {
+ throw new Exception($error_msg);
}
else {
- $reflection = new ReflectionClass($real_class);
- $class = $reflection->newInstanceArgs($arguments);
- }
-
- if ( defined('DEBUG_MODE') && DEBUG_MODE && defined('DBG_PROFILE_MEMORY') && DBG_PROFILE_MEMORY && $this->Application->isDebugMode() ) {
- $mem_after = memory_get_usage();
- $time_after = microtime(true);
- $mem_used = $mem_after - $mem_before;
- $time_used = $time_after - $time_before;
+ if ( $this->Application->isDebugMode() ) {
+ $this->Application->Debugger->appendTrace();
+ }
- $this->Application->Debugger->appendHTML('Factroy created <b>'.$real_class.'</b> - used '.round($mem_used/1024, 3).'Kb time: '.round($time_used, 5));
- $this->Application->Debugger->profilerAddTotal('objects', null, $mem_used);
+ trigger_error($error_msg, E_USER_WARNING);
}
- return $class;
+ $false = false;
+ return $false;
}
- /**
- * Registers new class in the factory
- *
- * @param string $real_class Real name of class as in class declaration
- * @param string $file Filename in what $real_class is declared
- * @param string $pseudo_class Name under this class object will be accessed using getObject method
- * @param Array $dependecies List of classes required for this class functioning
- * @access public
- */
- function registerClass($real_class, $file, $pseudo_class=null, $dependecies = Array() )
- {
- if ( !isset($pseudo_class) ) {
- $pseudo_class = $real_class;
- }
+ if ( defined('DEBUG_MODE') && defined('DBG_FACTORY') && DBG_FACTORY && $this->Application->isDebugMode() ) {
+ $this->Application->Debugger->appendHTML('<b>Creating object:</b> Pseudo class: ' . $pseudo_class . ' Prefix: ' . $name);
+ $this->Application->Debugger->appendTrace();
+ }
- if ( !isset($this->Files[$real_class]) ) {
- $this->Files[$real_class] = preg_replace('/^'.preg_quote(FULL_PATH, '/').'/', '', $file, 1);
- }
+ $this->Storage[$name] =& $this->makeClass($pseudo_class, $arguments);
+ $this->Storage[$name]->Init($ret['prefix'], $ret['special']);
+ $this->Application->EventManager->runBuildEvent($ret['prefix_special'], $pseudo_class, $event_params);
+
+ return $this->Storage[$name];
+ }
+
+ /**
+ * Removes object from storage, so next time it could be created from scratch
+ *
+ * @param string $name Object's name in the Storage
+ * @return void
+ * @access public
+ */
+ public function DestroyObject($name)
+ {
+ unset($this->Storage[$name]);
+ }
+
+ /**
+ * Checks if object with prefix passes was already created in factory
+ *
+ * @param string $name object pseudo_class, prefix
+ * @return bool
+ * @access public
+ */
+ public function hasObject($name)
+ {
+ return isset($this->Storage[$name]);
+ }
+
+ /**
+ * Get's real class name for pseudo class,
+ * includes class file and creates class
+ * instance.
+ * All parameters except first one are passed to object constuctor
+ * through mediator method makeClass that creates instance of class
+ *
+ * Pattern: Factory Method
+ *
+ * @param string $pseudo_class
+ * @param Array $arguments
+ * @return kBase
+ * @access public
+ */
+ public function &makeClass($pseudo_class, $arguments = Array ())
+ {
+ $real_class = $this->realClasses[$pseudo_class];
- if ( isset($this->realClasses[$pseudo_class]) ) {
- $this->registerDependency($real_class, $pseudo_class);
- }
+ $mem_before = memory_get_usage();
+ $time_before = microtime(true);
- if ($dependecies) {
- if ( !is_array($dependecies) ) {
- $dependecies = Array ($dependecies);
- }
+ $arguments = (array)$arguments;
- foreach ($dependecies as $required_class) {
- $this->registerDependency($real_class, $required_class);
- }
- }
-
- $this->realClasses[$pseudo_class] = $real_class;
+ if ( !$arguments ) {
+ $class = new $real_class();
+ }
+ else {
+ $reflection = new ReflectionClass($real_class);
+ $class = $reflection->newInstanceArgs($arguments);
}
- /**
- * Unregisters existing class from factory
- *
- * @param string $real_class Real name of class as in class declaration
- * @param string $pseudo_class Name under this class object is accessed using getObject method
- */
- function unregisterClass($real_class, $pseudo_class = null)
- {
- if ( !isset($pseudo_class) ) {
- $pseudo_class = $real_class;
- }
+ if ( defined('DEBUG_MODE') && DEBUG_MODE && defined('DBG_PROFILE_MEMORY') && DBG_PROFILE_MEMORY && $this->Application->isDebugMode() ) {
+ $mem_after = memory_get_usage();
+ $time_after = microtime(true);
+ $mem_used = $mem_after - $mem_before;
+ $time_used = $time_after - $time_before;
- unset($this->Files[$real_class]);
+ $this->Application->Debugger->appendHTML('Factroy created <b>' . $real_class . '</b> - used ' . round($mem_used / 1024, 3) . 'Kb time: ' . round($time_used, 5));
+ $this->Application->Debugger->profilerAddTotal('objects', null, $mem_used);
+ }
- if ( !array_key_exists($real_class, $this->Dependencies) ) {
- return ;
- }
+ return $class;
+ }
- $this->realClasses[$pseudo_class] = $this->Dependencies[$real_class][0];
- unset( $this->Dependencies[$real_class] );
+ /**
+ * Registers new class in the factory
+ *
+ * @param string $real_class Real name of class as in class declaration
+ * @param string $file Filename in what $real_class is declared
+ * @param string $pseudo_class Name under this class object will be accessed using getObject method
+ * @return void
+ * @access public
+ */
+ public function registerClass($real_class, $file, $pseudo_class = null)
+ {
+ if ( !isset($pseudo_class) ) {
+ $pseudo_class = $real_class;
}
- /**
- * Add $class_name to required classes list for $depended_class class.
- * All required class files are included before $depended_class file is included
- *
- * @param string $depended_class
- * @param string $class_name
- * @author Alex
- */
- function registerDependency($depended_class, $class_name)
- {
- if ($this->realClasses[$class_name] == $depended_class) {
- // same class
- return ;
- }
+ if ( !isset($this->Files[$real_class]) ) {
+ $this->Files[$real_class] = preg_replace('/^' . preg_quote(FULL_PATH, '/') . '/', '', $file, 1);
+ }
- $dependencies =& $this->Dependencies[$depended_class];
- $dependency_exists = is_array($dependencies) && in_array($this->realClasses[$class_name], $dependencies);
+ $this->realClasses[$pseudo_class] = $real_class;
+ }
- if ( !$dependency_exists ) {
- $dependencies[] = $this->realClasses[$class_name];
- }
- }
- }
\ No newline at end of file
+ /**
+ * Unregisters existing class from factory
+ *
+ * @param string $real_class Real name of class as in class declaration
+ * @param string $pseudo_class Name under this class object is accessed using getObject method
+ * @return void
+ * @access public
+ */
+ public function unregisterClass($real_class, $pseudo_class = null)
+ {
+ unset($this->Files[$real_class]);
+ }
+}
\ No newline at end of file
Index: branches/5.2.x/core/kernel/utility/debugger.php
===================================================================
--- branches/5.2.x/core/kernel/utility/debugger.php (revision 15129)
+++ branches/5.2.x/core/kernel/utility/debugger.php (revision 15130)
@@ -1,1940 +1,1952 @@
<?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!');
if( !class_exists('Debugger') ) {
/**
* Contains misc functions, used by debugger (mostly copied from kUtil class)
*/
class DebuggerUtil {
/**
* Checks if constant is defined and has positive value
*
* @param string $const_name
* @return bool
*/
public static function constOn($const_name)
{
return defined($const_name) && constant($const_name);
}
/**
* Define constant if it was not already defined before
*
* @param string $const_name
* @param string $const_value
* @access public
*/
public static function safeDefine($const_name, $const_value)
{
if ( !defined($const_name) ) {
define($const_name, $const_value);
}
}
/**
* Formats file/memory size in nice way
*
* @param int $bytes
* @return string
* @access public
*/
public static function formatSize($bytes)
{
if ($bytes >= 1099511627776) {
$return = round($bytes / 1024 / 1024 / 1024 / 1024, 2);
$suffix = "TB";
} elseif ($bytes >= 1073741824) {
$return = round($bytes / 1024 / 1024 / 1024, 2);
$suffix = "GB";
} elseif ($bytes >= 1048576) {
$return = round($bytes / 1024 / 1024, 2);
$suffix = "MB";
} elseif ($bytes >= 1024) {
$return = round($bytes / 1024, 2);
$suffix = "KB";
} else {
$return = $bytes;
$suffix = "Byte";
}
$return .= ' '.$suffix;
return $return;
}
/**
* Checks, that user IP address is within allowed range
*
* @param string $ip_list semi-column (by default) separated ip address list
* @param string $separator ip address separator (default ";")
*
* @return bool
*/
public static function ipMatch($ip_list, $separator = ';')
{
if ( !isset($_SERVER['REMOTE_ADDR']) ) {
// PHP CLI used -> never match
return false;
}
$ip_match = false;
$ip_addresses = $ip_list ? explode($separator, $ip_list) : Array ();
foreach ($ip_addresses as $ip_address) {
if (self::netMatch($ip_address, $_SERVER['REMOTE_ADDR'])) {
$ip_match = true;
break;
}
}
return $ip_match;
}
/**
* Checks, that given ip belongs to given subnet
*
* @param string $network
* @param string $ip
* @return bool
* @access public
*/
public static function netMatch($network, $ip) {
$network = trim($network);
$ip = trim($ip);
if ( preg_replace('/[\d\.\/-]/', '', $network) != '' ) {
$network = gethostbyname($network);
}
if ($network == $ip) {
// comparing two ip addresses directly
return true;
}
$d = strpos($network, '-');
if ($d !== false) {
// ip address range specified
$from = ip2long(trim(substr($network, 0, $d)));
$to = ip2long(trim(substr($network, $d + 1)));
$ip = ip2long($ip);
return ($ip >= $from && $ip <= $to);
}
elseif (strpos($network, '/') !== false) {
// single subnet specified
$ip_arr = explode('/', $network);
if (!preg_match("@\d*\.\d*\.\d*\.\d*@", $ip_arr[0], $matches)) {
$ip_arr[0] .= '.0'; // Alternate form 194.1.4/24
}
$network_long = ip2long($ip_arr[0]);
$x = ip2long($ip_arr[1]);
$mask = long2ip($x) == $ip_arr[1] ? $x : (0xffffffff << (32 - $ip_arr[1]));
$ip_long = ip2long($ip);
return ($ip_long & $mask) == ($network_long & $mask);
}
return false;
}
}
/**
* Main debugger class, that can be used with any In-Portal (or not) project
*/
class Debugger {
/**
* Holds reference to global KernelApplication instance
*
* @var kApplication
* @access private
*/
private $Application = null;
/**
* Set to true if fatal error occurred
*
* @var bool
* @access private
*/
private $IsFatalError = false;
/**
* Counts warnings on the page
*
* @var int
* @access public
*/
public $WarningCount = 0;
/**
* Allows to track compile errors, like "stack-overflow"
*
* @var bool
* @access private
*/
private $_compileError = false;
/**
* Debugger data for building report
*
* @var Array
* @access private
*/
private $Data = Array ();
/**
* Holds information about each profiler record (start/end/description)
*
* @var Array
* @access private
*/
private $ProfilerData = Array ();
/**
* Holds information about total execution time per profiler key (e.g. total sql time)
*
* @var Array
* @access private
*/
private $ProfilerTotals = Array ();
/**
* Counts how much each of total types were called (e.g. total error count)
*
* @var Array
* @access private
*/
private $ProfilerTotalCount = Array ();
/**
* Holds information about all profile points registered
*
* @var Array
* @access private
*/
private $ProfilePoints = Array ();
/**
* Prevent recursion when processing debug_backtrace() function results
*
* @var Array
* @access private
*/
private $RecursionStack = Array ();
/**
* Cross browser debugger report scrollbar width detection
*
* @var int
* @access private
*/
private $scrollbarWidth = 0;
/**
* Long errors are saved here, because trigger_error doesn't support error messages over 1KB in size
*
* @var Array
* @access private
*/
private $longErrors = Array ();
/**
* Remembers how much memory & time was spent on including files
*
* @var Array
* @access public
* @see kUtil::includeOnce
*/
public $IncludesData = Array ();
/**
* Remembers maximal include deep level
*
* @var int
* @access public
* @see kUtil::includeOnce
*/
public $IncludeLevel = 0;
/**
* Prevents report generation more then once
*
* @var bool
* @access private
*/
private $reportDone = false;
/**
* Transparent spacer image used in case of none spacer image defined via SPACER_URL constant.
* Used while drawing progress bars (memory usage, time usage, etc.)
*
* @var string
* @access private
*/
private $dummyImage = '';
/**
* Temporary files created by debugger will be stored here
*
* @var string
* @access private
*/
private $tempFolder = '';
/**
* Debug rows will be separated using this string before writing to debug file
*
* @var string
* @access private
*/
private $rowSeparator = '@@';
/**
* Base URL for debugger includes
*
* @var string
* @access private
*/
private $baseURL = '';
/**
* Sub-folder, where In-Portal is installed
*
* @var string
* @access private
*/
private $basePath = '';
/**
* Holds last recorded timestamp (for appendTimestamp)
*
* @var int
* @access private
*/
private $LastMoment;
/**
* Determines, that current request is AJAX request
*
* @var bool
* @access private
*/
private $_isAjax = false;
/**
* Creates instance of debugger
*/
public function __construct()
{
global $start, $dbg_options;
// check if user haven't defined DEBUG_MODE contant directly
if ( defined('DEBUG_MODE') && DEBUG_MODE ) {
die('error: constant DEBUG_MODE defined directly, please use <strong>$dbg_options</strong> array instead');
}
// check IP before enabling debug mode
$ip_match = DebuggerUtil::ipMatch(isset($dbg_options['DBG_IP']) ? $dbg_options['DBG_IP'] : '');
if ( !$ip_match || (isset($_COOKIE['debug_off']) && $_COOKIE['debug_off']) ) {
define('DEBUG_MODE', 0);
return;
}
// debug is allowed for user, continue initialization
$this->InitDebugger();
$this->profileStart('kernel4_startup', 'Startup and Initialization of kernel4', $start);
$this->profileStart('script_runtime', 'Script runtime', $start);
$this->LastMoment = $start;
error_reporting(E_ALL);
// show errors on screen in case if not in Zend Studio debugging
ini_set('display_errors', DebuggerUtil::constOn('DBG_ZEND_PRESENT') ? 0 : 1);
// vertical scrollbar width differs in Firefox and other browsers
$this->scrollbarWidth = $this->isGecko() ? 22 : 25;
$this->appendRequest();
}
/**
* Set's default values to constants debugger uses
*
*/
function InitDebugger()
{
global $dbg_options;
unset($dbg_options['DBG_IP']);
// Detect fact, that this session being debugged by Zend Studio
foreach ($_COOKIE as $cookie_name => $cookie_value) {
if (substr($cookie_name, 0, 6) == 'debug_') {
DebuggerUtil::safeDefine('DBG_ZEND_PRESENT', 1);
break;
}
}
DebuggerUtil::safeDefine('DBG_ZEND_PRESENT', 0); // set this constant value to 0 (zero) to debug debugger using Zend Studio
// set default values for debugger constants
$dbg_constMap = Array (
'DBG_USE_HIGHLIGHT' => 1, // highlight output same as php code using "highlight_string" function
'DBG_WINDOW_WIDTH' => 700, // set width of debugger window (in pixels) for better viewing large amount of debug data
'DBG_USE_SHUTDOWN_FUNC' => DBG_ZEND_PRESENT ? 0 : 1, // use shutdown function to include debugger code into output
'DBG_HANDLE_ERRORS' => DBG_ZEND_PRESENT ? 0 : 1, // handle all allowed by php (see php manual) errors instead of default handler
'DBG_IGNORE_STRICT_ERRORS' => 0, // ignore PHP5 errors about private/public view modified missing in class declarations
'DBG_DOMVIEWER' => '/temp/domviewer.html', // path to DOMViewer on website
'DOC_ROOT' => str_replace('\\', '/', realpath($_SERVER['DOCUMENT_ROOT']) ), // windows hack
'DBG_LOCAL_BASE_PATH' => 'w:', // replace DOC_ROOT in filenames (in errors) using this path
);
// only for IE, in case if no windows php script editor defined
if (!defined('DBG_EDITOR')) {
// $dbg_constMap['DBG_EDITOR'] = 'c:\Program Files\UltraEdit\uedit32.exe %F/%L';
$dbg_constMap['DBG_EDITOR'] = 'c:\Program Files\Zend\ZendStudio-5.2.0\bin\ZDE.exe %F';
}
// debugger is initialized before kHTTPQuery, so do jQuery headers check here too
if (array_key_exists('HTTP_X_REQUESTED_WITH', $_SERVER) && $_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest') {
$this->_isAjax = true;
}
elseif (array_key_exists('ajax', $_GET) && $_GET['ajax'] == 'yes') {
$this->_isAjax = true;
}
// user defined options override debugger defaults
$dbg_constMap = array_merge($dbg_constMap, $dbg_options);
if ($this->_isAjax && array_key_exists('DBG_SKIP_AJAX', $dbg_constMap) && $dbg_constMap['DBG_SKIP_AJAX']) {
$dbg_constMap['DBG_SKIP_REPORTING'] = 1;
}
// allows to validate unit configs via request variable
if ( !array_key_exists('DBG_VALIDATE_CONFIGS', $dbg_constMap) ) {
$dbg_constMap['DBG_VALIDATE_CONFIGS'] = array_key_exists('validate_configs', $_GET) ? (int)$_GET['validate_configs'] : 0;
}
// when validation configs, don't show sqls for better validation error displaying
if ($dbg_constMap['DBG_VALIDATE_CONFIGS']) {
$dbg_constMap['DBG_SQL_PROFILE'] = 0;
}
// when showing explain make shure, that debugger window is large enough
if (array_key_exists('DBG_SQL_EXPLAIN', $dbg_constMap) && $dbg_constMap['DBG_SQL_EXPLAIN']) {
$dbg_constMap['DBG_WINDOW_WIDTH'] = 1000;
}
foreach ($dbg_constMap as $dbg_constName => $dbg_constValue) {
DebuggerUtil::safeDefine($dbg_constName, $dbg_constValue);
}
}
/**
* Performs debugger initialization
*
* @return void
*/
private function InitReport()
{
if ( !class_exists('kApplication') ) {
return;
}
$application =& kApplication::Instance();
// string used to separate debugger records while in file (used in debugger dump filename too)
$this->rowSeparator = '@' . (/*is_object($application->Factory) &&*/ $application->InitDone ? $application->GetSID() : 0) . '@';
// $this->rowSeparator = '@' . rand(0, 100000) . '@';
// include debugger files from this url
$reg_exp = '/^' . preg_quote(FULL_PATH, '/') . '/';
$kernel_path = preg_replace($reg_exp, '', KERNEL_PATH, 1);
$this->baseURL = PROTOCOL . SERVER_NAME . (defined('PORT') ? ':' . PORT : '') . rtrim(BASE_PATH, '/') . $kernel_path . '/utility/debugger';
// store debugger cookies at this path
$this->basePath = rtrim(BASE_PATH, '/');
// save debug output in this folder
$this->tempFolder = defined('RESTRICTED') ? RESTRICTED : WRITEABLE . '/cache';
}
/**
* Allows to overcome short error message problem in tigger_error function
*
* @param string $msg
* @return int
* @access public
*/
public function mapLongError($msg)
{
$key = $this->generateID();
$this->longErrors[$key] = $msg;
return $key;
}
/**
* Appends all passed variable values (without variable names) to debug output
*
* @return void
* @access public
*/
public function dumpVars()
{
$dump_mode = 'var_dump';
$dumpVars = func_get_args();
if ( $dumpVars[count($dumpVars) - 1] === 'STRICT' ) {
$dump_mode = 'strict_var_dump';
array_pop($dumpVars);
}
foreach ($dumpVars as $varValue) {
$this->Data[] = Array ('value' => $varValue, 'debug_type' => $dump_mode);
}
}
/**
* Transforms collected data at given index into human-readable HTML to place in debugger report
*
* @param int $dataIndex
* @return string
* @access private
*/
private function prepareHTML($dataIndex)
{
static $errors_displayed = 0;
$Data =& $this->Data[$dataIndex];
if ( $Data['debug_type'] == 'html' ) {
return $Data['html'];
}
switch ($Data['debug_type']) {
case 'error':
$errors_displayed++;
$fileLink = $this->getFileLink($Data['file'], $Data['line']);
$ret = '<b class="debug_error">' . $this->getErrorNameByCode($Data['no']) . ' (#' . $errors_displayed . ')</b>: ' . $Data['str'];
$ret .= ' in <b>' . $fileLink . '</b> on line <b>' . $Data['line'] . '</b>';
return $ret;
break;
case 'exception':
$fileLink = $this->getFileLink($Data['file'], $Data['line']);
$ret = '<b class="debug_error">' . $Data['exception_class'] . '</b>: ' . $Data['str'];
$ret .= ' in <b>' . $fileLink . '</b> on line <b>' . $Data['line'] . '</b>';
return $ret;
break;
case 'var_dump':
return $this->highlightString($this->print_r($Data['value'], true));
break;
case 'strict_var_dump':
return $this->highlightString(var_export($Data['value'], true));
break;
case 'trace':
ini_set('memory_limit', '500M');
$trace =& $Data['trace'];
$i = 0;
$traceCount = count($trace);
$ret = '';
while ( $i < $traceCount ) {
$traceRec =& $trace[$i];
$argsID = 'trace_args_' . $dataIndex . '_' . $i;
$has_args = isset($traceRec['args']);
if ( isset($traceRec['file']) ) {
$func_name = isset($traceRec['class']) ? $traceRec['class'] . $traceRec['type'] . $traceRec['function'] : $traceRec['function'];
$args_link = $has_args ? '<a href="javascript:$Debugger.ToggleTraceArgs(\'' . $argsID . '\');" title="Show/Hide Function Arguments"><b>Function</b></a>' : '<strong>Function</strong>';
$ret .= $args_link . ': ' . $this->getFileLink($traceRec['file'], $traceRec['line'], $func_name);
$ret .= ' in <b>' . basename($traceRec['file']) . '</b> on line <b>' . $traceRec['line'] . '</b><br>';
}
else {
$ret .= 'no file information available';
}
if ( $has_args ) {
// if parameter value is longer then 200 symbols, then leave only first 50
$args = $this->highlightString($this->print_r($traceRec['args'], true));
$ret .= '<div id="' . $argsID . '" style="display: none;">' . $args . '</div>';
}
$i++;
}
return $ret;
break;
case 'profiler':
$profileKey = $Data['profile_key'];
$Data =& $this->ProfilerData[$profileKey];
$runtime = ($Data['ends'] - $Data['begins']); // in seconds
$totals_key = getArrayValue($Data, 'totalsKey');
if ( $totals_key ) {
$total_before = $Data['totalsBefore'];
$total = $this->ProfilerTotals[$totals_key];
$div_width = Array ();
$total_width = ($this->getWindowWidth() - 10);
$div_width['before'] = round(($total_before / $total) * $total_width);
$div_width['current'] = round(($runtime / $total) * $total_width);
$div_width['left'] = round((($total - $total_before - $runtime) / $total) * $total_width);
$subtitle = array_key_exists('subtitle', $Data) ? ' (' . $Data['subtitle'] . ')' : '';
$ret = '<b>Name' . $subtitle . '</b>: ' . $Data['description'] . '<br />';
$additional = isset($Data['additional']) ? $Data['additional'] : Array ();
if ( isset($Data['file']) ) {
array_unshift($additional, Array ('name' => 'File', 'value' => $this->getFileLink($Data['file'], $Data['line'], basename($Data['file']) . ':' . $Data['line'])));
}
array_unshift($additional, Array ('name' => 'Runtime', 'value' => $runtime . 's'));
$ret .= '<div>'; //FF 3.5 needs this!
foreach ($additional as $mixed_param) {
$ret .= '[<strong>' . $mixed_param['name'] . '</strong>: ' . $mixed_param['value'] . '] ';
}
/*if ( isset($Data['file']) ) {
$ret .= '[<b>Runtime</b>: ' . $runtime . 's] [<b>File</b>: ' . $this->getFileLink($Data['file'], $Data['line'], basename($Data['file']) . ':' . $Data['line']) . ']<br />';
}
else {
$ret .= '<b>Runtime</b>: ' . $runtime . 's<br />';
}*/
$ret .= '</div>';
$ret .= '<div class="dbg_profiler" style="width: ' . $div_width['before'] . 'px; border-right: 0px; background-color: #298DDF;"><img src="' . $this->dummyImage . '" width="1" height="1"/></div>';
$ret .= '<div class="dbg_profiler" style="width: ' . $div_width['current'] . 'px; border-left: 0px; border-right: 0px; background-color: #EF4A4A;"><img src="' . $this->dummyImage . '" width="1" height="1"/></div>';
$ret .= '<div class="dbg_profiler" style="width: ' . $div_width['left'] . 'px; border-left: 0px; background-color: #DFDFDF;"><img src="' . $this->dummyImage . '" width="1" height="1"/></div>';
return $ret;
}
else {
return '<b>Name</b>: ' . $Data['description'] . '<br><b>Runtime</b>: ' . $runtime . 's';
}
break;
default:
return 'incorrect debug data';
break;
}
}
/**
* Returns debugger report window width excluding scrollbar
*
* @return int
* @access private
*/
private function getWindowWidth()
{
return DBG_WINDOW_WIDTH - $this->scrollbarWidth - 8;
}
/**
* Tells debugger to skip objects that are heavy in plan of memory usage while printing debug_backtrace results
*
* @param Object $object
* @return bool
* @access private
*/
private function IsBigObject(&$object)
{
$skip_classes = Array(
defined('APPLICATION_CLASS') ? APPLICATION_CLASS : 'kApplication',
'kFactory',
'kUnitConfigReader',
'NParser',
);
foreach ($skip_classes as $class_name) {
if ( strtolower(get_class($object)) == strtolower($class_name) ) {
return true;
}
}
return false;
}
/**
* Advanced version of print_r (for debugger only). Don't print objects recursively
*
* @param Array $array
* @param bool $return_output return output or print it out
* @param int $tab_count offset in tabs
* @return string
* @access private
*/
private function print_r(&$array, $return_output = false, $tab_count = -1)
{
static $first_line = true;
// not an array at all
if ( !is_array($array) ) {
switch ( gettype($array) ) {
case 'NULL':
return 'NULL' . "\n";
break;
case 'object':
return $this->processObject($array, $tab_count);
break;
default:
// number or string
if ( strlen($array) > 200 ) {
$array = substr($array, 0, 50) . ' ...';
}
return $array . "\n";
break;
}
}
$output = '';
$tab_count++;
$output .= "Array\n" . str_repeat(' ', $tab_count) . "(\n";
$tab_count++;
$tabsign = $tab_count ? str_repeat(' ', $tab_count) : '';
$array_keys = array_keys($array);
foreach ($array_keys as $key) {
switch ( gettype($array[$key]) ) {
case 'array':
$output .= $tabsign . '[' . $key . '] = ' . $this->print_r($array[$key], true, $tab_count);
break;
case 'boolean':
$output .= $tabsign . '[' . $key . '] = ' . ($array[$key] ? 'true' : 'false') . "\n";
break;
case 'integer':
case 'double':
case 'string':
if ( strlen($array[$key]) > 200 ) {
$array[$key] = substr($array[$key], 0, 50) . ' ...';
}
$output .= $tabsign . '[' . $key . '] = ' . $array[$key] . "\n";
break;
case 'NULL':
$output .= $tabsign . '[' . $key . "] = NULL\n";
break;
case 'object':
$output .= $tabsign . '[' . $key . "] = ";
$output .= "Object (" . get_class($array[$key]) . ") = \n" . str_repeat(' ', $tab_count + 1) . "(\n";
$output .= $this->processObject($array[$key], $tab_count + 2);
$output .= str_repeat(' ', $tab_count + 1) . ")\n";
break;
default:
$output .= $tabsign . '[' . $key . '] unknown = ' . gettype($array[$key]) . "\n";
break;
}
}
$tab_count--;
$output .= str_repeat(' ', $tab_count) . ")\n";
if ( $first_line ) {
$first_line = false;
$output .= "\n";
}
$tab_count--;
if ( $return_output ) {
return $output;
}
else {
echo $output;
}
return true;
}
/**
* Returns string representation of given object (more like print_r, but with recursion prevention check)
*
* @param Object $object
* @param int $tab_count
* @return string
* @access private
*/
private function processObject(&$object, $tab_count)
{
$object_class = get_class($object);
if ( !in_array($object_class, $this->RecursionStack) ) {
if ( $this->IsBigObject($object) ) {
return 'SKIPPED (class: ' . $object_class . ")\n";
}
$attribute_names = get_class_vars($object_class);
if ( !$attribute_names ) {
return "NO_ATTRIBUTES\n";
}
else {
$output = '';
array_push($this->RecursionStack, $object_class);
$tabsign = $tab_count ? str_repeat(' ', $tab_count) : '';
foreach ($attribute_names as $attribute_name => $attribute_value) {
if ( is_object($object->$attribute_name) ) {
// it is object
$output .= $tabsign . '[' . $attribute_name . '] = ' . $this->processObject($object->$attribute_name, $tab_count + 1);
}
else {
$output .= $tabsign . '[' . $attribute_name . '] = ' . $this->print_r($object->$attribute_name, true, $tab_count);
}
}
array_pop($this->RecursionStack);
return $output;
}
}
else {
// object [in recursion stack]
return '*** RECURSION *** (class: ' . $object_class . ")\n";
}
}
/**
* Format SQL Query using predefined formatting
* and highlighting techniques
*
* @param string $sql
* @return string
* @access public
*/
public function formatSQL($sql)
{
$sql = trim(preg_replace('/(\n|\t| )+/is', ' ', $sql));
// whitespace in the beginning of the regex is to avoid splitting inside words, for example "FROM int_ConfigurationValues" into "FROM intConfiguration\n\tValues"
$formatted_sql = preg_replace('/\s(CREATE TABLE|DROP TABLE|SELECT|UPDATE|SET|REPLACE|INSERT|DELETE|VALUES|FROM|LEFT JOIN|INNER JOIN|LIMIT|WHERE|HAVING|GROUP BY|ORDER BY)\s/is', "\n\t$1 ", ' ' . $sql);
$formatted_sql = $this->highlightString($formatted_sql);
if ( defined('DBG_SQL_EXPLAIN') && DBG_SQL_EXPLAIN ) {
if ( substr($sql, 0, 6) == 'SELECT' ) {
$formatted_sql .= '<br/>' . '<strong>Explain</strong>:<br /><br />';
$explain_result = $this->Application->Conn->Query('EXPLAIN ' . $sql, null, true);
$explain_table = '';
foreach ($explain_result as $explain_row) {
if ( !$explain_table ) {
// first row -> draw header
$explain_table .= '<tr class="explain_header"><td>' . implode('</td><td>', array_keys($explain_row)) . '</td></tr>';
}
$explain_table .= '<tr><td>' . implode('</td><td>', $explain_row) . '</td></tr>';
}
$formatted_sql .= '<table class="dbg_explain_table">' . $explain_table . '</table>';
}
}
return $formatted_sql;
}
/**
* Highlights given string using "highlight_string" method
*
* @param string $string
* @return string
* @access public
*/
public function highlightString($string)
{
if ( !(defined('DBG_USE_HIGHLIGHT') && DBG_USE_HIGHLIGHT) || $this->_compileError ) {
return nl2br($string);
}
$string = str_replace(Array ('\\', '/'), Array ('_no_match_string_', '_n_m_s_'), $string);
$this->_compileError = true; // next line is possible cause of compile error
$string = highlight_string('<?php ' . $string . ' ?>', true);
$this->_compileError = false;
$string = str_replace(Array ('_no_match_string_', '_n_m_s_'), Array ('\\', '/'), $string);
if ( strlen($string) >= 65536 ) {
// preg_replace will fail, when string is longer, then 65KB
return str_replace(Array ('&lt;?php&nbsp;', '?&gt;'), '', $string);
}
return preg_replace('/&lt;\?(.*)php&nbsp;(.*)\?&gt;/Us', '\\2', $string);
}
/**
* Determine by php type of browser used to show debugger
*
* @return bool
* @access private
*/
private function isGecko()
{
// we need isset because we may run scripts from shell with no user_agent at all
return isset($_SERVER['HTTP_USER_AGENT']) && strpos(strtolower($_SERVER['HTTP_USER_AGENT']), 'firefox') !== false;
}
/**
* Returns link for editing php file (from error) in external editor
*
* @param string $file filename with path from root folder
* @param int $lineno line number in file where error is found
* @param string $title text to show on file edit link
* @return string
* @access public
*/
public function getFileLink($file, $lineno = 1, $title = '')
{
if ( !$title ) {
$title = str_replace('/', '\\', $this->getLocalFile($file));
}
if ( $this->isGecko() ) {
return '<a href="file://' . $this->getLocalFile($file) . '">' . $title . '</a>';
}
else {
return '<a href="javascript:$Debugger.editFile(\'' . $this->getLocalFile($file) . '\', ' . $lineno . ');" title="' . $file . '">' . $title . '</a>';
}
}
/**
* Converts filepath on server to filepath in mapped DocumentRoot on developer pc
*
* @param string $remoteFile
* @return string
* @access private
*/
private function getLocalFile($remoteFile)
{
return preg_replace('/^' . preg_quote(DOC_ROOT, '/') . '/', DBG_LOCAL_BASE_PATH, $remoteFile, 1);
}
/**
* Appends call trace till this method call
*
* @param int $levels_to_shift
* @return void
* @access public
*/
public function appendTrace($levels_to_shift = 1)
{
$levels_shifted = 0;
$trace = debug_backtrace();
while ( $levels_shifted < $levels_to_shift ) {
array_shift($trace);
$levels_shifted++;
}
$this->Data[] = Array ('trace' => $trace, 'debug_type' => 'trace');
}
/**
* Appends call trace till this method call
*
* @param Exception $exception
* @return void
* @access private
*/
private function appendExceptionTrace(&$exception)
{
$trace = $exception->getTrace();
$this->Data[] = Array('trace' => $trace, 'debug_type' => 'trace');
}
/**
* Adds memory usage statistics
*
* @param string $msg
* @param int $used
* @return void
* @access public
*/
public function appendMemoryUsage($msg, $used = null)
{
if ( !isset($used) ) {
$used = round(memory_get_usage() / 1024);
}
$this->appendHTML('<b>Memory usage</b> ' . $msg . ' ' . $used . 'Kb');
}
/**
* Appends HTML code without transformations
*
* @param string $html
* @return void
* @access public
*/
public function appendHTML($html)
{
$this->Data[] = Array ('html' => $html, 'debug_type' => 'html');
}
/**
* Change debugger info that was already generated before.
* Returns true if html was set.
*
* @param int $index
* @param string $html
* @param string $type = {'append','prepend','replace'}
* @return bool
* @access public
*/
public function setHTMLByIndex($index, $html, $type = 'append')
{
if ( !isset($this->Data[$index]) || $this->Data[$index]['debug_type'] != 'html' ) {
return false;
}
switch ( $type ) {
case 'append':
$this->Data[$index]['html'] .= '<br>' . $html;
break;
case 'prepend':
$this->Data[$index]['html'] = $this->Data[$index]['html'] . '<br>' . $html;
break;
case 'replace':
$this->Data[$index]['html'] = $html;
break;
}
return true;
}
/**
* Move $debugLineCount lines of input from debug output
* end to beginning.
*
* @param int $debugLineCount
* @return void
* @access private
*/
private function moveToBegin($debugLineCount)
{
$lines = array_splice($this->Data, count($this->Data) - $debugLineCount, $debugLineCount);
$this->Data = array_merge($lines, $this->Data);
}
/**
* Moves all debugger report lines after $debugLineCount into $new_row position
*
* @param int $new_row
* @param int $debugLineCount
* @return void
* @access private
*/
private function moveAfterRow($new_row, $debugLineCount)
{
$lines = array_splice($this->Data, count($this->Data) - $debugLineCount, $debugLineCount);
$rows_before = array_splice($this->Data, 0, $new_row, $lines);
$this->Data = array_merge($rows_before, $this->Data);
}
/**
* Appends HTTP REQUEST information to debugger report
*
* @return void
* @access private
*/
private function appendRequest()
{
if ( isset($_SERVER['SCRIPT_FILENAME']) ) {
$script = $_SERVER['SCRIPT_FILENAME'];
}
else {
$script = $_SERVER['DOCUMENT_ROOT'] . $_SERVER['PHP_SELF'];
}
$this->appendHTML('ScriptName: <b>' . $this->getFileLink($script, 1, basename($script)) . '</b> (<b>' . dirname($script) . '</b>)');
if ( $this->_isAjax ) {
$this->appendHTML('RequestURI: ' . $_SERVER['REQUEST_URI'] . ' (QS Length:' . strlen($_SERVER['QUERY_STRING']) . ')');
}
$tools_html = ' <table style="width: ' . $this->getWindowWidth() . 'px;">
<tr>
<td>' . $this->_getDomViewerHTML() . '</td>
<td>' . $this->_getToolsHTML() . '</td>
</tr>
</table>';
$this->appendHTML($tools_html);
ob_start();
?>
<table border="0" cellspacing="0" cellpadding="0" class="dbg_flat_table" style="width: <?php echo $this->getWindowWidth(); ?>px;">
<thead style="font-weight: bold;">
<td width="20">Src</td><td>Name</td><td>Value</td>
</thead>
<?php
foreach ($_REQUEST as $key => $value) {
if ( !is_array($value) && trim($value) == '' ) {
$value = '<b class="debug_error">no value</b>';
}
else {
$value = htmlspecialchars($this->print_r($value, true));
}
$in_cookie = isset($_COOKIE[$key]);
$src = isset($_GET[$key]) && !$in_cookie ? 'GE' : (isset($_POST[$key]) && !$in_cookie ? 'PO' : ($in_cookie ? 'CO' : '?'));
echo '<tr><td>' . $src . '</td><td>' . $key . '</td><td>' . $value . '</td></tr>';
}
?>
</table>
<?php
$this->appendHTML(ob_get_contents());
ob_end_clean();
}
/**
* Appends php session content to debugger output
*
* @return void
* @access private
*/
private function appendSession()
{
if ( isset($_SESSION) && $_SESSION ) {
$this->appendHTML('PHP Session: [<b>' . ini_get('session.name') . '</b>]');
$this->dumpVars($_SESSION);
$this->moveToBegin(2);
}
}
/**
* Starts profiling of a given $key
*
* @param string $key
* @param string $description
* @param int $timeStamp
* @return void
* @access public
*/
public function profileStart($key, $description = null, $timeStamp = null)
{
if ( !isset($timeStamp) ) {
$timeStamp = microtime(true);
}
$this->ProfilerData[$key] = Array ('begins' => $timeStamp, 'ends' => 5000, 'debuggerRowID' => count($this->Data));
if ( isset($description) ) {
$this->ProfilerData[$key]['description'] = $description;
}
if ( substr($key, 0, 4) == 'sql_' ) {
// append place from what was called
$trace_results = debug_backtrace();
$trace_count = count($trace_results);
$i = 0;
while ( $i < $trace_count ) {
if ( !isset($trace_results[$i]['file']) ) {
$i++;
continue;
}
$trace_file = basename($trace_results[$i]['file']);
if ( $trace_file != 'db_connection.php' && $trace_file != 'db_load_balancer.php' && $trace_file != 'adodb.inc.php' ) {
break;
}
$i++;
}
$this->ProfilerData[$key]['file'] = $trace_results[$i]['file'];
$this->ProfilerData[$key]['line'] = $trace_results[$i]['line'];
if ( array_key_exists('object', $trace_results[$i + 1]) && isset($trace_results[$i + 1]['object']->Prefix) ) {
$object =& $trace_results[$i + 1]['object'];
/* @var $object kBase */
$prefix_special = rtrim($object->Prefix . '.' . $object->Special, '.');
$this->ProfilerData[$key]['prefix_special'] = $prefix_special;
}
unset($trace_results);
}
$this->Data[] = Array ('profile_key' => $key, 'debug_type' => 'profiler');
}
/**
* Ends profiling for a given $key
*
* @param string $key
* @param string $description
* @param int $timeStamp
* @return void
* @access public
*/
public function profileFinish($key, $description = null, $timeStamp = null)
{
if ( !isset($timeStamp) ) {
$timeStamp = microtime(true);
}
$this->ProfilerData[$key]['ends'] = $timeStamp;
if ( isset($description) ) {
$this->ProfilerData[$key]['description'] = $description;
}
if ( substr($key, 0, 4) == 'sql_' ) {
$func_arguments = func_get_args();
$rows_affected = $func_arguments[3];
$additional = Array ();
if ( $rows_affected > 0 ) {
$additional[] = Array ('name' => 'Affected Rows', 'value' => $rows_affected);
if ( isset($func_arguments[4]) ) {
if ( strlen($func_arguments[4]) > 200 ) {
$func_arguments[4] = substr($func_arguments[4], 0, 50) . ' ...';
}
$additional[] = Array ('name' => 'Result', 'value' => $func_arguments[4]);
}
}
$additional[] = Array ('name' => 'Query Number', 'value' => $func_arguments[5]);
if ( $func_arguments[6] ) {
$this->profilerAddTotal('cachable_queries', $key);
$this->ProfilerData[$key]['subtitle'] = 'cachable';
}
if ( $func_arguments[7] ) {
$additional[] = Array ('name' => 'Server #', 'value' => $func_arguments[7]);
}
if ( array_key_exists('prefix_special', $this->ProfilerData[$key]) ) {
$additional[] = Array ('name' => 'PrefixSpecial', 'value' => $this->ProfilerData[$key]['prefix_special']);
}
$this->ProfilerData[$key]['additional'] =& $additional;
}
}
/**
* Collects total execution time from profiler record
*
* @param string $total_key
* @param string $key
* @param int $value
* @return void
* @access public
*/
public function profilerAddTotal($total_key, $key = null, $value = null)
{
if ( !isset($this->ProfilerTotals[$total_key]) ) {
$this->ProfilerTotals[$total_key] = 0;
$this->ProfilerTotalCount[$total_key] = 0;
}
if ( !isset($value) ) {
$value = $this->ProfilerData[$key]['ends'] - $this->ProfilerData[$key]['begins'];
}
if ( isset($key) ) {
$this->ProfilerData[$key]['totalsKey'] = $total_key;
$this->ProfilerData[$key]['totalsBefore'] = $this->ProfilerTotals[$total_key];
}
$this->ProfilerTotals[$total_key] += $value;
$this->ProfilerTotalCount[$total_key]++;
}
/**
* Traces relative code execution speed between this method calls
*
* @param string $message
* @return void
* @access public
*/
public function appendTimestamp($message)
{
global $start;
$time = microtime(true);
$from_last = $time - $this->LastMoment;
$from_start = $time - $start;
$this->appendHTML(sprintf("<strong>%s</strong> %.5f from last %.5f from start", $message, $from_last, $from_start));
$this->LastMoment = $time;
}
/**
* Returns unique ID for each method call
*
* @return int
* @access public
*/
public function generateID()
{
list($usec, $sec) = explode(' ', microtime());
$id_part_1 = substr($usec, 4, 4);
$id_part_2 = mt_rand(1, 9);
$id_part_3 = substr($sec, 6, 4);
$digit_one = substr($id_part_1, 0, 1);
if ( $digit_one == 0 ) {
$digit_one = mt_rand(1, 9);
$id_part_1 = preg_replace('/^0/', '', $id_part_1);
$id_part_1 = $digit_one . $id_part_1;
}
return $id_part_1 . $id_part_2 . $id_part_3;
}
/**
* Returns error name based on it's code
*
* @param int $error_code
* @return string
* @access private
*/
private function getErrorNameByCode($error_code)
{
$error_map = Array (
'Fatal Error' => Array (E_USER_ERROR),
'Warning' => Array (E_WARNING, E_USER_WARNING),
'Notice' => Array (E_NOTICE, E_USER_NOTICE),
);
if ( defined('E_STRICT') ) {
// since PHP 5
$error_map['PHP5 Strict'] = Array (E_STRICT);
}
if ( defined('E_RECOVERABLE_ERROR') ) {
// since PHP 5.2
$error_map['Fatal Error (recoverable)'] = Array (E_RECOVERABLE_ERROR);
}
if ( defined('E_DEPRECATED') ) {
// since PHP 5.3
$error_map['PHP5 Depricated'] = Array (E_DEPRECATED, E_USER_DEPRECATED);
}
foreach ($error_map as $error_name => $error_codes) {
if ( in_array($error_code, $error_codes) ) {
return $error_name;
}
}
return '';
}
/**
* Returns profile total key (check against missing key too)
*
* @param string $key
* @return int
* @access private
*/
private function getProfilerTotal($key)
{
if ( isset($this->ProfilerTotalCount[$key]) ) {
return (int)$this->ProfilerTotalCount[$key];
}
return 0;
}
/**
* Counts how much calls were made to a place, where this method is called (basic version of profiler)
*
* @param string $title
* @param int $level
* @return void
* @access public
*/
public function ProfilePoint($title, $level = 1)
{
$trace_results = debug_backtrace();
$level = min($level, count($trace_results) - 1);
do {
$point = $trace_results[$level];
$location = $point['file'] . ':' . $point['line'];
$level++;
$has_more = isset($trace_results[$level]);
} while ( $has_more && $point['function'] == $trace_results[$level]['function'] );
if ( !isset($this->ProfilePoints[$title]) ) {
$this->ProfilePoints[$title] = Array ();
}
if ( !isset($this->ProfilePoints[$title][$location]) ) {
$this->ProfilePoints[$title][$location] = 0;
}
$this->ProfilePoints[$title][$location]++;
}
/**
* Generates report
*
* @param bool $returnResult
* @param bool $clean_output_buffer
*
* @return string
* @access public
*/
public function printReport($returnResult = false, $clean_output_buffer = true)
{
if ( $this->reportDone ) {
// don't print same report twice (in case if shutdown function used + compression + fatal error)
return '';
}
$this->profileFinish('script_runtime');
$this->breakOutofBuffering(!$returnResult);
$debugger_start = memory_get_usage();
if ( defined('SPACER_URL') ) {
$this->dummyImage = SPACER_URL;
}
$this->InitReport(); // set parameters required by AJAX
// defined here, because user can define this constant while script is running, not event before debugger is started
DebuggerUtil::safeDefine('DBG_RAISE_ON_WARNINGS', 0);
DebuggerUtil::safeDefine('DBG_TOOLBAR_BUTTONS', 1);
$this->appendSession(); // show php session if any
// ensure, that 1st line of debug output always is this one:
$top_line = '<table cellspacing="0" cellpadding="0" style="width: ' . $this->getWindowWidth() . 'px; margin: 0px;"><tr><td align="left" width="50%">[<a href="javascript:window.location.reload();">Reload Frame</a>] [<a href="javascript:$Debugger.Toggle(27);">Hide Debugger</a>] [<a href="javascript:$Debugger.Clear();">Clear Debugger</a>]</td><td align="right" width="50%">[Current Time: <b>' . date('H:i:s') . '</b>] [File Size: <b>#DBG_FILESIZE#</b>]</td></tr></table>';
$this->appendHTML($top_line);
$this->moveToBegin(1);
if ( count($this->ProfilePoints) > 0 ) {
foreach ($this->ProfilePoints as $point => $locations) {
arsort($this->ProfilePoints[$point]);
}
$this->appendHTML($this->highlightString($this->print_r($this->ProfilePoints, true)));
}
if ( DebuggerUtil::constOn('DBG_SQL_PROFILE') && isset($this->ProfilerTotals['sql']) ) {
// sql query profiling was enabled -> show totals
if ( array_key_exists('cachable_queries', $this->ProfilerTotalCount) ) {
$append = ' <strong>Cachable queries</strong>: ' . $this->ProfilerTotalCount['cachable_queries'];
}
else {
$append = '';
}
$this->appendHTML('<b>SQL Total time:</b> ' . $this->ProfilerTotals['sql'] . ' <b>Number of queries</b>: ' . $this->ProfilerTotalCount['sql'] . $append);
}
if ( DebuggerUtil::constOn('DBG_PROFILE_INCLUDES') && isset($this->ProfilerTotals['includes']) ) {
// included file profiling was enabled -> show totals
$this->appendHTML('<b>Included Files Total time:</b> ' . $this->ProfilerTotals['includes'] . ' Number of includes: ' . $this->ProfilerTotalCount['includes']);
}
if ( DebuggerUtil::constOn('DBG_PROFILE_MEMORY') ) {
// detailed memory usage reporting by objects was enabled -> show totals
$this->appendHTML('<b>Memory used by Objects:</b> ' . round($this->ProfilerTotals['objects'] / 1024, 2) . 'Kb');
}
if ( DebuggerUtil::constOn('DBG_INCLUDED_FILES') ) {
$files = get_included_files();
$this->appendHTML('<strong>Included files:</strong>');
foreach ($files as $file) {
$this->appendHTML($this->getFileLink($this->getLocalFile($file)) . ' (' . round(filesize($file) / 1024, 2) . 'Kb)');
}
}
if ( DebuggerUtil::constOn('DBG_PROFILE_INCLUDES') ) {
$totals = $totals_configs = Array ('mem' => 0, 'time' => 0);
$this->appendHTML('<b>Included files statistics:</b>' . (DebuggerUtil::constOn('DBG_SORT_INCLUDES_MEM') ? ' (sorted by memory usage)' : ''));
if ( is_array($this->IncludesData['mem']) ) {
if ( DebuggerUtil::constOn('DBG_SORT_INCLUDES_MEM') ) {
array_multisort($this->IncludesData['mem'], SORT_DESC, $this->IncludesData['file'], $this->IncludesData['time'], $this->IncludesData['level']);
}
foreach ($this->IncludesData['file'] as $key => $file_name) {
$this->appendHTML(str_repeat('&nbsp;->&nbsp;', ($this->IncludesData['level'][$key] >= 0 ? $this->IncludesData['level'][$key] : 0)) . $file_name . ' Mem: ' . sprintf("%.4f Kb", $this->IncludesData['mem'][$key] / 1024) . ' Time: ' . sprintf("%.4f", $this->IncludesData['time'][$key]));
if ( $this->IncludesData['level'][$key] == 0 ) {
$totals['mem'] += $this->IncludesData['mem'][$key];
$totals['time'] += $this->IncludesData['time'][$key];
}
elseif ( $this->IncludesData['level'][$key] == -1 ) {
$totals_configs['mem'] += $this->IncludesData['mem'][$key];
$totals_configs['time'] += $this->IncludesData['time'][$key];
}
}
$this->appendHTML('<b>Sub-Total classes:</b> ' . ' Mem: ' . sprintf("%.4f Kb", $totals['mem'] / 1024) . ' Time: ' . sprintf("%.4f", $totals['time']));
$this->appendHTML('<b>Sub-Total configs:</b> ' . ' Mem: ' . sprintf("%.4f Kb", $totals_configs['mem'] / 1024) . ' Time: ' . sprintf("%.4f", $totals_configs['time']));
$this->appendHTML('<span class="error"><b>Grand Total:</b></span> ' . ' Mem: ' . sprintf("%.4f Kb", ($totals['mem'] + $totals_configs['mem']) / 1024) . ' Time: ' . sprintf("%.4f", $totals['time'] + $totals_configs['time']));
}
}
$skip_reporting = DebuggerUtil::constOn('DBG_SKIP_REPORTING') || DebuggerUtil::constOn('DBG_ZEND_PRESENT');
if ( ($this->_isAjax && !DebuggerUtil::constOn('DBG_SKIP_AJAX')) || !$skip_reporting ) {
$debug_file = $this->tempFolder . '/debug_' . $this->rowSeparator . '.txt';
if ( file_exists($debug_file) ) {
unlink($debug_file);
}
$i = 0;
$fp = fopen($debug_file, 'a');
$lineCount = count($this->Data);
while ( $i < $lineCount ) {
fwrite($fp, $this->prepareHTML($i) . $this->rowSeparator);
$i++;
}
fclose($fp);
}
if ( $skip_reporting ) {
// let debugger write report and then don't output anything
$this->reportDone = true;
return '';
}
$application =& kApplication::Instance();
$dbg_path = str_replace(FULL_PATH, '', $this->tempFolder);
+ $debugger_params = Array (
+ 'RowSeparator' => $this->rowSeparator,
+ 'ErrorsCount' => (int)$this->getProfilerTotal('error_handling'),
+ 'IsFatalError' => $this->IsFatalError ? 'true' : 'false',
+ 'SQLCount' => (int)$this->getProfilerTotal('sql'),
+ 'SQLTime' => isset($this->ProfilerTotals['sql']) ? sprintf('%.5f', $this->ProfilerTotals['sql']) : 0,
+ 'ScriptTime' => sprintf('%.5f', $this->ProfilerData['script_runtime']['ends'] - $this->ProfilerData['script_runtime']['begins']),
+ 'ScriptMemory' => DebuggerUtil::formatSize($this->getMemoryUsed($debugger_start)),
+ );
+
ob_start();
// the <script .. /script> and hidden div helps browser to break out of script tag or attribute esacped
// with " or ' in case fatal error (or user-error) occurs inside it in compiled template,
// otherwise it has no effect
?>
<div style="display: none" x='nothing'><script></script></div><html><body></body></html>
- <script type="text/javascript" src="<?php echo $this->baseURL; ?>/debugger.js?v2"></script>
+ <script type="text/javascript" src="<?php echo $this->baseURL; ?>/debugger.js?v3"></script>
<link rel="stylesheet" rev="stylesheet" href="<?php echo $this->baseURL; ?>/debugger.css" type="text/css" media="screen" />
<script type="text/javascript">
- var $Debugger = new Debugger(<?php echo "'".$this->rowSeparator."', ".$this->getProfilerTotal('error_handling').', '.($this->IsFatalError ? 'true' : 'false').', '.$this->getProfilerTotal('sql'); ?>);
+ var $Debugger = new Debugger(<?php echo json_encode($debugger_params); ?>);
$Debugger.createEnvironment(<?php echo DBG_WINDOW_WIDTH; ?>, <?php echo $this->getWindowWidth(); ?>);
$Debugger.DOMViewerURL = '<?php echo constant('DBG_DOMVIEWER'); ?>';
$Debugger.EditorPath = '<?php echo defined('DBG_EDITOR') ? addslashes(DBG_EDITOR) : '' ?>';
$Debugger.DebugURL = '<?php echo $this->baseURL.'/debugger_responce.php?sid='.$this->rowSeparator.'&path='.urlencode($dbg_path); ?>';
$Debugger.EventURL = '<?php echo /*is_object($application->Factory) &&*/ $application->InitDone ? $application->HREF('dummy', '', Array ('pass' => 'm', '__NO_REWRITE__' => 1)) : ''; ?>';
$Debugger.BasePath = '<?php echo $this->basePath; ?>';
<?php
$is_install = defined('IS_INSTALL') && IS_INSTALL;
if ( $this->IsFatalError || (!$is_install && DBG_RAISE_ON_WARNINGS && $this->WarningCount) ) {
echo '$Debugger.Toggle();';
}
if ( DBG_TOOLBAR_BUTTONS ) {
echo '$Debugger.AddToolbar("$Debugger");';
}
?>
window.focus();
</script>
<?php
- if ( !isset($this->ProfilerTotals['error_handling']) ) {
- $memory_used = $debugger_start;
- $this->ProfilerTotalCount['error_handling'] = 0;
- }
- else {
- $memory_used = $debugger_start - $this->ProfilerTotals['error_handling'];
- }
-
if ( $returnResult ) {
$ret = ob_get_contents();
if ( $clean_output_buffer ) {
ob_end_clean();
}
- $ret .= $this->getShortReport($memory_used);
+ $ret .= $this->getShortReport($this->getMemoryUsed($debugger_start));
$this->reportDone = true;
return $ret;
}
else {
if ( !DebuggerUtil::constOn('DBG_HIDE_FULL_REPORT') ) {
$this->breakOutofBuffering();
}
elseif ( $clean_output_buffer ) {
ob_clean();
}
- echo $this->getShortReport($memory_used);
+ echo $this->getShortReport($this->getMemoryUsed($debugger_start));
$this->reportDone = true;
}
return '';
}
+ function getMemoryUsed($debugger_start)
+ {
+ if ( !isset($this->ProfilerTotals['error_handling']) ) {
+ $memory_used = $debugger_start;
+ $this->ProfilerTotalCount['error_handling'] = 0;
+ }
+ else {
+ $memory_used = $debugger_start - $this->ProfilerTotals['error_handling'];
+ }
+
+ return $memory_used;
+ }
+
/**
* Format's memory usage report by debugger
*
* @param int $memory_used
* @return string
* @access private
*/
private function getShortReport($memory_used)
{
if ( DebuggerUtil::constOn('DBG_TOOLBAR_BUTTONS') ) {
- // we have sql & error count in toolbar, don't duplicate here
- $info = Array (
- 'Script Runtime' => 'PROFILE:script_runtime',
- 'SQL\'s Runtime' => 'PROFILE_T:sql',
- );
+ // evenrything is in toolbar - don't duplicate
+ return '';
}
else {
// toolbar not visible, then show sql & error count too
$info = Array (
'Script Runtime' => 'PROFILE:script_runtime',
'SQL\'s Runtime' => 'PROFILE_T:sql',
'-' => 'SEP:-',
'Notice / Warning' => 'PROFILE_TC:error_handling',
'SQLs Count' => 'PROFILE_TC:sql',
);
}
- $ret = '<tr><td>Application:</td><td><b>' . DebuggerUtil::formatSize($memory_used) . '</b> (' . $memory_used . ')</td></tr>';
+ $ret = ''; // '<tr><td>Application:</td><td><b>' . DebuggerUtil::formatSize($memory_used) . '</b> (' . $memory_used . ')</td></tr>';
foreach ($info as $title => $value_key) {
list ($record_type, $record_data) = explode(':', $value_key, 2);
switch ( $record_type ) {
case 'PROFILE': // profiler totals value
$Data =& $this->ProfilerData[$record_data];
$profile_time = ($Data['ends'] - $Data['begins']); // in seconds
$ret .= '<tr><td>' . $title . ':</td><td><b>' . sprintf('%.5f', $profile_time) . ' s</b></td></tr>';
break;
case 'PROFILE_TC': // profile totals record count
$record_cell = '<td>';
if ( $record_data == 'error_handling' && $this->ProfilerTotalCount[$record_data] > 0 ) {
$record_cell = '<td class="debug_error">';
}
$ret .= '<tr>' . $record_cell . $title . ':</td>' . $record_cell . '<b>' . $this->ProfilerTotalCount[$record_data] . '</b></td></tr>';
break;
case 'PROFILE_T': // profile total
$record_cell = '<td>';
$total = array_key_exists($record_data, $this->ProfilerTotals) ? $this->ProfilerTotals[$record_data] : 0;
$ret .= '<tr>' . $record_cell . $title . ':</td>' . $record_cell . '<b>' . sprintf('%.5f', $total) . ' s</b></td></tr>';
break;
case 'SEP':
$ret .= '<tr><td colspan="2" style="height: 1px; background-color: #000000; padding: 0px;"><img src="' . $this->dummyImage . '" height="1" alt=""/></td></tr>';
break;
}
}
return '<br /><table class="dbg_stats_table"><tr><td style="border-color: #FFFFFF;"><table class="dbg_stats_table" align="left">' . $ret . '</table></td></tr></table>';
}
/**
* User-defined error handler
*
* @throws Exception
* @param int $errno
* @param string $errstr
* @param string $errfile
* @param int $errline
* @param array $errcontext
* @return bool
* @access public
*/
public function saveError($errno, $errstr, $errfile = null, $errline = null, $errcontext = Array ())
{
$this->ProfilerData['error_handling']['begins'] = memory_get_usage();
$errorType = $this->getErrorNameByCode($errno);
if (!$errorType) {
throw new Exception('Unknown error type [' . $errno . ']');
return false;
}
elseif ( substr($errorType, 0, 5) == 'Fatal' ) {
$this->IsFatalError = true;
$this->appendTrace(4);
}
if ( DebuggerUtil::constOn('DBG_IGNORE_STRICT_ERRORS') && defined('E_STRICT') && ($errno == E_STRICT) ) {
return false;
}
$this->expandError($errstr, $errfile, $errline);
$this->Data[] = Array (
'no' => $errno, 'str' => $errstr, 'file' => $errfile, 'line' => $errline,
'context' => $errcontext, 'debug_type' => 'error'
);
$this->ProfilerData['error_handling']['ends'] = memory_get_usage();
$this->profilerAddTotal('error_handling', 'error_handling');
if ($errorType == 'Warning') {
$this->WarningCount++;
}
if ( $this->IsFatalError ) {
// append debugger report to data in buffer & clean buffer afterwards
die( $this->breakOutofBuffering(false) . $this->printReport(true) );
}
return true;
}
/**
* User-defined exception handler
*
* @param Exception $exception
* @return void
* @access public
*/
public function saveException($exception)
{
$this->ProfilerData['error_handling']['begins'] = memory_get_usage();
$this->appendExceptionTrace($exception);
$errno = $exception->getCode();
$errstr = $exception->getMessage();
$errfile = $exception->getFile();
$errline = $exception->getLine();
$this->expandError($errstr, $errfile, $errline);
$this->Data[] = Array (
'no' => $errno, 'str' => $errstr, 'file' => $errfile, 'line' => $errline,
'exception_class' => get_class($exception), 'debug_type' => 'exception'
);
$this->ProfilerData['error_handling']['ends'] = memory_get_usage();
$this->profilerAddTotal('error_handling', 'error_handling');
$this->IsFatalError = true;
// append debugger report to data in buffer & clean buffer afterwards
die( $this->breakOutofBuffering(false) . $this->printReport(true) );
}
/**
* Transforms short error messages into long ones
*
* @param string $errstr
* @param string $errfile
* @param int $errline
* @return void
* @access private
*/
private function expandError(&$errstr, &$errfile, &$errline)
{
if ( preg_match('/(.*)#([\d]+)$/', $errstr, $rets) ) {
// replace short message with long one (due triger_error limitations on message size)
$long_id = $rets[2];
$errstr = $this->longErrors[$long_id];
unset($this->longErrors[$long_id]);
}
if ( strpos($errfile, 'eval()\'d code') !== false ) {
$errstr = '[<b>EVAL</b>, line <b>' . $errline . '</b>]: ' . $errstr;
$tmpStr = $errfile;
$pos = strpos($tmpStr, '(');
$errfile = substr($tmpStr, 0, $pos);
$pos++;
$errline = substr($tmpStr, $pos, strpos($tmpStr, ')', $pos) - $pos);
}
}
/**
* Break buffering in case if fatal error is happened in the middle
*
* @param bool $flush
* @return string
* @access private
*/
private function breakOutofBuffering($flush = true)
{
$buffer_content = Array ();
while ( ob_get_level() ) {
$buffer_content[] = ob_get_clean();
}
$ret = implode('', array_reverse($buffer_content));
if ( $flush ) {
echo $ret;
flush();
}
return $ret;
}
/**
* Saves given message to "vb_debug.txt" file in DocumentRoot
*
* @param string $msg
* @return void
* @access public
*/
public function saveToFile($msg)
{
$fp = fopen($_SERVER['DOCUMENT_ROOT'] . '/vb_debug.txt', 'a');
fwrite($fp, $msg . "\n");
fclose($fp);
}
/**
* Prints given constant values in a table
*
* @param mixed $constants
* @return void
* @access public
*/
public function printConstants($constants)
{
if ( !is_array($constants) ) {
$constants = explode(',', $constants);
}
$constant_tpl = '<tr><td>%s</td><td><b>%s</b></td></tr>';
$ret = '<table class="dbg_flat_table" style="width: ' . $this->getWindowWidth() . 'px;">';
foreach ($constants as $constant_name) {
$ret .= sprintf($constant_tpl, $constant_name, constant($constant_name));
}
$ret .= '</table>';
$this->appendHTML($ret);
}
/**
* Attaches debugger to Application
*
* @return void
* @access public
*/
public function AttachToApplication()
{
if ( !DebuggerUtil::constOn('DBG_HANDLE_ERRORS') ) {
return;
}
if ( class_exists('kApplication') ) {
// replace application error/exception handler with own
restore_error_handler();
restore_exception_handler();
$this->Application =& kApplication::Instance();
$this->Application->Debugger =& $this;
$this->Application->errorHandlers[] = Array (&$this, 'saveError');
$this->Application->exceptionHandlers[] = Array (&$this, 'saveException');
}
else {
set_error_handler( Array (&$this, 'saveError') );
set_exception_handler( Array (&$this, 'saveException') );
}
}
/**
* Returns HTML for tools section
*
* @return string
* @access private
*/
private function _getToolsHTML()
{
$html = '<table>
<tr>
<td>System Tools:</td>
<td>
<select id="reset_cache" style="border: 1px solid #000000;">
<option value=""></option>
<option value="events[adm][OnResetModRwCache]">Reset mod_rewrite Cache</option>
<option value="events[adm][OnResetCMSMenuCache]">Reset SMS Menu Cache</option>
<option value="events[adm][OnResetSections]">Reset Sections Cache</option>
<option value="events[adm][OnResetConfigsCache]">Reset Configs Cache</option>
<option value="events[adm][OnRebuildThemes]">Re-build Themes Files</option>
<option value="events[lang][OnReflectMultiLingualFields]">Re-build Multilanguage Fields</option>
<option value="events[adm][OnDeleteCompiledTemplates]">Delete Compiled Templates</option>
</select>
</td>
<td>
<input type="button" class="button" onclick="$Debugger.resetCache(\'reset_cache\');" value="Go"/>
</td>
</tr>
</table>';
return $html;
}
/**
* Returns HTML for dom viewer section
*
* @return string
* @access private
*/
private function _getDomViewerHTML()
{
$html = '<table>
<tr>
<td>
<a href="http://www.brainjar.com/dhtml/domviewer/" target="_blank">DomViewer</a>:
</td>
<td>
<input id="dbg_domviewer" type="text" value="window" style="border: 1px solid #000000;"/>
</td>
<td>
<button class="button" onclick="return $Debugger.OpenDOMViewer();">Show</button>
</td>
</tr>
</table>';
return $html;
}
}
if ( !function_exists('memory_get_usage') ) {
// PHP 4.x and compiled without --enable-memory-limit option
function memory_get_usage()
{
return -1;
}
}
if ( !DebuggerUtil::constOn('DBG_ZEND_PRESENT') ) {
$debugger = new Debugger();
}
if ( DebuggerUtil::constOn('DBG_USE_SHUTDOWN_FUNC') ) {
register_shutdown_function(Array (&$debugger, 'printReport'));
}
}
\ No newline at end of file
Index: branches/5.2.x/core/kernel/utility/unit_config_reader.php
===================================================================
--- branches/5.2.x/core/kernel/utility/unit_config_reader.php (revision 15129)
+++ branches/5.2.x/core/kernel/utility/unit_config_reader.php (revision 15130)
@@ -1,1068 +1,1028 @@
<?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 kUnitConfigReader extends kBase implements kiCacheable {
/**
* Configs reader
*
* @var Array
* @access private
*/
var $configData = Array();
var $configFiles = Array();
var $CacheExpired = false;
var $prefixFiles = array();
var $ProcessAllConfigs = false;
var $FinalStage = false;
var $StoreCache = false;
var $AfterConfigProcessed = array();
/**
* Escaped directory separator for using in regular expressions
*
* @var string
*/
var $_directorySeparator = '';
/**
* Regular expression for detecting module folder
*
* @var string
*/
var $_moduleFolderRegExp = '';
/**
* Folders to skip during unit config search
*
* @var Array
*/
var $_skipFolders = Array ('CVS', '.svn', 'admin_templates', 'libchart');
/**
* Creates instance of unit config reader
*
*/
public function __construct()
{
parent::__construct();
$this->_directorySeparator = preg_quote(DIRECTORY_SEPARATOR);
$editor_path = explode('/', trim(EDITOR_PATH, '/'));
$this->_skipFolders[] = array_pop($editor_path); // last of cmseditor folders
$this->_moduleFolderRegExp = '#' . $this->_directorySeparator . '(core|modules' . $this->_directorySeparator . '.*?)' . $this->_directorySeparator . '#';
}
/**
* Sets data from cache to object
*
* @param Array $data
* @access public
*/
public function setFromCache(&$data)
{
$this->prefixFiles = $data['ConfigReader.prefixFiles'];
}
/**
* Gets object data for caching
*
* @access public
* @return Array
*/
public function getToCache()
{
return Array (
'ConfigReader.prefixFiles' => $this->prefixFiles,
);
}
function scanModules($folderPath, $cache = true)
{
if (defined('IS_INSTALL') && IS_INSTALL && !defined('FORCE_CONFIG_CACHE')) {
// disable config caching during installation
$cache = false;
}
if ($cache) {
$restored = $this->Application->cacheManager->LoadUnitCache();
if ($restored) {
if ( defined('DEBUG_MODE') && DEBUG_MODE && $this->Application->isDebugMode() ) {
$this->Application->Debugger->appendHTML('UnitConfigReader: Restoring Cache');
}
return;
}
}
if ( defined('DEBUG_MODE') && DEBUG_MODE && $this->Application->isDebugMode() ) {
$this->Application->Debugger->appendHTML('UnitConfigReader: Generating Cache');
}
$this->ProcessAllConfigs = true;
$this->includeConfigFiles($folderPath, $cache);
$this->ParseConfigs();
// tell AfterConfigRead to store cache if needed
// can't store it here because AfterConfigRead needs ability to change config data
$this->StoreCache = $cache;
if ( !$this->Application->InitDone ) {
// scanModules is called multiple times during installation process
$this->Application->InitManagers();
// get build-in rewrite listeners ONLY to be able to parse mod-rewrite url when unit config cache is missing
$this->retrieveCollections();
$this->_sortRewriteListeners();
}
$this->Application->cacheManager->applyDelayedUnitProcessing();
}
function findConfigFiles($folderPath, $level = 0)
{
// if FULL_PATH = "/" ensure, that all "/" in $folderPath are not deleted
$reg_exp = '/^' . preg_quote(FULL_PATH, '/') . '/';
$folderPath = preg_replace($reg_exp, '', $folderPath, 1); // this make sense, since $folderPath may NOT contain FULL_PATH
$base_folder = FULL_PATH . $folderPath . DIRECTORY_SEPARATOR;
$sub_folders = glob($base_folder . '*', GLOB_ONLYDIR);
if (!$sub_folders) {
return ;
}
if ($level == 0) {
// don't scan Front-End themes because of extensive directory structure
$sub_folders = array_diff($sub_folders, Array ($base_folder . 'themes', $base_folder . 'tools'));
}
foreach ($sub_folders as $full_path) {
$sub_folder = substr($full_path, strlen($base_folder));
if (in_array($sub_folder, $this->_skipFolders)) {
continue;
}
if (preg_match('/^\./', $sub_folder)) {
// don't scan ".folders"
continue;
}
$config_name = $this->getConfigName($folderPath . DIRECTORY_SEPARATOR . $sub_folder);
if (file_exists(FULL_PATH . $config_name)) {
$this->configFiles[] = $config_name;
}
$this->findConfigFiles($full_path, $level + 1);
}
}
function includeConfigFiles($folderPath, $cache = true)
{
$this->Application->refreshModuleInfo();
if ( $this->Application->isCachingType(CACHING_TYPE_MEMORY) ) {
$data = $this->Application->getCache('master:config_files', false, CacheSettings::$unitCacheRebuildTime);
}
else {
$data = $this->Application->getDBCache('config_files', CacheSettings::$unitCacheRebuildTime);
}
if ( $data ) {
$this->configFiles = unserialize($data);
if ( !defined('DBG_VALIDATE_CONFIGS') && !DBG_VALIDATE_CONFIGS ) {
shuffle($this->configFiles);
}
}
else {
if ( $cache ) {
if ( $this->Application->isCachingType(CACHING_TYPE_MEMORY) ) {
$this->Application->rebuildCache('master:config_files', kCache::REBUILD_NOW, CacheSettings::$unitCacheRebuildTime);
}
else {
$this->Application->rebuildDBCache('config_files', kCache::REBUILD_NOW, CacheSettings::$unitCacheRebuildTime);
}
}
$this->findConfigFiles(FULL_PATH . DIRECTORY_SEPARATOR . 'core'); // search from core directory
$this->findConfigFiles($folderPath); // search from modules directory
if ( $cache ) {
if ( $this->Application->isCachingType(CACHING_TYPE_MEMORY) ) {
$this->Application->setCache('master:config_files', serialize($this->configFiles));
}
else {
$this->Application->setDBCache('config_files', serialize($this->configFiles));
}
}
}
foreach ($this->configFiles as $filename) {
$prefix = $this->PreloadConfigFile($filename);
if (!$prefix) {
throw new Exception('Prefix not defined in config file <strong>' . $filename . '</strong>');
}
}
if ($cache) {
unset($this->configFiles);
}
}
/**
* Process all read config files - called ONLY when there is no cache!
*
*/
function ParseConfigs()
{
- // 1. process normal configs and their dependencies
+ // 1. process normal configs
$prioritized_configs = array();
foreach ($this->configData as $prefix => $config) {
if (isset($config['ConfigPriority'])) {
$prioritized_configs[$prefix] = $config['ConfigPriority'];
continue;
}
$this->parseConfig($prefix);
}
foreach ($this->configData as $prefix => $config) {
- $this->ProcessDependencies($prefix);
$this->postProcessConfig($prefix, 'AggregateConfigs', 'sub_prefix');
$clones = $this->postProcessConfig($prefix, 'Clones', 'prefix');
}
- // 2. process prioritized configs and their dependencies
+ // 2. process prioritized configs
asort($prioritized_configs);
foreach ($prioritized_configs as $prefix => $priority) {
$this->parseConfig($prefix);
}
-
- foreach ($prioritized_configs as $prefix => $priority) {
- $this->ProcessDependencies($prefix);
- }
}
function AfterConfigRead($store_cache = null)
{
// if (!$this->ProcessAllConfigs) return ;
$this->FinalStage = true;
foreach ($this->configData as $prefix => $config) {
$this->runAfterConfigRead($prefix);
}
if ( !isset($store_cache) ) {
// $store_cache not overridden -> use global setting
$store_cache = $this->StoreCache;
}
if ($store_cache || (defined('IS_INSTALL') && IS_INSTALL)) {
// cache is not stored during install, but dynamic clones should be processed in any case
$this->processDynamicClones();
$this->retrieveCollections();
}
if ($store_cache) {
$this->_sortRewriteListeners();
- $after_event = new kEvent('adm:OnAfterCacheRebuild');
- $this->Application->HandleEvent($after_event);
+ $this->Application->HandleEvent(new kEvent('adm:OnAfterCacheRebuild'));
$this->Application->cacheManager->UpdateUnitCache();
if (defined('DEBUG_MODE') && DEBUG_MODE && defined('DBG_VALIDATE_CONFIGS') && DBG_VALIDATE_CONFIGS) {
// validate configs here to have changes from OnAfterConfigRead hooks to prefixes
foreach ($this->configData as $prefix => $config) {
if (!isset($config['TableName'])) continue;
$this->ValidateConfig($prefix);
}
}
}
}
/**
* Sort rewrite listeners according to RewritePriority (non-prioritized listeners goes first)
*
*/
function _sortRewriteListeners()
{
$listeners = Array ();
$prioritized_listeners = Array ();
// process non-prioritized listeners
foreach ($this->Application->RewriteListeners as $prefix => $listener_data) {
if ($listener_data['priority'] === false) {
$listeners[$prefix] = $listener_data;
}
else {
$prioritized_listeners[$prefix] = $listener_data['priority'];
}
}
// process prioritized listeners
asort($prioritized_listeners, SORT_NUMERIC);
foreach ($prioritized_listeners as $prefix => $priority) {
$listeners[$prefix] = $this->Application->RewriteListeners[$prefix];
}
$this->Application->RewriteListeners = $listeners;
}
/**
* Re-reads all configs
*
*/
function ReReadConfigs()
{
// don't reset prefix file, since file scanning could slow down the process
$prefix_files_backup = $this->prefixFiles;
$this->Application->cacheManager->EmptyUnitCache();
$this->prefixFiles = $prefix_files_backup;
// parse all configs
$this->ProcessAllConfigs = true;
$this->AfterConfigProcessed = Array ();
$this->includeConfigFiles(MODULES_PATH, false);
$this->ParseConfigs();
$this->AfterConfigRead(false);
$this->processDynamicClones();
// don't call kUnitConfigReader::retrieveCollections since it
// will overwrite what we already have in kApplication class instance
}
/**
* Process clones, that were defined via OnAfterConfigRead event
*
*/
function processDynamicClones()
{
$new_clones = Array();
foreach ($this->configData as $prefix => $config) {
$clones = $this->postProcessConfig($prefix, 'Clones', 'prefix');
if ($clones) {
$new_clones = array_merge($new_clones, $clones);
}
}
// execute delayed methods for cloned unit configs
$this->Application->cacheManager->applyDelayedUnitProcessing();
// call OnAfterConfigRead for cloned configs
$new_clones = array_unique($new_clones);
foreach ($new_clones as $prefix) {
$this->runAfterConfigRead($prefix);
}
}
/**
* Process all collectible unit config options here to also catch ones, defined from OnAfterConfigRead events
*
*/
function retrieveCollections()
{
foreach ($this->configData as $prefix => $config) {
// collect replacement templates
if (array_key_exists('ReplacementTemplates', $config) && $config['ReplacementTemplates']) {
$this->Application->ReplacementTemplates = array_merge($this->Application->ReplacementTemplates, $config['ReplacementTemplates']);
}
// collect rewrite listeners
if (array_key_exists('RewriteListener', $config) && $config['RewriteListener']) {
$rewrite_listeners = $config['RewriteListener'];
if (!is_array($rewrite_listeners)) {
// when one method is used to build and parse url
$rewrite_listeners = Array ($rewrite_listeners, $rewrite_listeners);
}
foreach ($rewrite_listeners as $index => $rewrite_listener) {
if (strpos($rewrite_listener, ':') === false) {
$rewrite_listeners[$index] = $prefix . '_EventHandler:' . $rewrite_listener;
}
}
$rewrite_priority = array_key_exists('RewritePriority', $config) ? $config['RewritePriority'] : false;
$this->Application->RewriteListeners[$prefix] = Array ('listener' => $rewrite_listeners, 'priority' => $rewrite_priority);
}
}
}
/**
* Register nessasary classes
* This method should only process the data which is cached!
*
* @param string $prefix
* @access private
*/
function parseConfig($prefix)
{
$this->parseClasses($prefix);
$this->parseScheduledTasks($prefix);
$this->parseHooks($prefix);
$this->parseAggregatedTags($prefix);
}
protected function parseClasses($prefix)
{
$config =& $this->configData[$prefix];
$register_classes = $this->getClasses($prefix);
foreach ($register_classes as $class_info) {
- // remember class dependencies
- $class_name = $class_info['class'];
- $require_classes = isset($class_info['require_classes']) ? $class_info['require_classes'] : Array ();
-
- if ($require_classes) {
- $require_classes = (array)$require_classes;
-
- if ( !isset($config['_Dependencies'][$class_name]) ) {
- $config['_Dependencies'][$class_name] = Array ();
- }
-
- $config['_Dependencies'][$class_name] = array_merge($config['_Dependencies'][$class_name], $require_classes);
- }
-
- // register class
$this->Application->registerClass(
- $class_name,
+ $class_info['class'],
$config['BasePath'] . DIRECTORY_SEPARATOR . $class_info['file'],
$class_info['pseudo']
);
if ( isset($class_info['build_event']) && $class_info['build_event'] ) {
$this->Application->delayUnitProcessing('registerBuildEvent', Array ($class_info['pseudo'], $class_info['build_event']));
}
}
}
protected function parseScheduledTasks($prefix)
{
$config =& $this->configData[$prefix];
if ( !isset($config['ScheduledTasks']) || !$config['ScheduledTasks'] ) {
return ;
}
$scheduled_tasks = $config['ScheduledTasks'];
foreach ($scheduled_tasks as $short_name => $scheduled_task_info) {
$event_status = array_key_exists('Status', $scheduled_task_info) ? $scheduled_task_info['Status'] : STATUS_ACTIVE;
$this->Application->delayUnitProcessing('registerScheduledTask', Array ( $short_name, $config['Prefix'] . ':' . $scheduled_task_info['EventName'], $scheduled_task_info['RunInterval'], $event_status ));
}
}
protected function parseHooks($prefix)
{
$config =& $this->configData[$prefix];
if ( !isset($config['Hooks']) || !$config['Hooks'] ) {
return ;
}
$hooks = $config['Hooks'];
foreach ($hooks as $hook) {
if ( isset($config['ParentPrefix']) && ($hook['HookToPrefix'] == $config['ParentPrefix']) ) {
trigger_error('Depricated Hook Usage [prefix: <strong>' . $config['Prefix'] . '</strong>; do_prefix: <strong>' . $hook['DoPrefix'] . '</strong>] use <strong>#PARENT#</strong> as <strong>HookToPrefix</strong> value, where HookToPrefix is same as ParentPrefix', defined('E_USER_DEPRECATED') ? E_USER_DEPRECATED : E_USER_NOTICE);
}
if ($hook['HookToPrefix'] == '') {
// new: set hooktoprefix to current prefix if not set
$hook['HookToPrefix'] = $config['Prefix'];
}
if ( isset($config['ParentPrefix']) ) {
// new: allow to set hook to parent prefix what ever it is
if ($hook['HookToPrefix'] == '#PARENT#') {
$hook['HookToPrefix'] = $config['ParentPrefix'];
}
if ($hook['DoPrefix'] == '#PARENT#') {
$hook['DoPrefix'] = $config['ParentPrefix'];
}
}
elseif ($hook['HookToPrefix'] == '#PARENT#' || $hook['DoPrefix'] == '#PARENT#') {
// we need parent prefix but it's not set !
continue;
}
$hook_events = (array)$hook['HookToEvent'];
$do_prefix = $hook['DoPrefix'] == '' ? $config['Prefix'] : $hook['DoPrefix'];
foreach ($hook_events as $hook_event) {
$hook_event = $hook['HookToPrefix'] . '.' . $hook['HookToSpecial'] . ':' . $hook_event;
$do_event = $do_prefix . '.' . $hook['DoSpecial'] . ':' . $hook['DoEvent'];
$this->Application->delayUnitProcessing('registerHook', Array ($hook_event, $do_event, $hook['Mode'], $hook['Conditional']));
}
}
}
protected function parseAggregatedTags($prefix)
{
$config =& $this->configData[$prefix];
$aggregated_tags = isset($config['AggregateTags']) ? $config['AggregateTags'] : Array ();
foreach ($aggregated_tags as $aggregate_tag) {
if ( isset($config['ParentPrefix']) ) {
if ($aggregate_tag['AggregateTo'] == $config['ParentPrefix']) {
trigger_error('Depricated Aggregate Tag Usage [prefix: <b>'.$config['Prefix'].'</b>; AggregateTo: <b>'.$aggregate_tag['AggregateTo'].'</b>] use <b>#PARENT#</b> as <b>AggregateTo</b> value, where AggregateTo is same as ParentPrefix', defined('E_USER_DEPRECATED') ? E_USER_DEPRECATED : E_USER_NOTICE);
}
if ($aggregate_tag['AggregateTo'] == '#PARENT#') {
$aggregate_tag['AggregateTo'] = $config['ParentPrefix'];
}
}
$aggregate_tag['LocalPrefix'] = $config['Prefix'];
$this->Application->delayUnitProcessing('registerAggregateTag', Array ($aggregate_tag));
}
}
function ValidateConfig($prefix)
{
global $debugger;
$config =& $this->configData[$prefix];
$tablename = $config['TableName'];
$float_types = Array ('float', 'double', 'numeric');
$table_found = $this->Conn->Query('SHOW TABLES LIKE "'.$tablename.'"');
if (!$table_found) {
// config present, but table missing, strange
kUtil::safeDefine('DBG_RAISE_ON_WARNINGS', 1);
$debugger->appendHTML("<b class='debug_error'>Config Warning: </b>Table <strong>$tablename</strong> missing, but prefix <b>".$config['Prefix']."</b> requires it!");
$debugger->WarningCount++;
return ;
}
$res = $this->Conn->Query('DESCRIBE '.$tablename);
$config_link = $debugger->getFileLink(FULL_PATH.$this->prefixFiles[$config['Prefix']], 1, $config['Prefix']);
$error_messages = Array (
'field_not_found' => 'Field <strong>%s</strong> exists in the database, but <strong>is not defined</strong> in config',
'default_missing' => 'Default value for field <strong>%s</strong> not set in config',
'not_null_error1' => 'Field <strong>%s</strong> is NOT NULL in the database, but is not configured as not_null', // or required',
'not_null_error2' => 'Field <strong>%s</strong> is described as NOT NULL in config, but <strong>does not have DEFAULT value</strong>',
'not_null_error3' => 'Field <strong>%s</strong> is described as <strong>NOT NULL in config</strong>, but is <strong>NULL in db</strong>',
'invalid_default' => '<strong>Default value</strong> for field %s<strong>%s</strong> not sync. to db (in config = %s, in db = %s)',
'date_column_not_null_error' => 'Field <strong>%s</strong> must be NULL in config and database, since it contains date',
'user_column_default_error' => 'Field <strong>%s</strong> must be have NULL as default value, since it holds user id',
'type_missing' => '<strong>Type definition</strong> for field <strong>%s</strong> missing in config',
'virtual_type_missing' => '<strong>Type definition</strong> for virtual field <strong>%s</strong> missing in config',
'virtual_default_missing' => 'Default value for virtual field <strong>%s</strong> not set in config',
'virtual_not_null_error' => 'Virtual field <strong>%s</strong> cannot be not null, since it doesn\'t exist in database',
'invalid_calculated_field' => 'Calculated field <strong>%s</strong> is missing corresponding virtual field',
);
$config_errors = Array ();
$tablename = preg_replace('/^'.preg_quote(TABLE_PREFIX, '/').'(.*)/', '\\1', $tablename); // remove table prefix
// validate unit config field declaration in relation to database table structure
foreach ($res as $field) {
$f_name = $field['Field'];
if (getArrayValue($config, 'Fields')) {
if (preg_match('/l[\d]+_[\w]/', $f_name)) {
// skip multilingual fields
continue;
}
if (!array_key_exists ($f_name, $config['Fields'])) {
$config_errors[] = sprintf($error_messages['field_not_found'], $f_name);
}
else {
$db_default = $field['Default'];
if (is_numeric($db_default)) {
$db_default = preg_match('/[\.,]/', $db_default) ? (float)$db_default : (int)$db_default;
}
$default_missing = false;
$options = $config['Fields'][$f_name];
$not_null = isset($options['not_null']) && $options['not_null'];
$formatter = array_key_exists('formatter', $options) ? $options['formatter'] : false;
if (!array_key_exists('default', $options)) {
$config_errors[] = sprintf($error_messages['default_missing'], $f_name);
$default_missing = true;
}
if ($field['Null'] != 'YES') {
// field is NOT NULL in database (MySQL5 for null returns "NO", but MySQL4 returns "")
if ( $f_name != $config['IDField'] && !isset($options['not_null']) /*&& !isset($options['required'])*/ ) {
$config_errors[] = sprintf($error_messages['not_null_error1'], $f_name);
}
if ($not_null && !isset($options['default']) ) {
$config_errors[] = sprintf($error_messages['not_null_error2'], $f_name);
}
}
elseif ($not_null) {
$config_errors[] = sprintf($error_messages['not_null_error3'], $f_name);
}
if (($formatter == 'kDateFormatter') && $not_null) {
$config_errors[] = sprintf($error_messages['date_column_not_null_error'], $f_name);
}
// columns, holding userid should have NULL as default value
if (array_key_exists('type', $options) && !$default_missing) {
// both type and default value set
if (preg_match('/ById$/', $f_name) && $options['default'] !== null) {
$config_errors[] = sprintf($error_messages['user_column_default_error'], $f_name);
}
}
if (!array_key_exists('type', $options)) {
$config_errors[] = sprintf($error_messages['type_missing'], $f_name);
}
if (!$default_missing && ($field['Type'] != 'text')) {
if ( is_null($db_default) && $not_null ) {
$db_default = $options['type'] == 'string' ? '' : 0;
}
if ($f_name == $config['IDField'] && $options['type'] != 'string' && $options['default'] !== 0) {
$config_errors[] = sprintf($error_messages['invalid_default'], '<span class="debug_error">IDField</span> ', $f_name, $this->varDump($options['default']), $this->varDump($field['Default']));
}
else if (((string)$options['default'] != '#NOW#') && ($db_default !== $options['default']) && !in_array($options['type'], $float_types)) {
$config_errors[] = sprintf($error_messages['invalid_default'], '', $f_name, $this->varDump($options['default']), $this->varDump($db_default));
}
}
}
}
}
// validate virtual fields
if ( array_key_exists('VirtualFields', $config) ) {
foreach ($config['VirtualFields'] as $f_name => $options) {
if (!array_key_exists('type', $options)) {
$config_errors[] = sprintf($error_messages['virtual_type_missing'], $f_name);
}
if (array_key_exists('not_null', $options)) {
$config_errors[] = sprintf($error_messages['virtual_not_null_error'], $f_name);
}
if (!array_key_exists('default', $options)) {
$config_errors[] = sprintf($error_messages['virtual_default_missing'], $f_name);
}
}
}
// validate calculated fields
if ( array_key_exists('CalculatedFields', $config) ) {
foreach ($config['CalculatedFields'] as $special => $calculated_fields) {
foreach ($calculated_fields as $calculated_field => $calculated_field_expr) {
if ( !isset($config['VirtualFields'][$calculated_field]) ) {
$config_errors[] = sprintf($error_messages['invalid_calculated_field'], $calculated_field);
}
}
}
$config_errors = array_unique($config_errors);
}
if ($config_errors) {
$error_prefix = '<strong class="debug_error">Config Error'.(count($config_errors) > 1 ? 's' : '').': </strong> for prefix <strong>'.$config_link.'</strong> ('.$tablename.') in unit config:<br />';
$config_errors = $error_prefix.'&nbsp;&nbsp;&nbsp;'.implode('<br />&nbsp;&nbsp;&nbsp;', $config_errors);
kUtil::safeDefine('DBG_RAISE_ON_WARNINGS', 1);
$debugger->appendHTML($config_errors);
$debugger->WarningCount++;
}
}
function varDump($value)
{
return '<strong>'.var_export($value, true).'</strong> of '.gettype($value);
}
- protected function ProcessDependencies($prefix)
- {
- $config =& $this->configData[$prefix];
- $dependencies = getArrayValue($config, '_Dependencies');
- /* @var $dependencies Array */
-
- if ( !$dependencies ) {
- return ;
- }
-
- foreach ($dependencies as $real_class => $requires) {
- foreach ($requires as $class) {
- $this->Application->registerDependency($real_class, $class);
- }
- }
-
- unset($config['_Dependencies']);
- }
-
function postProcessConfig($prefix, $config_key, $dst_prefix_var)
{
$main_config =& $this->configData[$prefix];
$sub_configs = isset($main_config[$config_key]) && $main_config[$config_key] ? $main_config[$config_key] : Array ();
if ( !$sub_configs ) {
return Array ();
}
unset($main_config[$config_key]);
$processed = array();
foreach ($sub_configs as $sub_prefix => $sub_config) {
if ($config_key == 'AggregateConfigs' && !isset($this->configData[$sub_prefix])) {
$this->loadConfig($sub_prefix);
}
$sub_config['Prefix'] = $sub_prefix;
$this->configData[$sub_prefix] = kUtil::array_merge_recursive($this->configData[$$dst_prefix_var], $sub_config);
// when merging empty array to non-empty results non-empty array, but empty is required
foreach ($sub_config as $sub_key => $sub_value) {
if (!$sub_value) {
unset($this->configData[$sub_prefix][$sub_key]);
}
}
if ($config_key == 'Clones') {
$this->prefixFiles[$sub_prefix] = $this->prefixFiles[$prefix];
}
$this->postProcessConfig($sub_prefix, $config_key, $dst_prefix_var);
if ($config_key == 'AggregateConfigs') {
$processed = array_merge($this->postProcessConfig($sub_prefix, 'Clones', 'prefix'), $processed);
}
elseif ($this->ProcessAllConfigs) {
$this->parseConfig($sub_prefix);
}
array_push($processed, $sub_prefix);
}
if (!$prefix) {
// configs, that used only for cloning & not used ifself
unset($this->configData[$prefix]);
}
return array_unique($processed);
}
function PreloadConfigFile($filename)
{
$config_found = file_exists(FULL_PATH . $filename) && $this->configAllowed($filename);
if (defined('DEBUG_MODE') && DEBUG_MODE && defined('DBG_PROFILE_INCLUDES') && DBG_PROFILE_INCLUDES) {
if ( in_array($filename, get_included_files()) ) {
return '';
}
global $debugger;
if ($config_found) {
$file = FULL_PATH . $filename;
$file_crc = crc32($file);
$debugger->ProfileStart('inc_' . $file_crc, $file);
include_once($file);
$debugger->ProfileFinish('inc_' . $file_crc);
$debugger->profilerAddTotal('includes', 'inc_' . $file_crc);
}
}
elseif ($config_found) {
include_once(FULL_PATH . $filename);
}
if ($config_found) {
if (isset($config) && $config) {
// config file is included for 1st time -> save it's content for future processing
$prefix = array_key_exists('Prefix', $config) ? $config['Prefix'] : '';
preg_match($this->_moduleFolderRegExp, $filename, $rets);
$config['ModuleFolder'] = str_replace(DIRECTORY_SEPARATOR, '/', $rets[1]);
$config['BasePath'] = dirname(FULL_PATH . $filename);
if (array_key_exists('AdminTemplatePath', $config)) {
// append template base folder for admin templates path of this prefix
$module_templates = $rets[1] == 'core' ? '' : substr($rets[1], 8) . '/';
$config['AdminTemplatePath'] = $module_templates . $config['AdminTemplatePath'];
}
if (array_key_exists($prefix, $this->prefixFiles) && ($this->prefixFiles[$prefix] != $filename)) {
trigger_error(
'Single unit config prefix "<strong>' . $prefix . '</strong>" ' .
'is used in multiple unit config files: ' .
'"<strong>' . $this->prefixFiles[$prefix] . '</strong>", "<strong>' . $filename . '</strong>"',
E_USER_WARNING
);
}
$this->configData[$prefix] = $config;
$this->prefixFiles[$prefix] = $filename;
return $prefix;
}
else {
$prefix = array_search($filename, $this->prefixFiles);
if ( $prefix ) {
// attempt is made to include config file twice or more, but include_once prevents that,
// but file exists on hdd, then it is already saved to all required arrays, just return it's prefix
return $prefix;
}
}
}
return 'dummy';
}
function loadConfig($prefix)
{
if ( !isset($this->prefixFiles[$prefix]) ) {
throw new Exception('Configuration file for prefix <strong>' . $prefix . '</strong> is unknown');
return ;
}
$file = $this->prefixFiles[$prefix];
$prefix = $this->PreloadConfigFile($file);
if ($this->FinalStage) {
// run prefix OnAfterConfigRead so all
// hooks to it can define their clonses
$this->runAfterConfigRead($prefix);
}
$clones = $this->postProcessConfig($prefix, 'AggregateConfigs', 'sub_prefix');
$clones = array_merge($this->postProcessConfig($prefix, 'Clones', 'prefix'), $clones);
if ($this->FinalStage) {
$clones = array_unique($clones);
foreach ($clones as $a_prefix) {
$this->runAfterConfigRead($a_prefix);
}
}
}
function runAfterConfigRead($prefix)
{
if (in_array($prefix, $this->AfterConfigProcessed)) {
return ;
}
$this->Application->HandleEvent( new kEvent($prefix . ':OnAfterConfigRead') );
if (!(defined('IS_INSTALL') && IS_INSTALL)) {
// allow to call OnAfterConfigRead multiple times during install
array_push($this->AfterConfigProcessed, $prefix);
}
}
/**
* Reads unit (specified by $prefix)
* option specified by $option
*
* @param string $prefix
* @param string $name
* @param mixed $default
* @return string
* @access public
*/
function getUnitOption($prefix, $name, $default = false)
{
if (preg_match('/(.*)\.(.*)/', $prefix, $rets)) {
if (!isset($this->configData[$rets[1]])) {
$this->loadConfig($rets[1]);
}
$ret = isset($this->configData[$rets[1]][$name][$rets[2]]) ? $this->configData[$rets[1]][$name][$rets[2]] : false;
// $ret = getArrayValue($this->configData, $rets[1], $name, $rets[2]);
}
else {
if (!isset($this->configData[$prefix])) {
$this->loadConfig($prefix);
}
$ret = isset($this->configData[$prefix][$name]) ? $this->configData[$prefix][$name] : false;
// $ret = getArrayValue($this->configData, $prefix, $name);
}
return $ret === false ? $default : $ret;
}
/**
* Read all unit with $prefix options
*
* @param string $prefix
* @return Array
* @access public
*/
function getUnitOptions($prefix)
{
if (!isset($this->configData[$prefix])) {
$this->loadConfig($prefix);
}
return $this->configData[$prefix];
}
/**
* Set's new unit option value
*
* @param string $prefix
* @param string $name
* @param string $value
* @access public
*/
function setUnitOption($prefix, $name, $value)
{
if ( preg_match('/(.*)\.(.*)/', $prefix, $rets) ) {
if ( !isset($this->configData[$rets[1]]) ) {
$this->loadConfig($rets[1]);
}
$this->configData[$rets[1]][$name][$rets[2]] = $value;
}
else {
if ( !isset($this->configData[$prefix]) ) {
$this->loadConfig($prefix);
}
$this->configData[$prefix][$name] = $value;
}
}
protected function getClasses($prefix)
{
$config =& $this->configData[$prefix];
$class_params = Array ('ItemClass', 'ListClass', 'EventHandlerClass', 'TagProcessorClass');
$register_classes = isset($config['RegisterClasses']) ? $config['RegisterClasses'] : Array ();
foreach ($class_params as $param_name) {
if ( !isset($config[$param_name]) ) {
continue;
}
$config[$param_name]['pseudo'] = $this->getPseudoByOptionName($param_name, $prefix);
$register_classes[] = $config[$param_name];
}
return $register_classes;
}
protected function getPseudoByOptionName($option_name, $prefix)
{
$pseudo_class_map = Array (
'ItemClass' => '%s',
'ListClass' => '%s_List',
'EventHandlerClass' => '%s_EventHandler',
'TagProcessorClass' => '%s_TagProcessor'
);
return sprintf($pseudo_class_map[$option_name], $prefix);
}
/**
* Get's config file name based
* on folder name supplied
*
* @param string $folderPath
* @return string
* @access private
*/
function getConfigName($folderPath)
{
return $folderPath . DIRECTORY_SEPARATOR . basename($folderPath) . '_config.php';
}
/**
* Checks if config file is allowed for includion (if module of config is installed)
*
* @param string $config_path relative path from in-portal directory
*/
function configAllowed($config_path)
{
static $module_paths = null;
if (defined('IS_INSTALL') && IS_INSTALL) {
// at installation start no modules in db and kernel configs could not be read
return true;
}
if (preg_match('#^' . $this->_directorySeparator . 'core#', $config_path)) {
// always allow to include configs from "core" module's folder
return true;
}
if (!$this->Application->ModuleInfo) {
return false;
}
if (!isset($module_paths)) {
$module_paths = Array ();
foreach ($this->Application->ModuleInfo as $module_name => $module_info) {
$module_paths[] = str_replace('/', DIRECTORY_SEPARATOR, rtrim($module_info['Path'], '/'));
}
$module_paths = array_unique($module_paths);
}
preg_match($this->_moduleFolderRegExp, $config_path, $rets);
// config file path starts with module folder path
return in_array($rets[1], $module_paths);
}
/**
* Returns true if config exists and is allowed for reading
*
* @param string $prefix
* @return bool
*/
function prefixRegistred($prefix)
{
return isset($this->prefixFiles[$prefix]) ? true : false;
}
/**
* Returns config file for given prefix
*
* @param string $prefix
* @return string
*/
function getPrefixFile($prefix)
{
return array_key_exists($prefix, $this->prefixFiles) ? $this->prefixFiles[$prefix] : false;
}
function iterateConfigs($callback_function, $params)
{
$this->includeConfigFiles(MODULES_PATH); //make sure to re-read all configs
$this->AfterConfigRead();
foreach ($this->configData as $prefix => $config_data) {
$callback_function[0]->$callback_function[1]($prefix, $config_data, $params);
}
}
}
\ No newline at end of file
Index: branches/5.2.x/core/kernel/event_handler.php
===================================================================
--- branches/5.2.x/core/kernel/event_handler.php (revision 15129)
+++ branches/5.2.x/core/kernel/event_handler.php (revision 15130)
@@ -1,197 +1,197 @@
<?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 addressing 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 current Prefix_Special
* for variables being 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
*
* @return void
* @see kEventHandler::$eventMethods
* @access protected
*/
protected function mapEvents()
{
}
/**
* Allows to override standard permission mapping
*
* @return void
* @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(kEvent &$event)
+ public function processEvent(kEvent $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
* @return void
* @access protected
*/
- protected function OnBuild(kEvent &$event)
+ protected function OnBuild(kEvent $event)
{
}
/**
* Returns to previous template in opener stack
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnGoBack(kEvent &$event)
+ protected function OnGoBack(kEvent $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, kEvent &$event)
+ protected function prepareObject(&$object, kEvent $event)
{
}
/**
* Checks user permission to execute given $event
*
* @param kEvent $event
* @return bool
* @access public
*/
- public function CheckPermission(kEvent &$event)
+ public function CheckPermission(kEvent $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
* @return void
* @access protected
*/
- protected function OnAfterConfigRead(kEvent &$event)
+ protected function OnAfterConfigRead(kEvent $event)
{
}
}
\ No newline at end of file
Index: branches/5.2.x/core/kernel/nparser/nparser_config.php
===================================================================
--- branches/5.2.x/core/kernel/nparser/nparser_config.php (revision 15129)
+++ branches/5.2.x/core/kernel/nparser/nparser_config.php (revision 15130)
@@ -1,25 +1,25 @@
<?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!');
$config = Array(
'Prefix' => 'nparser',
'EventHandlerClass' => Array('class' => 'kEventHandler', 'file' => '', 'build_event' => 'OnBuild'),
'RegisterClasses' => Array(
- Array('pseudo'=>'NParserCompiler','class'=>'NParserCompiler','file'=>'compiler.php','build_event'=>'','require_classes'=>'kHelper'),
+ Array('pseudo' => 'NParserCompiler', 'class' => 'NParserCompiler', 'file' => 'compiler.php', 'build_event' => ''),
),
);
Index: branches/5.2.x/core/kernel/kbase.php
===================================================================
--- branches/5.2.x/core/kernel/kbase.php (revision 15129)
+++ branches/5.2.x/core/kernel/kbase.php (revision 15130)
@@ -1,1091 +1,1084 @@
<?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!');
/**
* Base
*
*/
class kBase {
/**
* Reference to global kApplication instance
*
* @var kApplication
* @access protected
*/
protected $Application = null;
/**
* Connection to database
*
* @var kDBConnection
* @access protected
*/
protected $Conn = null;
/**
* Prefix, used during object creation
*
* @var string
* @access public
*/
public $Prefix = '';
/**
* Special, used during object creation
*
* @var string
* @access public
*/
public $Special = '';
/**
* Joined prefix and special, usually taken directly from
* tag beeing processed, to use in kApplication::recallObject method
*
* @var string
* @access protected
* @see kApplication::recallObject
*/
protected $prefixSpecial = '';
/**
* Set's references to kApplication and kDBConnection class instances
*
- * @param kApplication $application
* @access public
* @see kApplication
* @see kDBConnection
*/
- public function __construct($application = null)
+ public function __construct()
{
- if (!isset($application)) {
- $this->Application =& kApplication::Instance();
- }
- else {
- $this->Application =& $application;
- }
-
+ $this->Application =& kApplication::Instance();
$this->Conn =& $this->Application->GetADODBConnection();
}
/**
* Set's prefix and special
*
* @param string $prefix
* @param string $special
* @access public
*/
public function Init($prefix, $special)
{
$prefix = explode('_', $prefix, 2);
$this->Prefix = $prefix[0];
$this->Special = $special;
$this->prefixSpecial = rtrim($this->Prefix . '.' . $this->Special, '.');
}
/**
* Returns prefix and special (when present) joined by a "."
*
* @return string
* @access public
*/
public function getPrefixSpecial()
{
return $this->prefixSpecial;
}
}
class kHelper extends kBase {
/**
* Performs helper initialization
*
* @access public
*/
public function InitHelper()
{
}
/**
* Append prefix and special to tag
* params (get them from tagname) like
* they were really passed as params
*
* @param string $prefix_special
* @param Array $tag_params
* @return Array
* @access protected
*/
protected function prepareTagParams($prefix_special, $tag_params = Array())
{
$parts = explode('.', $prefix_special);
$ret = $tag_params;
$ret['Prefix'] = $parts[0];
$ret['Special'] = count($parts) > 1 ? $parts[1] : '';
$ret['PrefixSpecial'] = $prefix_special;
return $ret;
}
}
abstract class kDBBase extends kBase {
/**
* Name of primary key field for the unit
*
* @var string
* @access public
* @see kDBBase::TableName
*/
public $IDField = '';
/**
* Unit's database table name
*
* @var string
* @access public
*/
public $TableName = '';
/**
* Form name, used for validation
*
* @var string
*/
protected $formName = '';
/**
* Final form configuration
*
* @var Array
*/
protected $formConfig = Array ();
/**
* SELECT, FROM, JOIN parts of SELECT query (no filters, no limit, no ordering)
*
* @var string
* @access protected
*/
protected $SelectClause = '';
/**
* Unit fields definitions (fields from database plus virtual fields)
*
* @var Array
* @access protected
*/
protected $Fields = Array ();
/**
* Mapping between unit custom field IDs and their names
*
* @var Array
* @access protected
*/
protected $customFields = Array ();
/**
* Unit virtual field definitions
*
* @var Array
* @access protected
* @see kDBBase::getVirtualFields()
* @see kDBBase::setVirtualFields()
*/
protected $VirtualFields = Array ();
/**
* Fields that need to be queried using custom expression, e.g. IF(...) AS value
*
* @var Array
* @access protected
*/
protected $CalculatedFields = Array ();
/**
* Fields that contain aggregated functions, e.g. COUNT, SUM, etc.
*
* @var Array
* @access protected
*/
protected $AggregatedCalculatedFields = Array ();
/**
* Tells, that multilingual fields sould not be populated by default.
* Can be overriden from kDBBase::Configure method
*
* @var bool
* @access protected
*/
protected $populateMultiLangFields = false;
/**
* Event, that was used to create this object
*
* @var kEvent
* @access protected
*/
protected $parentEvent = null;
/**
* Sets new parent event to the object
*
* @param kEvent $event
* @return void
* @access public
*/
- public function setParentEvent(&$event)
+ public function setParentEvent($event)
{
$this->parentEvent =& $event;
}
/**
* Set object' TableName to LIVE table, defined in unit config
*
* @access public
*/
public function SwitchToLive()
{
$this->TableName = $this->Application->getUnitOption($this->Prefix, 'TableName');
}
/**
* Set object' TableName to TEMP table created based on table, defined in unit config
*
* @access public
*/
public function SwitchToTemp()
{
$table_name = $this->Application->getUnitOption($this->Prefix, 'TableName');
$this->TableName = $this->Application->GetTempName($table_name, 'prefix:' . $this->Prefix);
}
/**
* Checks if object uses temp table
*
* @return bool
* @access public
*/
public function IsTempTable()
{
return $this->Application->IsTempTable($this->TableName);
}
/**
* Sets SELECT part of list' query
*
* @param string $sql SELECT and FROM [JOIN] part of the query up to WHERE
* @access public
*/
public function SetSelectSQL($sql)
{
$this->SelectClause = $sql;
}
/**
* Returns object select clause without any transformations
*
* @return string
* @access public
*/
public function GetPlainSelectSQL()
{
return $this->SelectClause;
}
/**
* Returns SELECT part of list' query.
* 1. Occurrences of "%1$s" and "%s" are replaced to kDBBase::TableName
* 2. Occurrences of "%3$s" are replaced to temp table prefix (only for table, using TABLE_PREFIX)
*
* @param string $base_query given base query will override unit default select query
* @param bool $replace_table replace all possible occurrences
* @return string
* @access public
* @see kDBBase::replaceModePrefix
*/
public function GetSelectSQL($base_query = null, $replace_table = true)
{
if (!isset($base_query)) {
$base_query = $this->SelectClause;
}
if (!$replace_table) {
return $base_query;
}
$query = str_replace(Array('%1$s', '%s'), $this->TableName, $base_query);
return $this->replaceModePrefix($query);
}
/**
* Allows sub-stables to be in same mode as main item (e.g. LEFT JOINED ones)
*
* @param string $query
* @return string
* @access protected
*/
protected function replaceModePrefix($query)
{
$live_table = substr($this->Application->GetLiveName($this->TableName), strlen(TABLE_PREFIX));
if (preg_match('/'.preg_quote(TABLE_PREFIX, '/').'(.*)'.preg_quote($live_table, '/').'/', $this->TableName, $rets)) {
// will only happen, when table has a prefix (like in K4)
return str_replace('%3$s', $rets[1], $query);
}
// will happen, when K3 table without prefix is used
return $query;
}
/**
* Sets calculated fields
*
* @param Array $fields
* @access public
*/
public function setCalculatedFields($fields)
{
$this->CalculatedFields = $fields;
}
/**
* Adds calculated field declaration to object.
*
* @param string $name
* @param string $sql_clause
* @access public
*/
public function addCalculatedField($name, $sql_clause)
{
$this->CalculatedFields[$name] = $sql_clause;
}
/**
* Returns required mixing of aggregated & non-aggregated calculated fields
*
* @param int $aggregated 0 - having + aggregated, 1 - having only, 2 - aggregated only
* @return Array
* @access public
*/
public function getCalculatedFields($aggregated = 1)
{
switch ($aggregated) {
case 0:
$fields = array_merge($this->CalculatedFields, $this->AggregatedCalculatedFields);
break;
case 1:
$fields = $this->CalculatedFields;
break;
case 2:
$fields = $this->AggregatedCalculatedFields; // TODO: never used
break;
default:
$fields = Array();
break;
}
return $fields;
}
/**
* Checks, that given field is a calculated field
*
* @param string $field
* @return bool
* @access public
*/
public function isCalculatedField($field)
{
return array_key_exists($field, $this->CalculatedFields);
}
/**
* Insert calculated fields sql into query in place of %2$s,
* return processed query.
*
* @param string $query
* @param int $aggregated 0 - having + aggregated, 1 - having only, 2 - aggregated only
* @return string
* @access protected
*/
protected function addCalculatedFields($query, $aggregated = 1)
{
$fields = $this->getCalculatedFields($aggregated);
if ($fields) {
$sql = Array ();
$fields = str_replace('%2$s', $this->Application->GetVar('m_lang'), $fields);
foreach ($fields as $field_name => $field_expression) {
$sql[] = '('.$field_expression.') AS `'.$field_name.'`';
}
$sql = implode(',',$sql);
return $this->Application->ReplaceLanguageTags( str_replace('%2$s', ','.$sql, $query) );
}
return str_replace('%2$s', '', $query);
}
/**
* Performs initial object configuration, which includes setting the following:
* - primary key and table name
* - field definitions (including field modifiers, formatters, default values)
*
* @param bool $populate_ml_fields create all ml fields from db in config or not
* @param string $form_name form name for validation
* @access public
*/
public function Configure($populate_ml_fields = null, $form_name = null)
{
if ( isset($populate_ml_fields) ) {
$this->populateMultiLangFields = $populate_ml_fields;
}
$this->IDField = $this->Application->getUnitOption($this->Prefix, 'IDField');
$this->TableName = $this->Application->getUnitOption($this->Prefix, 'TableName');
$this->initForm($form_name);
$this->defineFields();
$this->ApplyFieldModifiers(null, true); // should be called only after all fields definitions been set
$this->prepareConfigOptions(); // this should go last, but before setDefaultValues, order is significant!
// only set on first call of method
if ( isset($populate_ml_fields) ) {
$this->SetDefaultValues();
}
}
/**
* Adjusts object according to given form name
*
* @param string $form_name
* @return void
* @access protected
*/
protected function initForm($form_name = null)
{
$forms = $this->Application->getUnitOption($this->Prefix, 'Forms', Array ());
$this->formName = $form_name;
$this->formConfig = isset($forms['default']) ? $forms['default'] : Array ();
if ( !$this->formName ) {
return ;
}
if ( !isset($forms[$this->formName]) ) {
trigger_error('Form "<strong>' . $this->formName . '</strong>" isn\'t declared in "<strong>' . $this->Prefix . '</strong>" unit config.', E_USER_NOTICE);
}
else {
$this->formConfig = kUtil::array_merge_recursive($this->formConfig, $forms[$this->formName]);
}
}
/**
* Add field definitions from all possible sources
* Used field sources: database fields, custom fields, virtual fields, calculated fields, aggregated calculated fields
*
* @access protected
*/
protected function defineFields()
{
$this->Fields = $this->getFormOption('Fields', Array ());
$this->customFields = $this->getFormOption('CustomFields', Array());
$this->setVirtualFields( $this->getFormOption('VirtualFields', Array ()) );
$calculated_fields = $this->getFormOption('CalculatedFields', Array());
$this->CalculatedFields = $this->getFieldsBySpecial($calculated_fields);
$aggregated_calculated_fields = $this->getFormOption('AggregatedCalculatedFields', Array());
$this->AggregatedCalculatedFields = $this->getFieldsBySpecial($aggregated_calculated_fields);
}
/**
* Returns form name, used for validation
*
* @return string
*/
public function getFormName()
{
return $this->formName;
}
/**
* Reads unit (specified by $prefix) option specified by $option and applies form change to it
*
* @param string $option
* @param mixed $default
* @return string
* @access public
*/
public function getFormOption($option, $default = false)
{
$ret = $this->Application->getUnitOption($this->Prefix, $option, $default);
if ( isset($this->formConfig[$option]) ) {
$ret = kUtil::array_merge_recursive($ret, $this->formConfig[$option]);
}
return $ret;
}
/**
* Only exteracts fields, that match current object Special
*
* @param Array $fields
* @return Array
* @access protected
*/
protected function getFieldsBySpecial($fields)
{
if ( array_key_exists($this->Special, $fields) ) {
return $fields[$this->Special];
}
return array_key_exists('', $fields) ? $fields[''] : Array();
}
/**
* Sets aggeregated calculated fields
*
* @param Array $fields
* @access public
*/
public function setAggregatedCalculatedFields($fields)
{
$this->AggregatedCalculatedFields = $fields;
}
/**
* Set's field names from table from config
*
* @param Array $fields
* @access public
*/
public function setCustomFields($fields)
{
$this->customFields = $fields;
}
/**
* Returns custom fields information from table from config
*
* @return Array
* @access public
*/
public function getCustomFields()
{
return $this->customFields;
}
/**
* Set's fields information from table from config
*
* @param Array $fields
* @access public
*/
public function setFields($fields)
{
$this->Fields = $fields;
}
/**
* Returns fields information from table from config
*
* @return Array
* @access public
*/
public function getFields()
{
return $this->Fields;
}
/**
* Checks, that given field exists
*
* @param string $field
* @return bool
* @access public
*/
public function isField($field)
{
return array_key_exists($field, $this->Fields);
}
/**
* Override field options with ones defined in submit via "field_modfiers" array (common for all prefixes)
*
* @param Array $field_modifiers
* @param bool $from_submit
* @return void
* @access public
* @author Alex
*/
public function ApplyFieldModifiers($field_modifiers = null, $from_submit = false)
{
$allowed_modifiers = Array ('required', 'multiple');
if ( $this->Application->isAdminUser ) {
// can change upload dir on the fly (admin only!)
$allowed_modifiers[] = 'upload_dir';
}
if ( !isset($field_modifiers) ) {
$field_modifiers = $this->Application->GetVar('field_modifiers');
if ( !$field_modifiers ) {
// no field modifiers
return;
}
$field_modifiers = getArrayValue($field_modifiers, $this->getPrefixSpecial());
}
if ( !$field_modifiers ) {
// no field modifiers for current prefix_special
return;
}
$fields = $this->Application->getUnitOption($this->Prefix, 'Fields', Array ());
$virtual_fields = $this->Application->getUnitOption($this->Prefix, 'VirtualFields', Array ());
foreach ($field_modifiers as $field => $field_options) {
foreach ($field_options as $option_name => $option_value) {
if ( !in_array(strtolower($option_name), $allowed_modifiers) ) {
continue;
}
if ( $from_submit ) {
// there are no "lN_FieldName" fields, since ApplyFieldModifiers is
// called before PrepareOptions method, which creates them
$field = preg_replace('/^l[\d]+_(.*)/', '\\1', $field);
}
if ( $this->isVirtualField($field) ) {
$virtual_fields[$field][$option_name] = $option_value;
$this->SetFieldOption($field, $option_name, $option_value, true);
}
$fields[$field][$option_name] = $option_value;
$this->SetFieldOption($field, $option_name, $option_value);
}
}
$this->Application->setUnitOption($this->Prefix, 'Fields', $fields);
$this->Application->setUnitOption($this->Prefix, 'VirtualFields', $virtual_fields);
}
/**
* Set fields (+options) for fields that physically doesn't exist in database
*
* @param Array $fields
* @access public
*/
public function setVirtualFields($fields)
{
if ($fields) {
$this->VirtualFields = $fields;
$this->Fields = array_merge($this->VirtualFields, $this->Fields);
}
}
/**
* Returns virtual fields
*
* @return Array
* @access public
*/
public function getVirtualFields()
{
return $this->VirtualFields;
}
/**
* Checks, that given field is a virtual field
*
* @param string $field
* @return bool
* @access public
*/
public function isVirtualField($field)
{
return array_key_exists($field, $this->VirtualFields);
}
/**
* Performs additional initialization for field default values
*
* @access protected
*/
protected function SetDefaultValues()
{
foreach ($this->Fields as $field => $options) {
if ( array_key_exists('default', $options) && $options['default'] === '#NOW#' ) {
$this->Fields[$field]['default'] = adodb_mktime();
}
}
}
/**
* Overwrites field definition in unit config
*
* @param string $field
* @param Array $options
* @param bool $is_virtual
* @access public
*/
public function SetFieldOptions($field, $options, $is_virtual = false)
{
if ($is_virtual) {
$this->VirtualFields[$field] = $options;
$this->Fields = array_merge($this->VirtualFields, $this->Fields);
}
else {
$this->Fields[$field] = $options;
}
}
/**
* Changes/sets given option's value in given field definiton
*
* @param string $field
* @param string $option_name
* @param mixed $option_value
* @param bool $is_virtual
* @access public
*/
public function SetFieldOption($field, $option_name, $option_value, $is_virtual = false)
{
if ($is_virtual) {
$this->VirtualFields[$field][$option_name] = $option_value;
}
$this->Fields[$field][$option_name] = $option_value;
}
/**
* Returns field definition from unit config.
* Also executes sql from "options_sql" field option to form "options" field option
*
* @param string $field
* @param bool $is_virtual
* @return Array
* @access public
*/
public function GetFieldOptions($field, $is_virtual = false)
{
$property_name = $is_virtual ? 'VirtualFields' : 'Fields';
if ( !array_key_exists($field, $this->$property_name) ) {
return Array ();
}
if (!$is_virtual) {
if (!array_key_exists('options_prepared', $this->Fields[$field]) || !$this->Fields[$field]['options_prepared']) {
// executes "options_sql" from field definition, only when field options are accessed (late binding)
$this->PrepareFieldOptions($field);
$this->Fields[$field]['options_prepared'] = true;
}
}
return $this->{$property_name}[$field];
}
/**
* Returns field option
*
* @param string $field
* @param string $option_name
* @param bool $is_virtual
* @param mixed $default
* @return mixed
* @access public
*/
public function GetFieldOption($field, $option_name, $is_virtual = false, $default = false)
{
$field_options = $this->GetFieldOptions($field, $is_virtual);
if ( !$field_options && strpos($field, '#') === false ) {
// we use "#FIELD_NAME#" as field for InputName tag in JavaScript, so ignore it
$form_name = $this->getFormName();
trigger_error('Field "<strong>' . $field . '</strong>" is not defined' . ($form_name ? ' on "<strong>' . $this->getFormName() . '</strong>" form' : '') . ' in "<strong>' . $this->Prefix . '</strong>" unit config', E_USER_WARNING);
return false;
}
return array_key_exists($option_name, $field_options) ? $field_options[$option_name] : $default;
}
/**
* Returns formatted field value
*
* @param string $name
* @param string $format
*
* @return string
* @access protected
*/
public function GetField($name, $format = null)
{
$formatter_class = $this->GetFieldOption($name, 'formatter');
if ( $formatter_class ) {
$value = ($formatter_class == 'kMultiLanguage') && !preg_match('/^l[0-9]+_/', $name) ? '' : $this->GetDBField($name);
$formatter =& $this->Application->recallObject($formatter_class);
/* @var $formatter kFormatter */
return $formatter->Format($value, $name, $this, $format);
}
return $this->GetDBField($name);
}
/**
* Returns unformatted field value
*
* @param string $field
* @return string
* @access protected
*/
abstract protected function GetDBField($field);
/**
* Checks of object has given field
*
* @param string $name
* @return bool
* @access protected
*/
abstract protected function HasField($name);
/**
* Returns field values
*
* @return Array
* @access protected
*/
abstract protected function GetFieldValues();
/**
* Populates values of sub-fields, based on formatters, set to mater fields
*
* @param Array $fields
* @access public
* @todo Maybe should not be publicly accessible
*/
public function UpdateFormattersSubFields($fields = null)
{
if ( !is_array($fields) ) {
$fields = array_keys($this->Fields);
}
foreach ($fields as $field) {
if ( isset($this->Fields[$field]['formatter']) ) {
$formatter =& $this->Application->recallObject($this->Fields[$field]['formatter']);
/* @var $formatter kFormatter */
$formatter->UpdateSubFields($field, $this->GetDBField($field), $this->Fields[$field], $this);
}
}
}
/**
* Use formatters, specified in field declarations to perform additional field initialization in unit config
*
* @access protected
*/
protected function prepareConfigOptions()
{
$field_names = array_keys($this->Fields);
foreach ($field_names as $field_name) {
if ( !array_key_exists('formatter', $this->Fields[$field_name]) ) {
continue;
}
$formatter =& $this->Application->recallObject( $this->Fields[$field_name]['formatter'] );
/* @var $formatter kFormatter */
$formatter->PrepareOptions($field_name, $this->Fields[$field_name], $this);
}
}
/**
* Escapes fields only, not expressions
*
* @param string $field_expr
* @return string
* @access protected
*/
protected function escapeField($field_expr)
{
return preg_match('/[.(]/', $field_expr) ? $field_expr : '`' . $field_expr . '`';
}
/**
* Replaces current language id in given field options
*
* @param string $field_name
* @param Array $field_option_names
* @access protected
*/
protected function _replaceLanguageId($field_name, $field_option_names)
{
// don't use GetVar('m_lang') since it's always equals to default language on editing form in admin
$current_language_id = $this->Application->Phrases->LanguageId;
$primary_language_id = $this->Application->GetDefaultLanguageId();
$field_options =& $this->Fields[$field_name];
foreach ($field_option_names as $option_name) {
$field_options[$option_name] = str_replace('%2$s', $current_language_id, $field_options[$option_name]);
$field_options[$option_name] = str_replace('%3$s', $primary_language_id, $field_options[$option_name]);
}
}
/**
* Transforms "options_sql" field option into valid "options" array for given field
*
* @param string $field_name
* @access protected
*/
protected function PrepareFieldOptions($field_name)
{
$field_options =& $this->Fields[$field_name];
if (array_key_exists('options_sql', $field_options) ) {
// get options based on given sql
$replace_options = Array ('option_title_field', 'option_key_field', 'options_sql');
$this->_replaceLanguageId($field_name, $replace_options);
$select_clause = $this->escapeField($field_options['option_title_field']) . ',' . $this->escapeField($field_options['option_key_field']);
$sql = sprintf($field_options['options_sql'], $select_clause);
if (array_key_exists('serial_name', $field_options)) {
// try to cache option sql on serial basis
$cache_key = 'sql_' . crc32($sql) . '[%' . $field_options['serial_name'] . '%]';
$dynamic_options = $this->Application->getCache($cache_key);
if ($dynamic_options === false) {
$this->Conn->nextQueryCachable = true;
$dynamic_options = $this->Conn->GetCol($sql, preg_replace('/^.*?\./', '', $field_options['option_key_field']));
$this->Application->setCache($cache_key, $dynamic_options);
}
}
else {
// don't cache options sql
$dynamic_options = $this->Conn->GetCol($sql, preg_replace('/^.*?\./', '', $field_options['option_key_field']));
}
$options_hash = array_key_exists('options', $field_options) ? $field_options['options'] : Array ();
$field_options['options'] = kUtil::array_merge_recursive($options_hash, $dynamic_options); // because of numeric keys
}
}
/**
* Returns ID of currently processed record
*
* @return int
* @access public
*/
public function GetID()
{
return $this->GetDBField($this->IDField);
}
/**
* Allows kDBTagProcessor.SectionTitle to detect if it's editing or new item creation
*
* @return bool
* @access public
*/
public function IsNewItem()
{
return $this->GetID() ? false : true;
}
/**
* Returns parent table information
*
* @param string $special special of main item
* @param bool $guess_special if object retrieved with specified special is not loaded, then try not to use special
* @return Array
* @access public
*/
public function getLinkedInfo($special = '', $guess_special = false)
{
$parent_prefix = $this->Application->getUnitOption($this->Prefix, 'ParentPrefix');
if ($parent_prefix) {
// if this is linked table, then set id from main table
$table_info = Array (
'TableName' => $this->Application->getUnitOption($this->Prefix,'TableName'),
'IdField' => $this->Application->getUnitOption($this->Prefix,'IDField'),
'ForeignKey' => $this->Application->getUnitOption($this->Prefix,'ForeignKey'),
'ParentTableKey' => $this->Application->getUnitOption($this->Prefix,'ParentTableKey'),
'ParentPrefix' => $parent_prefix
);
if (is_array($table_info['ForeignKey'])) {
$table_info['ForeignKey'] = getArrayValue($table_info, 'ForeignKey', $parent_prefix);
}
if (is_array($table_info['ParentTableKey'])) {
$table_info['ParentTableKey'] = getArrayValue($table_info, 'ParentTableKey', $parent_prefix);
}
$main_object =& $this->Application->recallObject($parent_prefix.'.'.$special, null, Array ('raise_warnings' => 0));
/* @var $main_object kDBItem */
if (!$main_object->isLoaded() && $guess_special) {
$main_object =& $this->Application->recallObject($parent_prefix);
}
return array_merge($table_info, Array('ParentId'=> $main_object->GetDBField( $table_info['ParentTableKey'] ) ) );
}
return false;
}
/**
* Returns true, when list/item was queried/loaded
*
* @return bool
* @access protected
*/
abstract protected function isLoaded();
/**
* Returns specified field value from all selected rows.
* Don't affect current record index
*
* @param string $field
* @return Array
* @access protected
*/
abstract protected function GetCol($field);
}
\ 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 15129)
+++ branches/5.2.x/core/units/priorites/priority_eh.php (revision 15130)
@@ -1,398 +1,398 @@
<?php
/**
* @version $Id$
* @package In-Portal
* @copyright Copyright (C) 1997 - 2011 Intechnic. All rights reserved.
* @license GNU/GPL
* In-Portal is Open Source software.
* This means that this software may have been modified pursuant
* the GNU General Public License, and as distributed it includes
* or is derivative of works licensed under the GNU General Public License
* or other free or open source software licenses.
* See http://www.in-portal.org/license for copyright notices and details.
*/
defined('FULL_PATH') or die('restricted access!');
class PriorityEventHandler extends kDBEventHandler {
/**
* Allows to override standard permission mapping
*
* @return void
* @access protected
* @see kEventHandler::$permMapping
*/
protected function mapPermissions()
{
parent::mapPermissions();
$permissions = Array (
'OnRecalculatePriorities' => Array ('self' => true),
);
$this->permMapping = array_merge($this->permMapping, $permissions);
}
/**
* Define alternative event processing method names
*
* @return void
* @see kEventHandler::$eventMethods
* @access protected
*/
protected function mapEvents()
{
parent::mapEvents();
$events_map = Array (
'OnMassMoveUp' => 'OnChangePriority',
'OnMassMoveDown' => 'OnChangePriority',
);
$this->eventMethods = array_merge($this->eventMethods, $events_map);
}
/**
* Occurs, when config was parsed, allows to change config data dynamically
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnAfterConfigRead(kEvent &$event)
+ protected function OnAfterConfigRead(kEvent $event)
{
parent::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)
+ 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)
+ 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)
+ 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)
+ 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)
+ 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)
+ 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)
+ 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)
+ 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' ) );
+ $dummy_event = new kEvent($prefix . ':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)
+ 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 15129)
+++ branches/5.2.x/core/units/visits/visits_event_handler.php (revision 15130)
@@ -1,143 +1,143 @@
<?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 standard permission mapping
*
* @return void
* @access protected
* @see kEventHandler::$permMapping
*/
protected 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)
+ 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(kEvent &$event)
+ protected function SetCustomQuery(kEvent $event)
{
parent::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, kEvent &$event)
+ protected function prepareObject(&$object, kEvent $event)
{
$types = $event->getEventParam('types');
if ( method_exists($object, 'AddGroupByField') ) {
if ( (!$types || $types == 'myvisitors') && $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)
+ 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/thesaurus/thesaurus_eh.php
===================================================================
--- branches/5.2.x/core/units/thesaurus/thesaurus_eh.php (revision 15129)
+++ branches/5.2.x/core/units/thesaurus/thesaurus_eh.php (revision 15130)
@@ -1,39 +1,39 @@
<?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 ThesaurusEventHandler extends kDBEventHandler {
/**
* Shows only thesaurus terms, that matches searched keywords
*
* @param kEvent $event
* @return void
* @access protected
* @see kDBEventHandler::OnListBuild()
*/
- protected function SetCustomQuery(kEvent &$event)
+ protected function SetCustomQuery(kEvent $event)
{
parent::SetCustomQuery($event);
$object =& $event->getObject();
/* @var $object kDBList */
if ( !$this->Application->isAdminUser ) {
$keywords = kUtil::unhtmlentities(trim($this->Application->GetVar('keywords')));
$object->addFilter('search_filter', '%1$s.SearchTerm LIKE ' . $this->Conn->qstr($keywords) . ' OR %1$s.SearchTerm LIKE ' . $this->Conn->qstr($keywords . '_'));
}
}
}
\ 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 15129)
+++ branches/5.2.x/core/units/theme_files/theme_file_eh.php (revision 15130)
@@ -1,233 +1,233 @@
<?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 standard permission mapping
*
* @return void
* @access protected
* @see kEventHandler::$permMapping
*/
protected 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(kEvent &$event)
+ public function CheckPermission(kEvent $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(kEvent &$event)
+ protected function OnAfterItemLoad(kEvent $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(kEvent &$event)
+ protected function OnBeforeItemUpdate(kEvent $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
* @return void
* @access protected
*/
- protected function OnAfterItemUpdate(kEvent &$event)
+ protected function OnAfterItemUpdate(kEvent $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)
+ 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)
+ 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, $this->getRequestProtectedFields($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)
+ 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 15129)
+++ branches/5.2.x/core/units/categories/categories_tag_processor.php (revision 15130)
@@ -1,2178 +1,2178 @@
<?php
/**
* @version $Id$
* @package In-Portal
* @copyright Copyright (C) 1997 - 2011 Intechnic. All rights reserved.
* @license GNU/GPL
* In-Portal is Open Source software.
* This means that this software may have been modified pursuant
* the GNU General Public License, and as distributed it includes
* or is derivative of works licensed under the GNU General Public License
* or other free or open source software licenses.
* See http://www.in-portal.org/license for copyright notices and details.
*/
defined('FULL_PATH') or die('restricted access!');
class CategoriesTagProcessor extends kDBTagProcessor {
function SubCatCount($params)
{
$object =& $this->getObject($params);
/* @var $object kDBItem */
if ( isset($params['today']) && $params['today'] ) {
$sql = 'SELECT COUNT(*)
FROM ' . $object->TableName . '
WHERE (ParentPath LIKE "' . $object->GetDBField('ParentPath') . '%") AND (CreatedOn > ' . (adodb_mktime() - 86400) . ')';
return $this->Conn->GetOne($sql) - 1;
}
return $object->GetDBField('CachedDescendantCatsQty');
}
/**
* Returns category count in system
*
* @param Array $params
* @return int
*/
function CategoryCount($params)
{
$count_helper =& $this->Application->recallObject('CountHelper');
/* @var $count_helper kCountHelper */
$today_only = isset($params['today']) && $params['today'];
return $count_helper->CategoryCount($today_only);
}
function IsNew($params)
{
$object =& $this->getObject($params);
/* @var $object kDBItem */
return $object->GetDBField('IsNew') ? 1 : 0;
}
function IsPick($params)
{
return $this->IsEditorsPick($params);
}
/**
* Returns item's editors pick status (using not formatted value)
*
* @param Array $params
* @return bool
*/
function IsEditorsPick($params)
{
$object =& $this->getObject($params);
/* @var $object kDBItem */
return $object->GetDBField('EditorsPick') == 1;
}
function ItemIcon($params)
{
$grids = $this->Application->getUnitOption($this->Prefix, 'Grids');
$grid = $grids[ $params['grid'] ];
if (!array_key_exists('Icons', $grid)) {
return '';
}
$icons = $grid['Icons'];
$icon_prefix = array_key_exists('icon_prefix', $params)? $params['icon_prefix'] : 'icon16_';
if (array_key_exists('name', $params)) {
$icon_name = $params['name'];
return array_key_exists($icon_name, $icons) ? $icons[$icon_name] : '';
}
$object =& $this->getObject($params);
/* @var $object kDBList */
if ($object->GetDBField('ThemeId') > 0) {
if (!$object->GetDBField('IsMenu')) {
return $icon_prefix . 'section_menuhidden_system.png';
}
return $icon_prefix . 'section_system.png';
}
$status = $object->GetDBField('Status');
if ($status == STATUS_DISABLED) {
return $icon_prefix . 'section_disabled.png';
}
if (!$object->GetDBField('IsMenu')) {
return $icon_prefix . 'section_menuhidden.png';
}
if ($status == STATUS_PENDING) {
return $icon_prefix . 'section_pending.png';
}
if ($object->GetDBField('IsNew') && ($icon_prefix == 'icon16_')) {
return $icon_prefix . 'section_new.png'; // show gris icon only in grids
}
return $icon_prefix . 'section.png';
}
function ItemCount($params)
{
$object =& $this->getObject($params);
/* @var $object kDBItem */
$ci_table = $this->Application->getUnitOption('ci', 'TableName');
$module_prefixes = implode(',', $this->Conn->qstrArray($this->_getModulePrefixes()));
$sql = 'SELECT COUNT(*)
FROM ' . $object->TableName . ' c
JOIN ' . $ci_table . ' ci ON c.CategoryId = ci.CategoryId
WHERE (c.TreeLeft BETWEEN ' . $object->GetDBField('TreeLeft') . ' AND ' . $object->GetDBField('TreeRight') . ') AND (ci.ItemPrefix IN (' . $module_prefixes . '))';
return $this->Conn->GetOne($sql);
}
function _getModulePrefixes()
{
$ret = Array ();
foreach ($this->Application->ModuleInfo as $module_info) {
$ret[] = $module_info['Var'];
}
return array_unique($ret);
}
function ListCategories($params)
{
return $this->PrintList2($params);
}
function RootCategoryName($params)
{
return $this->Application->ProcessParsedTag('m', 'RootCategoryName', $params);
}
function CheckModuleRoot($params)
{
$module_name = getArrayValue($params, 'module') ? $params['module'] : 'In-Commerce';
$module_root_cat = $this->Application->findModule('Name', $module_name, 'RootCat');
$additional_cats = $this->SelectParam($params, 'add_cats');
if ($additional_cats) {
$additional_cats = explode(',', $additional_cats);
}
else {
$additional_cats = array();
}
if ($this->Application->GetVar('m_cat_id') == $module_root_cat || in_array($this->Application->GetVar('m_cat_id'), $additional_cats)) {
$home_template = getArrayValue($params, 'home_template');
if (!$home_template) return;
$this->Application->Redirect($home_template, Array('pass'=>'all'));
};
}
function CategoryPath($params)
{
$category_helper =& $this->Application->recallObject('CategoryHelper');
/* @var $category_helper CategoryHelper */
return $category_helper->NavigationBar($params);
}
/**
* Shows category path to specified category
*
* @param Array $params
* @return string
*/
function FieldCategoryPath($params)
{
$object =& $this->getObject();
/* @var $object kDBItem */
$field = $this->SelectParam($params, 'name,field');
$category_id = $object->GetDBField($field);
if ($category_id) {
$params['cat_id'] = $category_id;
return $this->CategoryPath($params);
}
return '';
}
function CurrentCategoryName($params)
{
$cat_object =& $this->Application->recallObject($this->getPrefixSpecial(), $this->Prefix.'_List');
/* @var $cat_object kDBList */
$sql = 'SELECT '.$this->getTitleField().'
FROM '.$cat_object->TableName.'
WHERE CategoryId = '.(int)$this->Application->GetVar('m_cat_id');
return $this->Conn->GetOne($sql);
}
/**
* Returns current category name
*
* @param Array $params
* @return string
* @todo Find where it's used
*/
function CurrentCategory($params)
{
return $this->CurrentCategoryName($params);
}
function getTitleField()
{
$ml_formatter =& $this->Application->recallObject('kMultiLanguage');
/* @var $ml_formatter kMultiLanguage */
return $ml_formatter->LangFieldName('Name');
}
/**
* Returns symlinked category for given category
*
* @param int $category_id
* @return int
*/
function getCategorySymLink($category_id)
{
if (!$category_id) {
// don't bother to get symlink for "Home" category
return $category_id;
}
$cache_key = 'category_symlinks[%CSerial%]';
$cache = $this->Application->getCache($cache_key);
if ($cache === false) {
$id_field = $this->Application->getUnitOption($this->Prefix, 'IDField');
$table_name = $this->Application->getUnitOption($this->Prefix, 'TableName');
// get symlinked categories, that are not yet deleted
$this->Conn->nextQueryCachable = true;
$sql = 'SELECT c1.SymLinkCategoryId, c1.' . $id_field . '
FROM ' . $table_name . ' c1
JOIN ' . $table_name . ' c2 ON c1.SymLinkCategoryId = c2.' . $id_field;
$cache = $this->Conn->GetCol($sql, $id_field);
$this->Application->setCache($cache_key, $cache);
}
return array_key_exists($category_id, $cache) ? $cache[$category_id] : $category_id;
}
function CategoryLink($params)
{
$category_id = getArrayValue($params, 'cat_id');
if ( $category_id === false ) {
$category_id = $this->Application->GetVar($this->getPrefixSpecial() . '_id');
}
if ( "$category_id" == 'Root' ) {
$category_id = $this->Application->findModule('Name', $params['module'], 'RootCat');
}
elseif ( "$category_id" == 'current' ) {
$category_id = $this->Application->GetVar('m_cat_id');
}
if ( !array_key_exists('direct_link', $params) || !$params['direct_link'] ) {
$category_id = $this->getCategorySymLink((int)$category_id);
}
else {
unset($params['direct_link']);
}
$virtual_template = $this->Application->getVirtualPageTemplate($category_id);
if ( ($virtual_template !== false) && preg_match('/external:(.*)/', $virtual_template, $rets) ) {
// external url (return here, instead of always replacing $params['t'] for kApplication::HREF to find it)
return $rets[1];
}
unset($params['cat_id'], $params['module']);
$new_params = Array ('pass' => 'm', 'm_cat_id' => $category_id, 'pass_category' => 1);
$params = array_merge($params, $new_params);
return $this->Application->ProcessParsedTag('m', 't', $params);
}
function CategoryList($params)
{
//$object =& $this->Application->recallObject( $this->getPrefixSpecial() , $this->Prefix.'_List', $params );
$object =& $this->GetList($params);
if ($object->GetRecordsCount() == 0)
{
if (isset($params['block_no_cats'])) {
$params['name'] = $params['block_no_cats'];
return $this->Application->ParseBlock($params);
}
else {
return '';
}
}
if (isset($params['block'])) {
return $this->PrintList($params);
}
else {
$params['block'] = $params['block_main'];
if (isset($params['block_row_start'])) {
$params['row_start_block'] = $params['block_row_start'];
}
if (isset($params['block_row_end'])) {
$params['row_end_block'] = $params['block_row_end'];
}
return $this->PrintList2($params);
}
}
function Meta($params)
{
$object =& $this->Application->recallObject($this->Prefix); // .'.-item'
/* @var $object CategoriesItem */
$meta_type = $params['name'];
if ($object->isLoaded()) {
// 1. get module prefix by current category
$category_helper =& $this->Application->recallObject('CategoryHelper');
/* @var $category_helper CategoryHelper */
$category_path = explode('|', substr($object->GetDBField('ParentPath'), 1, -1));
$module_info = $category_helper->getCategoryModule($params, $category_path);
// In-Edit & Proj-CMS module prefixes doesn't have custom field with item template
if ($module_info && $module_info['Var'] != 'adm' && $module_info['Var'] != 'st') {
// 2. get item template by current category & module prefix
$rewrite_processor = $this->Application->recallObject('kRewriteUrlProcessor');
/* @var $rewrite_processor kRewriteUrlProcessor */
$category_params = Array (
'CategoryId' => $object->GetID(),
'ParentPath' => $object->GetDBField('ParentPath'),
);
$item_template = $rewrite_processor->GetItemTemplate($category_params, $module_info['Var']);
if ($this->Application->GetVar('t') == $item_template) {
// we are located on item's details page
$item =& $this->Application->recallObject($module_info['Var']);
/* @var $item kCatDBItem */
// 3. get item's meta data
$value = $item->GetField('Meta'.$meta_type);
if ($value) {
return $value;
}
}
// 4. get category meta data
$value = $object->GetField('Meta'.$meta_type);
if ($value) {
return $value;
}
}
}
// 5. get default meta data
switch ($meta_type) {
case 'Description':
$config_name = 'Category_MetaDesc';
break;
case 'Keywords':
$config_name = 'Category_MetaKey';
break;
}
return $this->Application->ConfigValue($config_name);
}
function BuildListSpecial($params)
{
if (($this->Special != '') && !is_numeric($this->Special)) {
// When recursive category list is printed (like in sitemap), then special
// should be generated even if it's already present. Without it list on this
// level will erase list on previous level, because it will be stored in same object.
return $this->Special;
}
if ( isset($params['parent_cat_id']) ) {
$parent_cat_id = $params['parent_cat_id'];
}
else {
$parent_cat_id = $this->Application->GetVar($this->Prefix.'_id');
if (!$parent_cat_id) {
$parent_cat_id = $this->Application->GetVar('m_cat_id');
}
if (!$parent_cat_id) {
$parent_cat_id = 0;
}
}
$list_unique_key = $this->getUniqueListKey($params);
// check for "admin" variable, because we are parsing front-end template from admin when using template editor feature
if ($this->Application->GetVar('admin') || !$this->Application->isAdmin) {
// add parent category to special, when on Front-End,
// because there can be many category lists on same page
$list_unique_key .= $parent_cat_id;
}
if ($list_unique_key == '') {
return parent::BuildListSpecial($params);
}
return crc32($list_unique_key);
}
function IsCurrent($params)
{
$object =& $this->getObject($params);
if ($object->GetID() == $this->Application->GetVar('m_cat_id')) {
return true;
}
else {
return false;
}
}
/**
* Substitutes category in last template base on current category
* This is required becasue when you navigate catalog using AJAX, last_template is not updated
* but when you open item edit from catalog last_template is used to build opener_stack
* So, if we don't substitute m_cat_id in last_template, after saving item we'll get redirected
* to the first category we've opened, not the one we navigated to using AJAX
*
* @param Array $params
*/
function UpdateLastTemplate($params)
{
$category_id = $this->Application->GetVar('m_cat_id');
$wid = $this->Application->GetVar('m_wid');
list($index_file, $env) = explode('|', $this->Application->RecallVar(rtrim('last_template_'.$wid, '_')), 2);
$vars_backup = Array ();
$vars = $this->Application->processQueryString( str_replace('%5C', '\\', $env) );
foreach ($vars as $var_name => $var_value) {
$vars_backup[$var_name] = $this->Application->GetVar($var_name);
$this->Application->SetVar($var_name, $var_value);
}
// update required fields
$this->Application->SetVar('m_cat_id', $category_id);
$this->Application->Session->SaveLastTemplate($params['template']);
foreach ($vars_backup as $var_name => $var_value) {
$this->Application->SetVar($var_name, $var_value);
}
}
function GetParentCategory($params)
{
$parent_id = $this->Application->getBaseCategory();
$category_id = $this->Application->GetVar('m_cat_id');
if ($category_id != $parent_id) {
$sql = 'SELECT ParentId
FROM ' . $this->Application->getUnitOption($this->Prefix, 'TableName') . '
WHERE ' . $this->Application->getUnitOption($this->Prefix, 'IDField') . ' = ' . $category_id;
$parent_id = $this->Conn->GetOne($sql);
}
return $parent_id;
}
function InitCacheUpdater($params)
{
kUtil::safeDefine('CACHE_PERM_CHUNK_SIZE', 30);
$continue = $this->Application->GetVar('continue');
$total_cats = (int) $this->Conn->GetOne('SELECT COUNT(*) FROM '.TABLE_PREFIX.'Categories');
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->HandleEvent(new kEvent('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 Categories, 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 . 'Categories
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 = isset($params['template']) ? $params['template'] : '';
if ( $template ) {
// when using from "c:CachedMenu" tag
$sql = 'SELECT ParentPath
FROM ' . TABLE_PREFIX . 'Categories
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 . 'Categories
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 . 'Categories';
}
$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 ) {
$name = getArrayValue($params, 'name');
if ( $name ) {
$num = crc32($name);
}
}
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_helper =& $this->Application->recallObject('PageHelper');
/* @var $page_helper PageHelper */
$content =& $this->Application->recallObject('content.-block', null, Array ('skip_autoload' => true));
/* @var $content kDBItem */
if ( !$page_helper->loadContentBlock($content, $page, $num) && EDITING_MODE ) {
$page_helper->createNewContentBlock($page->GetID(), $num);
$page_helper->loadContentBlock($content, $page, $num);
}
$edit_code_before = $edit_code_after = '';
if (EDITING_MODE == EDITING_MODE_CONTENT) {
$bg_color = isset($params['bgcolor']) ? $params['bgcolor'] : '#ffffff';
$url_params = Array (
'pass' => 'm,c,content',
'm_opener' => 'd',
'c_id' => $page->GetID(),
'content_id' => $content->GetID(),
'front' => 1,
'admin' => 1,
'__URLENCODE__' => 1,
'__NO_REWRITE__'=> 1,
'escape' => 1,
'index_file' => 'index.php',
// 'bgcolor' => $bg_color,
// '__FORCE_SID__' => 1
);
// link from Front-End to admin, don't remove "index.php"
$edit_url = $this->Application->HREF('categories/edit_content', ADMIN_DIRECTORY, $url_params, 'index.php');
$edit_code_before = '
<div class="cms-edit-btn-container">
<div class="cms-edit-btn" onclick="$form_name=\'kf_cont_'.$content->GetID().'\'; std_edit_item(\'content\', \'categories/edit_content\');">
<div class="cms-btn-image">
<img src="' . $this->Application->BaseURL() . 'core/admin_templates/img/top_frame/icons/content_mode.png" width="15" height="16" alt=""/>
</div>
<div class="cms-btn-text">' . $this->Application->Phrase('la_btn_EditContent', false, true) . ' '.(defined('DEBUG_MODE') && DEBUG_MODE ? " - #{$num}" : '').'</div>
</div>
<div class="cms-btn-content">';
$edit_form = '<form method="POST" style="display: inline; margin: 0px" name="kf_cont_'.$content->GetID().'" id="kf_cont_'.$content->GetID().'" action="'.$edit_url.'">';
$edit_form .= '<input type="hidden" name="c_id" value="'.$page->GetID().'"/>';
$edit_form .= '<input type="hidden" name="content_id" value="'.$content->GetID().'"/>';
$edit_form .= '<input type="hidden" name="front" value="1"/>';
$edit_form .= '<input type="hidden" name="bgcolor" value="'.$bg_color.'"/>';
$edit_form .= '<input type="hidden" name="m_lang" value="'.$this->Application->GetVar('m_lang').'"/>';
$edit_form .= '</form>';
$edit_code_after = '</div></div>';
if (array_key_exists('forms_later', $params) && $params['forms_later']) {
$all_forms = $this->Application->GetVar('all_forms');
$this->Application->SetVar('all_forms', $all_forms . $edit_form);
}
else {
$edit_code_after .= $edit_form;
}
}
if ($this->Application->GetVar('_editor_preview_') == 1) {
$data = $this->Application->RecallVar('_editor_preview_content_');
} else {
$data = $content->GetField('Content');
}
$data = $edit_code_before . $this->_transformContentBlockData($data, $params) . $edit_code_after;
if ($data != '') {
$this->Application->Parser->DataExists = true;
}
return $data;
}
/**
* Apply all kinds of content block data transformations without rewriting ContentBlock tag
*
* @param string $data
* @param Array $params
* @return string
*/
function _transformContentBlockData(&$data, $params)
{
return $data;
}
/**
* Returns current page name or page based on page/page_id parameters
*
* @param Array $params
* @return string
* @todo Used?
*/
function PageName($params)
{
$page =& $this->_getPage($params);
return $page->GetDBField('Name');
}
/**
* Returns current/given page information
*
* @param Array $params
* @return string
*/
function PageInfo($params)
{
$page =& $this->_getPage($params);
switch ($params['type']) {
case 'title':
$db_field = 'Title';
break;
case 'htmlhead_title':
$db_field = 'Name';
break;
case 'meta_title':
$db_field = 'MetaTitle';
break;
case 'menu_title':
$db_field = 'MenuTitle';
break;
case 'meta_keywords':
$db_field = 'MetaKeywords';
$cat_field = 'Keywords';
break;
case 'meta_description':
$db_field = 'MetaDescription';
$cat_field = 'Description';
break;
case 'tracking':
case 'index_tools':
if (!EDITING_MODE) {
$tracking = $page->GetDBField('IndexTools');
return $tracking ? $tracking : $this->Application->ConfigValue('cms_DefaultTrackingCode');
}
// no break here on purpose
default:
return '';
}
$default = isset($params['default']) ? $params['default'] : '';
$val = $page->GetField($db_field);
if (!$default) {
if ($this->Application->isModuleEnabled('In-Portal')) {
if (!$val && ($params['type'] == 'meta_keywords' || $params['type'] == 'meta_description')) {
// take category meta if it's not set for the page
return $this->Application->ProcessParsedTag('c', 'Meta', Array('name' => $cat_field));
}
}
}
if (isset($params['force_default']) && $params['force_default']) {
return $default;
}
if (preg_match('/^_Auto:/', $val)) {
$val = $default;
/*if ($db_field == 'Title') {
$page->SetDBField($db_field, $default);
$page->Update();
}*/
}
elseif ($page->GetID() == false) {
return $default;
}
return $val;
}
/**
* Includes admin css and js, that are required for cms usage on Front-Edn
*
* @param Array $params
* @return string
* @access protected
*/
protected function EditingScripts($params)
{
if ( $this->Application->GetVar('admin_scripts_included') || !EDITING_MODE ) {
return '';
}
$this->Application->SetVar('admin_scripts_included', 1);
$js_url = $this->Application->BaseURL() . 'core/admin_templates/js';
$minify_helper =& $this->Application->recallObject('MinifyHelper');
/* @var $minify_helper MinifyHelper */
$to_compress = Array (
$js_url . '/jquery/thickbox/thickbox.css',
$js_url . '/../incs/cms.css',
);
$css_compressed = $minify_helper->CompressScriptTag(Array ('files' => implode('|', $to_compress), 'templates_base' => $js_url . '/../'));
$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 . '/toolbar.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);
$page =& $this->_getPage($params);
$url_params = Array(
'pass' => 'm,c',
'c_id' => $page->GetID(),
'c_event' => 'OnGetPageInfo',
'__URLENCODE__' => 1,
'__NO_REWRITE__'=> 1,
'index_file' => 'index.php',
);
$page_helper =& $this->Application->recallObject('PageHelper');
/* @var $page_helper PageHelper */
$class_params = Array (
'pageId' => $page->GetID(),
'pageInfo' => $page_helper->getPageInfo( $page->GetID() ),
'editUrl' => $edit_template_url,
'browseUrl' => $this->Application->HREF('', '', Array ('editing_mode' => '#EDITING_MODE#', '__NO_REWRITE__' => 1, 'no_amp' => 1)),
'saveLayoutUrl' => $save_layout_url,
'editingMode' => (int)EDITING_MODE,
);
$ret .= "var aTemplateManager = new TemplateManager(" . json_encode($class_params) . ");\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 $visible_toolbar_buttons = true' . ";\n";
$ret .= 'var $use_toolbarlabels = ' . ($this->Application->ConfigValue('UseToolbarLabels') ? 'true' : 'false') . ";\n";;
$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 ( $this->Application->GetVar('preview') ) {
// prevents draft preview function to replace last template in session and break page/content block editing process
$this->Application->SetVar('skip_last_template', 1);
}
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
if ( EDITING_MODE == EDITING_MODE_CONTENT ) {
$tabs = "\n" . str_repeat("\t", 9);
$base_url = $this->Application->BaseURL();
$toolbar_hidden = $this->Application->GetVar('toolbar_hidden');
$edit_code .= '
<div>
<div id="cms-editing-notice">
<div class="top">
<a href="#" id="cms-close-editing-notice"></a>
<span prev_editors=""></span>
</div>
<div class="bottom"></div>
</div>
<div id="cms-revision-dropdown">
<div class="top"></div>
<div class="bottom"></div>
</div>
</div>';
if ( $this->Application->ConfigValue('EnablePageContentRevisionControl') ) {
$edit_code .= '<div id="cms-revision-toolbar-layer"' . ($toolbar_hidden ? ' style="top: -56px;"' : '') . '>
<div id="cms-revision-toolbar">
<script type="text/javascript">
var a_toolbar = new ToolBar(undefined, undefined, "' . $base_url . '#MODULE#/admin_templates/img/");
' . $this->toolbarButton('select', 'la_ToolTip_Save', $tabs) . $this->toolbarButton('delete', 'la_ToolTip_Discard', $tabs) . $tabs . 'a_toolbar.AddButton( new ToolBarSeparator("sep1") );';
if ( $this->Application->CheckAdminPermission('CATEGORY.REVISION.MODERATE', 0) ) {
$edit_code .= $this->toolbarButton('approve', 'la_ToolTip_Publish', $tabs) . $this->toolbarButton('decline', 'la_ToolTip_Decline', $tabs) . $tabs . 'a_toolbar.AddButton( new ToolBarSeparator("sep2") );';
}
$edit_code .= $this->toolbarButton('preview', 'la_ToolTip_Preview', $tabs);
if ( $this->Application->CheckAdminPermission('CATEGORY.REVISION.HISTORY.VIEW', 0) ) {
$edit_code .= $this->toolbarButton('history', 'la_ToolTip_History', $tabs);
}
$edit_code .= $tabs . 'a_toolbar.Render();' . "\n";
$revision =& $this->Application->recallObject('page-revision.current');
/* @var $revision kDBItem */
if ( !$revision->GetDBField('IsDraft') ) {
$edit_code .= $tabs . 'a_toolbar.DisableButton("select");' . $tabs . 'a_toolbar.DisableButton("delete");' . $tabs . 'a_toolbar.DisableButton("preview");';
}
if ( $revision->GetDBField('Status') == STATUS_ACTIVE || $revision->GetDBField('IsDraft') ) {
$edit_code .= $tabs . 'a_toolbar.DisableButton("approve");';
}
if ( $revision->GetDBField('Status') == STATUS_DISABLED || $revision->GetDBField('IsLive') || $revision->GetDBField('IsDraft') ) {
$edit_code .= $tabs . 'a_toolbar.DisableButton("decline");';
}
$publishing_tools = $this->Application->Phrase('la_btn_PublishingTools', false, true);
$edit_code .= substr($tabs, 0, -1) . '</script>
<div id="cms-current-revision-info">
<span class="revision-title"></span>
<div class="draft-saved"></div>
</div>
<a href="#" id="cms-close-toolbar"></a>
<div class="cms-clear"></div>
</div>
<a href="#" id="cms-toggle-revision-toolbar"' . ($toolbar_hidden ? '' : ' class="opened"') . '><span>' . $publishing_tools . '</span></a>
</div>' . "\n";
}
}
$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') {
if ( EDITING_MODE == EDITING_MODE_CONTENT ) {
$url_params = Array(
'pass' => 'm',
'm_opener' => 'd',
'm_cat_id' => $page->GetID(),
'__URLENCODE__' => 1,
'__NO_REWRITE__'=> 1,
'front' => 1,
'index_file' => 'index.php',
);
$revision = $this->Application->GetVar('revision');
if ( $revision ) {
$url_params['revision'] = $revision;
}
$page_admin_url = $this->Application->HREF('', ADMIN_DIRECTORY, $url_params);
$edit_code .= '<form method="POST" style="display: inline; margin: 0px" name="kf_revisions_'.$page->GetID().'" id="kf_revisions_'.$page->GetID().'" action="' . $page_admin_url . '">
<input type="hidden" name="revision" value="' . $this->Application->GetVar('revision', 0) . '"/>
</form>';
}
$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 toolbarButton($name, $title, $tabs)
{
$phrase = $this->Application->Phrase($title, false, true);
return $tabs . 'a_toolbar.AddButton( new ToolBarButton("' . $name . '", "' . htmlspecialchars($phrase) . '") );';
}
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 . 'Categories
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/categories/categories_event_handler.php
===================================================================
--- branches/5.2.x/core/units/categories/categories_event_handler.php (revision 15129)
+++ branches/5.2.x/core/units/categories/categories_event_handler.php (revision 15130)
@@ -1,2909 +1,2909 @@
<?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 CategoriesEventHandler extends kDBEventHandler {
/**
* Allows to override standard permission mapping
*
* @return void
* @access protected
* @see kEventHandler::$permMapping
*/
protected function mapPermissions()
{
parent::mapPermissions();
$permissions = Array (
'OnRebuildCache' => Array ('self' => 'add|edit'),
'OnCopy' => Array ('self' => true),
'OnCut' => Array ('self' => 'edit'),
'OnPasteClipboard' => Array ('self' => true),
'OnPaste' => Array ('self' => 'add|edit', 'subitem' => 'edit'),
'OnRecalculatePriorities' => Array ('self' => 'add|edit'), // category ordering
'OnItemBuild' => Array ('self' => true), // always allow to view individual categories (regardless of CATEGORY.VIEW right)
'OnUpdatePreviewBlock' => Array ('self' => true), // for FCKEditor integration
);
$this->permMapping = array_merge($this->permMapping, $permissions);
}
/**
* Categories are sorted using special sorting event
*
*/
function mapEvents()
{
parent::mapEvents();
$events_map = Array (
'OnMassMoveUp' => 'OnChangePriority',
'OnMassMoveDown' => 'OnChangePriority',
);
$this->eventMethods = array_merge($this->eventMethods, $events_map);
}
/**
* Checks user permission to execute given $event
*
* @param kEvent $event
* @return bool
* @access public
*/
- public function CheckPermission(kEvent &$event)
+ public function CheckPermission(kEvent $event)
{
if ( $event->Name == 'OnResetCMSMenuCache' ) {
// events from "Tools -> System Tools" section are controlled via that section "edit" permission
$perm_helper =& $this->Application->recallObject('PermissionsHelper');
/* @var $perm_helper kPermissionsHelper */
$perm_value = $this->Application->CheckPermission('in-portal:service.edit');
return $perm_helper->finalizePermissionCheck($event, $perm_value);
}
if ( !$this->Application->isAdmin ) {
if ( $event->Name == 'OnSetSortingDirect' ) {
// allow sorting on front event without view permission
return true;
}
if ( $event->Name == 'OnItemBuild' ) {
$category_id = $this->getPassedID($event);
if ( $category_id == 0 ) {
return true;
}
}
}
if ( in_array($event->Name, $this->_getMassPermissionEvents()) ) {
$items = $this->_getPermissionCheckInfo($event);
$perm_helper =& $this->Application->recallObject('PermissionsHelper');
/* @var $perm_helper kPermissionsHelper */
if ( ($event->Name == 'OnSave') && array_key_exists(0, $items) ) {
// adding new item (ID = 0)
$perm_value = $perm_helper->AddCheckPermission($items[0]['ParentId'], $event->Prefix) > 0;
}
else {
// leave only items, that can be edited
$ids = Array ();
$check_method = in_array($event->Name, Array ('OnMassDelete', 'OnCut')) ? 'DeleteCheckPermission' : 'ModifyCheckPermission';
foreach ($items as $item_id => $item_data) {
if ( $perm_helper->$check_method($item_data['CreatedById'], $item_data['ParentId'], $event->Prefix) > 0 ) {
$ids[] = $item_id;
}
}
if ( !$ids ) {
// no items left for editing -> no permission
return $perm_helper->finalizePermissionCheck($event, false);
}
$perm_value = true;
$event->setEventParam('ids', $ids); // will be used later by "kDBEventHandler::StoreSelectedIDs" method
}
return $perm_helper->finalizePermissionCheck($event, $perm_value);
}
if ( $event->Name == 'OnRecalculatePriorities' ) {
$perm_helper =& $this->Application->recallObject('PermissionsHelper');
/* @var $perm_helper kPermissionsHelper */
$category_id = $this->Application->GetVar('m_cat_id');
return $perm_helper->AddCheckPermission($category_id, $event->Prefix) || $perm_helper->ModifyCheckPermission(0, $category_id, $event->Prefix);
}
if ( $event->Name == 'OnPasteClipboard' ) {
// forces permission check to work by current category for "Paste In Category" operation
$category_id = $this->Application->GetVar('m_cat_id');
$this->Application->SetVar('c_id', $category_id);
}
return parent::CheckPermission($event);
}
/**
* Returns events, that require item-based (not just event-name based) permission check
*
* @return Array
*/
function _getMassPermissionEvents()
{
return Array (
'OnEdit', 'OnSave', 'OnMassDelete', 'OnMassApprove',
'OnMassDecline', 'OnMassMoveUp', 'OnMassMoveDown',
'OnCut',
);
}
/**
* Returns category item IDs, that require permission checking
*
* @param kEvent $event
* @return string
*/
- function _getPermissionCheckIDs(&$event)
+ function _getPermissionCheckIDs($event)
{
if ($event->Name == 'OnSave') {
$selected_ids = implode(',', $this->getSelectedIDs($event, true));
if (!$selected_ids) {
$selected_ids = 0; // when saving newly created item (OnPreCreate -> OnPreSave -> OnSave)
}
}
else {
// OnEdit, OnMassDelete events, when items are checked in grid
$selected_ids = implode(',', $this->StoreSelectedIDs($event));
}
return $selected_ids;
}
/**
* Returns information used in permission checking
*
* @param kEvent $event
* @return Array
*/
- function _getPermissionCheckInfo(&$event)
+ function _getPermissionCheckInfo($event)
{
// when saving data from temp table to live table check by data from temp table
$id_field = $this->Application->getUnitOption($event->Prefix, 'IDField');
$table_name = $this->Application->getUnitOption($event->Prefix, 'TableName');
if ($event->Name == 'OnSave') {
$table_name = $this->Application->GetTempName($table_name, 'prefix:' . $event->Prefix);
}
$sql = 'SELECT ' . $id_field . ', CreatedById, ParentId
FROM ' . $table_name . '
WHERE ' . $id_field . ' IN (' . $this->_getPermissionCheckIDs($event) . ')';
$items = $this->Conn->Query($sql, $id_field);
if (!$items) {
// when creating new category, then no IDs are stored in session
$items_info = $this->Application->GetVar( $event->getPrefixSpecial(true) );
list ($id, $fields_hash) = each($items_info);
if (array_key_exists('ParentId', $fields_hash)) {
$item_category = $fields_hash['ParentId'];
}
else {
$item_category = $this->Application->RecallVar('m_cat_id'); // saved in c:OnPreCreate event permission checking
}
$items[$id] = Array (
'CreatedById' => $this->Application->RecallVar('user_id'),
'ParentId' => $item_category,
);
}
return $items;
}
/**
* Set's mark, that root category is edited
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnEdit(kEvent &$event)
+ protected function OnEdit(kEvent $event)
{
$category_id = $this->Application->GetVar($event->getPrefixSpecial() . '_id');
$home_category = $this->Application->getBaseCategory();
$this->Application->StoreVar('IsRootCategory_' . $this->Application->GetVar('m_wid'), ($category_id === '0') || ($category_id == $home_category));
parent::OnEdit($event);
if ( $event->status == kEvent::erSUCCESS ) {
// keep "Section Properties" link (in browse modes) clean
$this->Application->DeleteVar('admin');
}
}
/**
* Adds selected link to listing
*
* @param kEvent $event
*/
- function OnProcessSelected(&$event)
+ function OnProcessSelected($event)
{
$object =& $event->getObject();
/* @var $object kDBItem */
$selected_ids = $this->Application->GetVar('selected_ids');
$this->RemoveRequiredFields($object);
$object->SetDBField($this->Application->RecallVar('dst_field'), $selected_ids['c']);
$object->Update();
$event->SetRedirectParam('opener', 'u');
}
/**
* Apply system filter to categories list
*
* @param kEvent $event
* @return void
* @access protected
* @see kDBEventHandler::OnListBuild()
*/
- protected function SetCustomQuery(kEvent &$event)
+ protected function SetCustomQuery(kEvent $event)
{
parent::SetCustomQuery($event);
$object =& $event->getObject();
/* @var $object kDBList */
// don't show "Content" category in advanced view
$object->addFilter('system_categories', '%1$s.Status <> 4');
// show system templates from current theme only + all virtual templates
$object->addFilter('theme_filter', '%1$s.ThemeId = ' . $this->_getCurrentThemeId() . ' OR %1$s.ThemeId = 0');
if ($event->Special == 'showall') {
// if using recycle bin don't show categories from there
$recycle_bin = $this->Application->ConfigValue('RecycleBinFolder');
if ($recycle_bin) {
$sql = 'SELECT TreeLeft, TreeRight
FROM '.TABLE_PREFIX.'Categories
WHERE CategoryId = '.$recycle_bin;
$tree_indexes = $this->Conn->GetRow($sql);
$object->addFilter('recyclebin_filter', '%1$s.TreeLeft < '.$tree_indexes['TreeLeft'].' OR %1$s.TreeLeft > '.$tree_indexes['TreeRight']);
}
}
if ( (string)$event->getEventParam('parent_cat_id') !== '' ) {
$parent_cat_id = $event->getEventParam('parent_cat_id');
if ("$parent_cat_id" == 'Root') {
$module_name = $event->getEventParam('module') ? $event->getEventParam('module') : 'In-Commerce';
$parent_cat_id = $this->Application->findModule('Name', $module_name, 'RootCat');
}
}
else {
$parent_cat_id = $this->Application->GetVar('c_id');
if (!$parent_cat_id) {
$parent_cat_id = $this->Application->GetVar('m_cat_id');
}
if (!$parent_cat_id) {
$parent_cat_id = 0;
}
}
if ("$parent_cat_id" == '0') {
// replace "0" category with "Content" category id (this way template
$parent_cat_id = $this->Application->getBaseCategory();
}
if ("$parent_cat_id" != 'any') {
if ($event->getEventParam('recursive')) {
if ($parent_cat_id > 0) {
// not "Home" category
$tree_indexes = $this->Application->getTreeIndex($parent_cat_id);
$object->addFilter('parent_filter', '%1$s.TreeLeft BETWEEN '.$tree_indexes['TreeLeft'].' AND '.$tree_indexes['TreeRight']);
}
}
else {
$object->addFilter('parent_filter', '%1$s.ParentId = '.$parent_cat_id);
}
}
$object->addFilter('perm_filter', TABLE_PREFIX . 'CategoryPermissionsCache.PermId = 1'); // check for CATEGORY.VIEW permission
if ($this->Application->RecallVar('user_id') != USER_ROOT) {
// apply permission filters to all users except "root"
$view_filters = Array ();
$groups = explode(',',$this->Application->RecallVar('UserGroups'));
foreach ($groups as $group) {
$view_filters[] = 'FIND_IN_SET('.$group.', ' . TABLE_PREFIX . 'CategoryPermissionsCache.ACL)';
}
$view_filter = implode(' OR ', $view_filters);
$object->addFilter('perm_filter2', $view_filter);
}
if (!$this->Application->isAdminUser) {
// apply status filter only on front
$object->addFilter('status_filter', $object->TableName.'.Status = 1');
}
// process "types" and "except" parameters
$type_clauses = Array();
$types = $event->getEventParam('types');
$types = $types ? explode(',', $types) : Array ();
$except_types = $event->getEventParam('except');
$except_types = $except_types ? explode(',', $except_types) : Array ();
if (in_array('related', $types) || in_array('related', $except_types)) {
$related_to = $event->getEventParam('related_to');
if (!$related_to) {
$related_prefix = $event->Prefix;
}
else {
$sql = 'SELECT Prefix
FROM '.TABLE_PREFIX.'ItemTypes
WHERE ItemName = '.$this->Conn->qstr($related_to);
$related_prefix = $this->Conn->GetOne($sql);
}
$rel_table = $this->Application->getUnitOption('rel', 'TableName');
$item_type = (int)$this->Application->getUnitOption($event->Prefix, 'ItemType');
if ($item_type == 0) {
trigger_error('<strong>ItemType</strong> not defined for prefix <strong>' . $event->Prefix . '</strong>', E_USER_WARNING);
}
// process case, then this list is called inside another list
$prefix_special = $event->getEventParam('PrefixSpecial');
if (!$prefix_special) {
$prefix_special = $this->Application->Parser->GetParam('PrefixSpecial');
}
$id = false;
if ($prefix_special !== false) {
$processed_prefix = $this->Application->processPrefix($prefix_special);
if ($processed_prefix['prefix'] == $related_prefix) {
// printing related categories within list of items (not on details page)
$list =& $this->Application->recallObject($prefix_special);
/* @var $list kDBList */
$id = $list->GetID();
}
}
if ($id === false) {
// printing related categories for single item (possibly on details page)
if ($related_prefix == 'c') {
$id = $this->Application->GetVar('m_cat_id');
}
else {
$id = $this->Application->GetVar($related_prefix . '_id');
}
}
$p_item =& $this->Application->recallObject($related_prefix . '.current', null, Array('skip_autoload' => true));
/* @var $p_item kCatDBItem */
$p_item->Load( (int)$id );
$p_resource_id = $p_item->GetDBField('ResourceId');
$sql = 'SELECT SourceId, TargetId FROM '.$rel_table.'
WHERE
(Enabled = 1)
AND (
(Type = 0 AND SourceId = '.$p_resource_id.' AND TargetType = '.$item_type.')
OR
(Type = 1
AND (
(SourceId = '.$p_resource_id.' AND TargetType = '.$item_type.')
OR
(TargetId = '.$p_resource_id.' AND SourceType = '.$item_type.')
)
)
)';
$related_ids_array = $this->Conn->Query($sql);
$related_ids = Array();
foreach ($related_ids_array as $key => $record) {
$related_ids[] = $record[ $record['SourceId'] == $p_resource_id ? 'TargetId' : 'SourceId' ];
}
if (count($related_ids) > 0) {
$type_clauses['related']['include'] = '%1$s.ResourceId IN ('.implode(',', $related_ids).')';
$type_clauses['related']['except'] = '%1$s.ResourceId NOT IN ('.implode(',', $related_ids).')';
}
else {
$type_clauses['related']['include'] = '0';
$type_clauses['related']['except'] = '1';
}
$type_clauses['related']['having_filter'] = false;
}
if (in_array('category_related', $type_clauses)) {
$object->removeFilter('parent_filter');
$resource_id = $this->Conn->GetOne('
SELECT ResourceId FROM '.$this->Application->getUnitOption($event->Prefix, 'TableName').'
WHERE CategoryId = '.$parent_cat_id
);
$sql = 'SELECT DISTINCT(TargetId) FROM '.TABLE_PREFIX.'CatalogRelationships
WHERE SourceId = '.$resource_id.' AND SourceType = 1';
$related_cats = $this->Conn->GetCol($sql);
$related_cats = is_array($related_cats) ? $related_cats : Array();
$sql = 'SELECT DISTINCT(SourceId) FROM '.TABLE_PREFIX.'CatalogRelationships
WHERE TargetId = '.$resource_id.' AND TargetType = 1 AND Type = 1';
$related_cats2 = $this->Conn->GetCol($sql);
$related_cats2 = is_array($related_cats2) ? $related_cats2 : Array();
$related_cats = array_unique( array_merge( $related_cats2, $related_cats ) );
if ($related_cats) {
$type_clauses['category_related']['include'] = '%1$s.ResourceId IN ('.implode(',', $related_cats).')';
$type_clauses['category_related']['except'] = '%1$s.ResourceId NOT IN ('.implode(',', $related_cats).')';
}
else
{
$type_clauses['category_related']['include'] = '0';
$type_clauses['category_related']['except'] = '1';
}
$type_clauses['category_related']['having_filter'] = false;
}
if (in_array('product_related', $types)) {
$object->removeFilter('parent_filter');
$product_id = $event->getEventParam('product_id') ? $event->getEventParam('product_id') : $this->Application->GetVar('p_id');
$resource_id = $this->Conn->GetOne('
SELECT ResourceId FROM '.$this->Application->getUnitOption('p', 'TableName').'
WHERE ProductId = '.$product_id
);
$sql = 'SELECT DISTINCT(TargetId) FROM '.TABLE_PREFIX.'CatalogRelationships
WHERE SourceId = '.$resource_id.' AND TargetType = 1';
$related_cats = $this->Conn->GetCol($sql);
$related_cats = is_array($related_cats) ? $related_cats : Array();
$sql = 'SELECT DISTINCT(SourceId) FROM '.TABLE_PREFIX.'CatalogRelationships
WHERE TargetId = '.$resource_id.' AND SourceType = 1 AND Type = 1';
$related_cats2 = $this->Conn->GetCol($sql);
$related_cats2 = is_array($related_cats2) ? $related_cats2 : Array();
$related_cats = array_unique( array_merge( $related_cats2, $related_cats ) );
if ($related_cats) {
$type_clauses['product_related']['include'] = '%1$s.ResourceId IN ('.implode(',', $related_cats).')';
$type_clauses['product_related']['except'] = '%1$s.ResourceId NOT IN ('.implode(',', $related_cats).')';
}
else {
$type_clauses['product_related']['include'] = '0';
$type_clauses['product_related']['except'] = '1';
}
$type_clauses['product_related']['having_filter'] = false;
}
$type_clauses['menu']['include'] = '%1$s.IsMenu = 1';
$type_clauses['menu']['except'] = '%1$s.IsMenu = 0';
$type_clauses['menu']['having_filter'] = false;
if (in_array('search', $types) || in_array('search', $except_types)) {
$event_mapping = Array (
'simple' => 'OnSimpleSearch',
'subsearch' => 'OnSubSearch',
'advanced' => 'OnAdvancedSearch'
);
$keywords = $event->getEventParam('keyword_string');
$type = $this->Application->GetVar('search_type', 'simple');
if ( $keywords ) {
// processing keyword_string param of ListProducts tag
$this->Application->SetVar('keywords', $keywords);
$type = 'simple';
}
$search_event = $event_mapping[$type];
$this->$search_event($event);
$object =& $event->getObject();
/* @var $object kDBList */
$search_sql = ' FROM ' . TABLE_PREFIX . 'ses_' . $this->Application->GetSID() . '_' . TABLE_PREFIX . 'Search
search_result LEFT JOIN %1$s ON %1$s.ResourceId = search_result.ResourceId';
$sql = str_replace('FROM %1$s', $search_sql, $object->GetPlainSelectSQL());
$object->SetSelectSQL($sql);
$object->addCalculatedField('Relevance', 'search_result.Relevance');
$object->AddOrderField('search_result.Relevance', 'desc', true);
$type_clauses['search']['include'] = '1';
$type_clauses['search']['except'] = '0';
$type_clauses['search']['having_filter'] = false;
}
$search_helper =& $this->Application->recallObject('SearchHelper');
/* @var $search_helper kSearchHelper */
$search_helper->SetComplexFilter($event, $type_clauses, implode(',', $types), implode(',', $except_types));
}
/**
* Returns current theme id
*
* @return int
*/
function _getCurrentThemeId()
{
$themes_helper =& $this->Application->recallObject('ThemesHelper');
/* @var $themes_helper kThemesHelper */
return (int)$themes_helper->getCurrentThemeId();
}
/**
* Returns ID of current item to be edited
* by checking ID passed in get/post as prefix_id
* or by looking at first from selected ids, stored.
* Returned id is also stored in Session in case
* it was explicitly passed as get/post
*
* @param kEvent $event
* @return int
* @access public
*/
- public function getPassedID(kEvent &$event)
+ public function getPassedID(kEvent $event)
{
if ( ($event->Special == 'page') || ($event->Special == '-virtual') || ($event->Prefix == 'st') ) {
return $this->_getPassedStructureID($event);
}
if ( $this->Application->isAdmin ) {
return parent::getPassedID($event);
}
return $this->Application->GetVar('m_cat_id');
}
/**
* Enter description here...
*
* @param kEvent $event
* @return int
*/
- function _getPassedStructureID(&$event)
+ function _getPassedStructureID($event)
{
static $page_by_template = Array ();
if ($event->Special == 'current') {
return $this->Application->GetVar('m_cat_id');
}
$event->setEventParam('raise_warnings', 0);
$page_id = parent::getPassedID($event);
if ($page_id === false) {
$template = $event->getEventParam('page');
if (!$template) {
$template = $this->Application->GetVar('t');
}
// bug: when template contains "-" symbols (or others, that stripDisallowed will replace) it's not found
if (!array_key_exists($template, $page_by_template)) {
$sql = 'SELECT ' . $this->Application->getUnitOption($event->Prefix, 'IDField') . '
FROM ' . $this->Application->getUnitOption($event->Prefix, 'TableName') . '
WHERE
(
(NamedParentPath = ' . $this->Conn->qstr($template) . ') OR
(NamedParentPath = ' . $this->Conn->qstr('Content/' . $template) . ') OR
(`Type` = ' . PAGE_TYPE_TEMPLATE . ' AND CachedTemplate = ' . $this->Conn->qstr($template) . ')
) AND (ThemeId = ' . $this->_getCurrentThemeId() . ' OR ThemeId = 0)';
$page_id = $this->Conn->GetOne($sql);
}
else {
$page_id = $page_by_template[$template];
}
if ($page_id === false && EDITING_MODE) {
// create missing pages, when in editing mode
$object =& $this->Application->recallObject($this->Prefix . '.rebuild', null, Array('skip_autoload' => true));
/* @var $object CategoriesItem */
$created = $this->_prepareAutoPage($object, $template, null, SMS_MODE_AUTO); // create virtual (not system!) page
if ($created) {
if ($this->Application->ConfigValue('QuickCategoryPermissionRebuild') || !$this->Application->isAdmin) {
$updater =& $this->Application->makeClass('kPermCacheUpdater');
/* @var $updater kPermCacheUpdater */
$updater->OneStepRun();
}
$this->_resetMenuCache();
$this->Application->RemoveVar('PermCache_UpdateRequired');
$page_id = $object->GetID();
$this->Application->SetVar('m_cat_id', $page_id);
}
}
if ($page_id) {
$page_by_template[$template] = $page_id;
}
}
if (!$page_id && !$this->Application->isAdmin) {
$page_id = $this->Application->GetVar('m_cat_id');
}
return $page_id;
}
- function ParentGetPassedID(&$event)
+ function ParentGetPassedID($event)
{
return parent::getPassedID($event);
}
/**
* Adds calculates fields for item statuses
*
* @param kCatDBItem $object
* @param kEvent $event
* @return void
* @access protected
*/
- protected function prepareObject(&$object, kEvent &$event)
+ protected function prepareObject(&$object, kEvent $event)
{
if ( $event->Special == '-virtual' ) {
return;
}
$object =& $event->getObject(Array ('skip_autoload' => true));
/* @var $object kDBItem */
$object->addCalculatedField(
'IsNew',
' IF(%1$s.NewItem = 2,
IF(%1$s.CreatedOn >= (UNIX_TIMESTAMP() - '.
$this->Application->ConfigValue('Category_DaysNew').
'*3600*24), 1, 0),
%1$s.NewItem
)');
}
/**
* Set correct parent path for newly created categories
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnAfterCopyToLive(kEvent &$event)
+ protected function OnAfterCopyToLive(kEvent $event)
{
parent::OnAfterCopyToLive($event);
$object =& $this->Application->recallObject($event->Prefix . '.-item', null, Array ('skip_autoload' => true, 'live_table' => true));
/* @var $object CategoriesItem */
$parent_path = false;
$object->Load($event->getEventParam('id'));
if ( $event->getEventParam('temp_id') == 0 ) {
if ( $object->isLoaded() ) {
// update path only for real categories (not including "Home" root category)
$fields_hash = Array ('ParentPath' => $object->buildParentPath());
$this->Conn->doUpdate($fields_hash, $object->TableName, 'CategoryId = ' . $object->GetID());
$parent_path = $fields_hash['ParentPath'];
}
}
else {
$parent_path = $object->GetDBField('ParentPath');
}
if ( $parent_path ) {
$cache_updater =& $this->Application->makeClass('kPermCacheUpdater', Array (null, $parent_path));
/* @var $cache_updater kPermCacheUpdater */
$cache_updater->OneStepRun();
}
}
/**
* Set cache modification mark if needed
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnBeforeDeleteFromLive(kEvent &$event)
+ protected function OnBeforeDeleteFromLive(kEvent $event)
{
parent::OnBeforeDeleteFromLive($event);
$id = $event->getEventParam('id');
// loading anyway, because this object is needed by "c-perm:OnBeforeDeleteFromLive" event
$temp_object =& $event->getObject(Array ('skip_autoload' => true));
/* @var $temp_object CategoriesItem */
$temp_object->Load($id);
if ( $id == 0 ) {
if ( $temp_object->isLoaded() ) {
// new category -> update cache (not loaded when "Home" category)
$this->Application->StoreVar('PermCache_UpdateRequired', 1);
}
return ;
}
// existing category was edited, check if in-cache fields are modified
$live_object =& $this->Application->recallObject($event->Prefix . '.-item', null, Array ('live_table' => true, 'skip_autoload' => true));
/* @var $live_object CategoriesItem */
$live_object->Load($id);
$cached_fields = Array ('l' . $this->Application->GetDefaultLanguageId() . '_Name', 'Filename', 'Template', 'ParentId', 'Priority');
foreach ($cached_fields as $cached_field) {
if ( $live_object->GetDBField($cached_field) != $temp_object->GetDBField($cached_field) ) {
// use session instead of REQUEST because of permission editing in category can contain
// multiple submits, that changes data before OnSave event occurs
$this->Application->StoreVar('PermCache_UpdateRequired', 1);
break;
}
}
// remember category filename change between temp and live records
if ( $temp_object->GetDBField('Filename') != $live_object->GetDBField('Filename') ) {
$filename_changes = $this->Application->GetVar($event->Prefix . '_filename_changes', Array ());
$filename_changes[ $live_object->GetID() ] = Array (
'from' => $live_object->GetDBField('Filename'),
'to' => $temp_object->GetDBField('Filename')
);
$this->Application->SetVar($event->Prefix . '_filename_changes', $filename_changes);
}
}
/**
* Calls kDBEventHandler::OnSave original event
* Used in proj-cms:StructureEventHandler->OnSave
*
* @param kEvent $event
*/
- function parentOnSave(&$event)
+ function parentOnSave($event)
{
parent::OnSave($event);
}
/**
* Reset root-category flag when new category is created
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnPreCreate(kEvent &$event)
+ protected function OnPreCreate(kEvent $event)
{
// 1. for permission editing of Home category
$this->Application->RemoveVar('IsRootCategory_' . $this->Application->GetVar('m_wid'));
parent::OnPreCreate($event);
$object =& $event->getObject();
/* @var $object kDBItem */
// 2. preset template
$category_id = $this->Application->GetVar('m_cat_id');
$root_category = $this->Application->getBaseCategory();
if ( $category_id == $root_category ) {
$object->SetDBField('Template', $this->_getDefaultDesign());
}
// 3. set default owner
$object->SetDBField('CreatedById', $this->Application->RecallVar('user_id'));
}
/**
* Checks cache update mark and redirect to cache if needed
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnSave(kEvent &$event)
+ protected function OnSave(kEvent $event)
{
// get data from live table before it is overwritten by parent OnSave method call
$ids = $this->getSelectedIDs($event, true);
$is_editing = implode('', $ids);
$old_statuses = $is_editing ? $this->_getCategoryStatus($ids) : Array ();
$object =& $event->getObject();
/* @var $object CategoriesItem */
parent::OnSave($event);
if ( $event->status != kEvent::erSUCCESS ) {
return;
}
if ( $this->Application->RecallVar('PermCache_UpdateRequired') ) {
$this->Application->RemoveVar('IsRootCategory_' . $this->Application->GetVar('m_wid'));
}
$this->Application->StoreVar('RefreshStructureTree', 1);
$this->_resetMenuCache();
if ( $is_editing ) {
// send email event to category owner, when it's status is changed (from admin)
$object->SwitchToLive();
$new_statuses = $this->_getCategoryStatus($ids);
$process_statuses = Array (STATUS_ACTIVE, STATUS_DISABLED);
foreach ($new_statuses as $category_id => $new_status) {
if ( $new_status != $old_statuses[$category_id] && in_array($new_status, $process_statuses) ) {
$object->Load($category_id);
$email_event = $new_status == STATUS_ACTIVE ? 'CATEGORY.APPROVE' : 'CATEGORY.DENY';
$this->Application->EmailEventUser($email_event, $object->GetDBField('CreatedById'));
}
}
}
// change opener stack in case if edited category filename was changed
$filename_changes = $this->Application->GetVar($event->Prefix . '_filename_changes', Array ());
if ( $filename_changes ) {
$opener_stack =& $this->Application->makeClass('kOpenerStack');
/* @var $opener_stack kOpenerStack */
list ($template, $params, $index_file) = $opener_stack->pop();
foreach ($filename_changes as $change_info) {
$template = str_ireplace($change_info['from'], $change_info['to'], $template);
}
$opener_stack->push($template, $params, $index_file);
$opener_stack->save();
}
}
/**
* Returns statuses of given categories
*
* @param Array $category_ids
* @return Array
*/
function _getCategoryStatus($category_ids)
{
$id_field = $this->Application->getUnitOption($this->Prefix, 'IDField');
$table_name = $this->Application->getUnitOption($this->Prefix, 'TableName');
$sql = 'SELECT Status, ' . $id_field . '
FROM ' . $table_name . '
WHERE ' . $id_field . ' IN (' . implode(',', $category_ids) . ')';
return $this->Conn->GetCol($sql, $id_field);
}
/**
* Creates a new item in temp table and
* stores item id in App vars and Session on success
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnPreSaveCreated(kEvent &$event)
+ protected function OnPreSaveCreated(kEvent $event)
{
$object =& $event->getObject( Array ('skip_autoload' => true) );
/* @var $object CategoriesItem */
if ( $object->IsRoot() ) {
// don't create root category while saving permissions
return;
}
parent::OnPreSaveCreated($event);
}
/**
* Deletes sym link to other category
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnAfterItemDelete(kEvent &$event)
+ protected function OnAfterItemDelete(kEvent $event)
{
parent::OnAfterItemDelete($event);
$object =& $event->getObject();
/* @var $object kDBItem */
$sql = 'UPDATE ' . $object->TableName . '
SET SymLinkCategoryId = NULL
WHERE SymLinkCategoryId = ' . $object->GetID();
$this->Conn->Query($sql);
}
/**
* Exclude root categories from deleting
*
* @param kEvent $event
* @param string $type
* @return void
* @access protected
*/
- protected function customProcessing(kEvent &$event, $type)
+ protected function customProcessing(kEvent $event, $type)
{
if ( $event->Name == 'OnMassDelete' && $type == 'before' ) {
$ids = $event->getEventParam('ids');
if ( !$ids || $this->Application->ConfigValue('AllowDeleteRootCats') ) {
return;
}
$root_categories = Array ();
// get module root categories and exclude them
foreach ($this->Application->ModuleInfo as $module_info) {
$root_categories[] = $module_info['RootCat'];
}
$root_categories = array_unique($root_categories);
if ( $root_categories && array_intersect($ids, $root_categories) ) {
$event->setEventParam('ids', array_diff($ids, $root_categories));
$this->Application->StoreVar('root_delete_error', 1);
}
}
}
/**
* Checks, that given template exists (physically) in given theme
*
* @param string $template
* @param int $theme_id
* @return bool
*/
function _templateFound($template, $theme_id = null)
{
static $init_made = false;
if (!$init_made) {
$this->Application->InitParser(true);
$init_made = true;
}
if (!isset($theme_id)) {
$theme_id = $this->_getCurrentThemeId();
}
$theme_name = $this->_getThemeName($theme_id);
return $this->Application->TemplatesCache->TemplateExists('theme:' . $theme_name . '/' . $template);
}
/**
* Removes ".tpl" in template path
*
* @param string $template
* @return string
*/
function _stripTemplateExtension($template)
{
// return preg_replace('/\.[^.\\\\\\/]*$/', '', $template);
return preg_replace('/^[\\/]{0,1}(.*)\.tpl$/', "$1", $template);
}
/**
* Deletes all selected items.
* Automatically recourse 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(kEvent &$event)
+ protected function OnMassDelete(kEvent $event)
{
if ( $this->Application->CheckPermission('SYSTEM_ACCESS.READONLY', 1) ) {
$event->status = kEvent::erFAIL;
return;
}
$to_delete = Array ();
$ids = $this->StoreSelectedIDs($event);
$recycle_bin = $this->Application->ConfigValue('RecycleBinFolder');
if ( $recycle_bin ) {
$rb =& $this->Application->recallObject('c.recycle', null, Array ('skip_autoload' => true));
/* @var $rb CategoriesItem */
$rb->Load($recycle_bin);
$cat =& $event->getObject(Array ('skip_autoload' => true));
/* @var $cat CategoriesItem */
foreach ($ids as $id) {
$cat->Load($id);
if ( preg_match('/^' . preg_quote($rb->GetDBField('ParentPath'), '/') . '/', $cat->GetDBField('ParentPath')) ) {
// already in "Recycle Bin" -> delete for real
$to_delete[] = $id;
continue;
}
// just move into "Recycle Bin" category
$cat->SetDBField('ParentId', $recycle_bin);
$cat->Update();
}
$ids = $to_delete;
}
$event->setEventParam('ids', $ids);
$this->customProcessing($event, 'before');
$ids = $event->getEventParam('ids');
if ( $ids ) {
$recursive_helper =& $this->Application->recallObject('RecursiveHelper');
/* @var $recursive_helper kRecursiveHelper */
foreach ($ids as $id) {
$recursive_helper->DeleteCategory($id, $event->Prefix);
}
}
$this->clearSelectedIDs($event);
$this->_ensurePermCacheRebuild($event);
}
/**
* Add selected items to clipboard with mode = COPY (CLONE)
*
* @param kEvent $event
*/
- function OnCopy(&$event)
+ function OnCopy($event)
{
$this->Application->RemoveVar('clipboard');
$clipboard_helper =& $this->Application->recallObject('ClipboardHelper');
/* @var $clipboard_helper kClipboardHelper */
$clipboard_helper->setClipboard($event, 'copy', $this->StoreSelectedIDs($event));
$this->clearSelectedIDs($event);
}
/**
* Add selected items to clipboard with mode = CUT
*
* @param kEvent $event
*/
- function OnCut(&$event)
+ function OnCut($event)
{
$this->Application->RemoveVar('clipboard');
$clipboard_helper =& $this->Application->recallObject('ClipboardHelper');
/* @var $clipboard_helper kClipboardHelper */
$clipboard_helper->setClipboard($event, 'cut', $this->StoreSelectedIDs($event));
$this->clearSelectedIDs($event);
}
/**
* Controls all item paste operations. Can occur only with filled clipboard.
*
* @param kEvent $event
*/
- function OnPasteClipboard(&$event)
+ function OnPasteClipboard($event)
{
$clipboard = unserialize( $this->Application->RecallVar('clipboard') );
foreach ($clipboard as $prefix => $clipboard_data) {
$paste_event = new kEvent($prefix.':OnPaste', Array('clipboard_data' => $clipboard_data));
$this->Application->HandleEvent($paste_event);
$event->copyFrom($paste_event);
}
}
/**
* Checks permission for OnPaste event
*
* @param kEvent $event
* @return bool
*/
- function _checkPastePermission(&$event)
+ function _checkPastePermission($event)
{
$perm_helper =& $this->Application->recallObject('PermissionsHelper');
/* @var $perm_helper kPermissionsHelper */
$category_id = $this->Application->GetVar('m_cat_id');
if ($perm_helper->AddCheckPermission($category_id, $event->Prefix) == 0) {
// no items left for editing -> no permission
return $perm_helper->finalizePermissionCheck($event, false);
}
return true;
}
/**
* Paste categories with sub-items from clipboard
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnPaste(&$event)
+ protected function OnPaste($event)
{
if ( $this->Application->CheckPermission('SYSTEM_ACCESS.READONLY', 1) || !$this->_checkPastePermission($event) ) {
$event->status = kEvent::erFAIL;
return;
}
$clipboard_data = $event->getEventParam('clipboard_data');
if ( !$clipboard_data['cut'] && !$clipboard_data['copy'] ) {
return;
}
// 1. get ParentId of moved category(-es) before it gets updated!!!)
$source_category_id = 0;
$id_field = $this->Application->getUnitOption($event->Prefix, 'IDField');
$table_name = $this->Application->getUnitOption($event->Prefix, 'TableName');
if ( $clipboard_data['cut'] ) {
$sql = 'SELECT ParentId
FROM ' . $table_name . '
WHERE ' . $id_field . ' = ' . $clipboard_data['cut'][0];
$source_category_id = $this->Conn->GetOne($sql);
}
$recursive_helper =& $this->Application->recallObject('RecursiveHelper');
/* @var $recursive_helper kRecursiveHelper */
if ( $clipboard_data['cut'] ) {
$recursive_helper->MoveCategories($clipboard_data['cut'], $this->Application->GetVar('m_cat_id'));
}
if ( $clipboard_data['copy'] ) {
// don't allow to copy/paste system OR theme-linked virtual pages
$sql = 'SELECT ' . $id_field . '
FROM ' . $table_name . '
WHERE ' . $id_field . ' IN (' . implode(',', $clipboard_data['copy']) . ') AND (`Type` = ' . PAGE_TYPE_VIRTUAL . ') AND (ThemeId = 0)';
$allowed_ids = $this->Conn->GetCol($sql);
if ( !$allowed_ids ) {
return;
}
foreach ($allowed_ids as $id) {
$recursive_helper->PasteCategory($id, $event->Prefix);
}
}
$priority_helper =& $this->Application->recallObject('PriorityHelper');
/* @var $priority_helper kPriorityHelper */
if ( $clipboard_data['cut'] ) {
$ids = $priority_helper->recalculatePriorities($event, 'ParentId = ' . $source_category_id);
if ( $ids ) {
$priority_helper->massUpdateChanged($event->Prefix, $ids);
}
}
// recalculate priorities of newly pasted categories in destination category
$parent_id = $this->Application->GetVar('m_cat_id');
$ids = $priority_helper->recalculatePriorities($event, 'ParentId = ' . $parent_id);
if ( $ids ) {
$priority_helper->massUpdateChanged($event->Prefix, $ids);
}
if ( $clipboard_data['cut'] || $clipboard_data['copy'] ) {
$this->_ensurePermCacheRebuild($event);
}
}
/**
* Ensures, that category permission cache is rebuild when category is added/edited/deleted
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function _ensurePermCacheRebuild(&$event)
+ protected function _ensurePermCacheRebuild($event)
{
if ( $this->Application->ConfigValue('QuickCategoryPermissionRebuild') ) {
$updater =& $this->Application->makeClass('kPermCacheUpdater');
/* @var $updater kPermCacheUpdater */
$updater->OneStepRun();
}
else {
// rebuild with progress bar
$event->redirect = 'categories/cache_updater';
}
$this->_resetMenuCache();
$this->Application->StoreVar('RefreshStructureTree', 1);
}
/**
* Occurs when pasting category
*
* @param kEvent $event
*/
- /*function OnCatPaste(&$event)
+ /*function OnCatPaste($event)
{
$inp_clipboard = $this->Application->RecallVar('ClipBoard');
$inp_clipboard = explode('-', $inp_clipboard, 2);
if($inp_clipboard[0] == 'COPY')
{
$saved_cat_id = $this->Application->GetVar('m_cat_id');
$cat_ids = $event->getEventParam('cat_ids');
$id_field = $this->Application->getUnitOption($event->Prefix, 'IDField');
$table = $this->Application->getUnitOption($event->Prefix, 'TableName');
$ids_sql = 'SELECT '.$id_field.' FROM '.$table.' WHERE ResourceId IN (%s)';
$resource_ids_sql = 'SELECT ItemResourceId FROM '.TABLE_PREFIX.'CategoryItems WHERE CategoryId = %s AND PrimaryCat = 1';
$object =& $this->Application->recallObject($event->Prefix.'.item', $event->Prefix, Array('skip_autoload' => true));
foreach($cat_ids as $source_cat => $dest_cat)
{
$item_resource_ids = $this->Conn->GetCol( sprintf($resource_ids_sql, $source_cat) );
if(!$item_resource_ids) continue;
$this->Application->SetVar('m_cat_id', $dest_cat);
$item_ids = $this->Conn->GetCol( sprintf($ids_sql, implode(',', $item_resource_ids) ) );
$temp =& $this->Application->recallObject($event->getPrefixSpecial().'_TempHandler', 'kTempTablesHandler');
if($item_ids) $temp->CloneItems($event->Prefix, $event->Special, $item_ids);
}
$this->Application->SetVar('m_cat_id', $saved_cat_id);
}
}*/
/**
* Clears clipboard content
*
* @param kEvent $event
*/
- function OnClearClipboard(&$event)
+ function OnClearClipboard($event)
{
$this->Application->RemoveVar('clipboard');
}
/**
* Sets correct status for new categories created on front-end
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnBeforeItemCreate(kEvent &$event)
+ protected function OnBeforeItemCreate(kEvent $event)
{
parent::OnBeforeItemCreate($event);
$object =& $event->getObject();
/* @var $object CategoriesItem */
if ( $object->GetDBField('ParentId') <= 0 ) {
// no parent category - use current (happens during import)
$object->SetDBField('ParentId', $this->Application->GetVar('m_cat_id'));
}
$this->_beforeItemChange($event);
if ( $this->Application->isAdmin || $event->Prefix == 'st' ) {
// don't check category permissions when auto-creating structure pages
return ;
}
$perm_helper =& $this->Application->recallObject('PermissionsHelper');
/* @var $perm_helper kPermissionsHelper */
$new_status = false;
$category_id = $this->Application->GetVar('m_cat_id');
if ( $perm_helper->CheckPermission('CATEGORY.ADD', 0, $category_id) ) {
$new_status = STATUS_ACTIVE;
}
else {
if ( $perm_helper->CheckPermission('CATEGORY.ADD.PENDING', 0, $category_id) ) {
$new_status = STATUS_PENDING;
}
}
if ( $new_status ) {
$object->SetDBField('Status', $new_status);
// don't forget to set Priority for suggested from Front-End categories
$min_priority = $this->_getNextPriority($object->GetDBField('ParentId'), $object->TableName);
$object->SetDBField('Priority', $min_priority);
}
else {
$event->status = kEvent::erPERM_FAIL;
return ;
}
}
/**
* Returns next available priority for given category from given table
*
* @param int $category_id
* @param string $table_name
* @return int
*/
function _getNextPriority($category_id, $table_name)
{
$sql = 'SELECT MIN(Priority)
FROM ' . $table_name . '
WHERE ParentId = ' . $category_id;
return (int)$this->Conn->GetOne($sql) - 1;
}
/**
* Sets correct status for new categories created on front-end
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnBeforeItemUpdate(kEvent &$event)
+ protected function OnBeforeItemUpdate(kEvent $event)
{
parent::OnBeforeItemUpdate($event);
$this->_beforeItemChange($event);
$object =& $event->getObject();
/* @var $object kDBItem */
if ( $object->GetChangedFields() ) {
$object->SetDBField('ModifiedById', $this->Application->RecallVar('user_id'));
}
}
/**
* Performs redirect to correct suggest confirmation template
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnCreate(kEvent &$event)
+ protected function OnCreate(kEvent $event)
{
parent::OnCreate($event);
if ( $this->Application->isAdmin || $event->status != kEvent::erSUCCESS ) {
// don't sent email or rebuild cache directly after category is created by admin
return;
}
$object =& $event->getObject();
/* @var $object kDBItem */
$cache_updater =& $this->Application->makeClass('kPermCacheUpdater', Array (null, $object->GetDBField('ParentPath')));
/* @var $cache_updater kPermCacheUpdater */
$cache_updater->OneStepRun();
$is_active = ($object->GetDBField('Status') == STATUS_ACTIVE);
$next_template = $is_active ? 'suggest_confirm_template' : 'suggest_pending_confirm_template';
$event->redirect = $this->Application->GetVar($next_template);
$event->SetRedirectParam('opener', 's');
// send email events
$perm_prefix = $this->Application->getUnitOption($event->Prefix, 'PermItemPrefix');
$event_suffix = $is_active ? 'ADD' : 'ADD.PENDING';
$this->Application->EmailEventAdmin($perm_prefix . '.' . $event_suffix);
$this->Application->EmailEventUser($perm_prefix . '.' . $event_suffix, $object->GetDBField('CreatedById'));
}
/**
* Returns current per-page setting for list
*
* @param kEvent $event
* @return int
* @access protected
*/
- protected function getPerPage(kEvent &$event)
+ protected function getPerPage(kEvent $event)
{
if ( !$this->Application->isAdmin ) {
$event->setEventParam('same_special', true);
}
return parent::getPerPage($event);
}
/**
* Set's correct page for list based on data provided with event
*
* @param kEvent $event
* @return void
* @access protected
* @see kDBEventHandler::OnListBuild()
*/
- protected function SetPagination(kEvent &$event)
+ protected function SetPagination(kEvent $event)
{
parent::SetPagination($event);
if ( !$this->Application->isAdmin ) {
$page_var = $event->getEventParam('page_var');
if ( $page_var !== false ) {
$page = $this->Application->GetVar($page_var);
if ( is_numeric($page) ) {
$object =& $event->getObject();
/* @var $object kDBList */
$object->SetPage($page);
}
}
}
}
/**
* Apply same processing to each item being selected in grid
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function iterateItems(kEvent &$event)
+ protected function iterateItems(kEvent $event)
{
if ( $event->Name != 'OnMassApprove' && $event->Name != 'OnMassDecline' ) {
parent::iterateItems($event);
}
if ( $this->Application->CheckPermission('SYSTEM_ACCESS.READONLY', 1) ) {
$event->status = kEvent::erFAIL;
return;
}
$object =& $event->getObject(Array ('skip_autoload' => true));
/* @var $object CategoriesItem */
$ids = $this->StoreSelectedIDs($event);
if ( $ids ) {
$propagate_category_status = $this->Application->GetVar('propagate_category_status');
$status_field = array_shift( $this->Application->getUnitOption($event->Prefix, 'StatusField') );
foreach ($ids as $id) {
$object->Load($id);
$object->SetDBField($status_field, $event->Name == 'OnMassApprove' ? 1 : 0);
if ( $object->Update() ) {
if ( $propagate_category_status ) {
$sql = 'UPDATE ' . $object->TableName . '
SET ' . $status_field . ' = ' . $object->GetDBField($status_field) . '
WHERE TreeLeft BETWEEN ' . $object->GetDBField('TreeLeft') . ' AND ' . $object->GetDBField('TreeRight');
$this->Conn->Query($sql);
}
$event->status = kEvent::erSUCCESS;
$email_event = $event->Name == 'OnMassApprove' ? 'CATEGORY.APPROVE' : 'CATEGORY.DENY';
$this->Application->EmailEventUser($email_event, $object->GetDBField('CreatedById'));
}
else {
$event->status = kEvent::erFAIL;
$event->redirect = false;
break;
}
}
}
$this->clearSelectedIDs($event);
$this->Application->StoreVar('RefreshStructureTree', 1);
}
/**
* Checks, that currently loaded item is allowed for viewing (non permission-based)
*
* @param kEvent $event
* @return bool
* @access protected
*/
- protected function checkItemStatus(kEvent &$event)
+ protected function checkItemStatus(kEvent $event)
{
$object =& $event->getObject();
/* @var $object kDBItem */
if ( !$object->isLoaded() ) {
return true;
}
if ( $object->GetDBField('Status') != STATUS_ACTIVE && $object->GetDBField('Status') != 4 ) {
if ( !$object->GetDBField('DirectLinkEnabled') || !$object->GetDBField('DirectLinkAuthKey') ) {
return false;
}
return $this->Application->GetVar('authkey') == $object->GetDBField('DirectLinkAuthKey');
}
return true;
}
// ============= for cms page processing =======================
/**
* Returns default design template
*
* @return string
*/
function _getDefaultDesign()
{
$default_design = trim($this->Application->ConfigValue('cms_DefaultDesign'), '/');
if (!$default_design) {
// theme-based alias for default design
return '#default_design#';
}
if (strpos($default_design, '#') === false) {
// real template, not alias, so prefix with "/"
return '/' . $default_design;
}
// alias
return $default_design;
}
/**
* Returns default design based on given virtual template (used from kApplication::Run)
*
* @param string $t
* @return string
* @access public
*/
public function GetDesignTemplate($t = null)
{
if ( !isset($t) ) {
$t = $this->Application->GetVar('t');
}
$page =& $this->Application->recallObject($this->Prefix . '.-virtual', null, Array ('page' => $t));
/* @var $page CategoriesItem */
if ( $page->isLoaded() ) {
$real_t = $page->GetDBField('CachedTemplate');
$this->Application->SetVar('m_cat_id', $page->GetDBField('CategoryId'));
if ( $page->GetDBField('FormId') ) {
$this->Application->SetVar('form_id', $page->GetDBField('FormId'));
}
}
else {
$not_found = $this->Application->ConfigValue('ErrorTemplate');
$real_t = $not_found ? $not_found : 'error_notfound';
$themes_helper =& $this->Application->recallObject('ThemesHelper');
/* @var $themes_helper kThemesHelper */
$theme_id = $this->Application->GetVar('m_theme');
$category_id = $themes_helper->getPageByTemplate($real_t, $theme_id);
$this->Application->SetVar('m_cat_id', $category_id);
header('HTTP/1.0 404 Not Found');
}
// replace alias in form #alias_name# to actual template used in this theme
$theme =& $this->Application->recallObject('theme.current');
/* @var $theme kDBItem */
$template = $theme->GetField('TemplateAliases', $real_t);
if ( $template ) {
return $template;
}
return $real_t;
}
/**
* Sets category id based on found template (used from kApplication::Run)
*
* @deprecated
*/
/*function SetCatByTemplate()
{
$t = $this->Application->GetVar('t');
$page =& $this->Application->recallObject($this->Prefix . '.-virtual');
if ($page->isLoaded()) {
$this->Application->SetVar('m_cat_id', $page->GetDBField('CategoryId') );
}
}*/
/**
* Prepares template paths
*
* @param kEvent $event
*/
- function _beforeItemChange(&$event)
+ function _beforeItemChange($event)
{
$object =& $event->getObject();
/* @var $object CategoriesItem */
$object->checkFilename();
$object->generateFilename();
$now = adodb_mktime();
if ( !$this->Application->isDebugMode() && strpos($event->Special, 'rebuild') === false ) {
$object->SetDBField('Type', $object->GetOriginalField('Type'));
$object->SetDBField('Protected', $object->GetOriginalField('Protected'));
if ( $object->GetDBField('Protected') ) {
// some fields are read-only for protected pages, when debug mode is off
$object->SetDBField('AutomaticFilename', $object->GetOriginalField('AutomaticFilename'));
$object->SetDBField('Filename', $object->GetOriginalField('Filename'));
$object->SetDBField('Status', $object->GetOriginalField('Status'));
}
}
$is_admin = $this->Application->isAdminUser;
if ( (!$object->IsTempTable() && !$is_admin) || ($is_admin && !$object->GetDBField('CreatedById')) ) {
$object->SetDBField('CreatedById', $this->Application->RecallVar('user_id'));
}
if ($object->GetChangedFields()) {
$object->SetDBField('Modified_date', $now);
$object->SetDBField('Modified_time', $now);
}
$object->setRequired('PageCacheKey', $object->GetDBField('OverridePageCacheKey'));
$object->SetDBField('Template', $this->_stripTemplateExtension( $object->GetDBField('Template') ));
if ($object->GetDBField('Type') == PAGE_TYPE_TEMPLATE) {
if (!$this->_templateFound($object->GetDBField('Template'), $object->GetDBField('ThemeId'))) {
$object->SetError('Template', 'template_file_missing', 'la_error_TemplateFileMissing');
}
}
$this->_saveTitleField($object, 'Title');
$this->_saveTitleField($object, 'MenuTitle');
$root_category = $this->Application->getBaseCategory();
if ( file_exists(FULL_PATH . '/themes') && ($object->GetDBField('ParentId') == $root_category) && ($object->GetDBField('Template') == CATEGORY_TEMPLATE_INHERIT) ) {
// there are themes + creating top level category
$object->SetError('Template', 'no_inherit');
}
if ( !$this->Application->isAdminUser && $object->isVirtualField('cust_RssSource') ) {
// only administrator can set/change "cust_RssSource" field
if ($object->GetDBField('cust_RssSource') != $object->GetOriginalField('cust_RssSource')) {
$object->SetError('cust_RssSource', 'not_allowed', 'la_error_OperationNotAllowed');
}
}
if ( !$object->GetDBField('DirectLinkAuthKey') ) {
$key_parts = Array (
$object->GetID(),
$object->GetDBField('ParentId'),
$object->GetField('Name'),
'b38'
);
$object->SetDBField('DirectLinkAuthKey', substr( md5( implode(':', $key_parts) ), 0, 20 ));
}
}
/**
* Sets page name to requested field in case when:
* 1. page was auto created (through theme file rebuild)
* 2. requested field is empty
*
* @param kDBItem $object
* @param string $field
* @author Alex
*/
function _saveTitleField(&$object, $field)
{
$value = $object->GetField($field, 'no_default'); // current value of target field
$ml_formatter =& $this->Application->recallObject('kMultiLanguage');
/* @var $ml_formatter kMultiLanguage */
$src_field = $ml_formatter->LangFieldName('Name');
$dst_field = $ml_formatter->LangFieldName($field);
$dst_field_not_changed = $object->GetOriginalField($dst_field) == $value;
if ($value == '' || preg_match('/^_Auto: (.*)/', $value) || (($object->GetOriginalField($src_field) == $value) && $dst_field_not_changed)) {
// target field is empty OR target field value starts with "_Auto: " OR (source field value
// before change was equals to current target field value AND target field value wasn't changed)
$object->SetField($dst_field, $object->GetField($src_field));
}
}
/**
* Don't allow to delete system pages, when not in debug mode
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnBeforeItemDelete(kEvent &$event)
+ protected function OnBeforeItemDelete(kEvent $event)
{
parent::OnBeforeItemDelete($event);
$object =& $event->getObject();
/* @var $object kDBItem */
if ( $object->GetDBField('Protected') && !$this->Application->isDebugMode(false) ) {
$event->status = kEvent::erFAIL;
}
}
/**
* Creates category based on given TPL file
*
* @param CategoriesItem $object
* @param string $template
* @param int $theme_id
* @param int $system_mode
* @param array $template_info
* @return bool
*/
function _prepareAutoPage(&$object, $template, $theme_id = null, $system_mode = SMS_MODE_AUTO, $template_info = Array ())
{
$template = $this->_stripTemplateExtension($template);
if ($system_mode == SMS_MODE_AUTO) {
$page_type = $this->_templateFound($template, $theme_id) ? PAGE_TYPE_TEMPLATE : PAGE_TYPE_VIRTUAL;
}
else {
$page_type = $system_mode == SMS_MODE_FORCE ? PAGE_TYPE_TEMPLATE : PAGE_TYPE_VIRTUAL;
}
if (($page_type == PAGE_TYPE_TEMPLATE) && ($template_info === false)) {
// do not auto-create system pages, when browsing through site
return false;
}
if (!isset($theme_id)) {
$theme_id = $this->_getCurrentThemeId();
}
$root_category = $this->Application->getBaseCategory();
$page_category = $this->Application->GetVar('m_cat_id');
if (!$page_category) {
$page_category = $root_category;
$this->Application->SetVar('m_cat_id', $page_category);
}
if (($page_type == PAGE_TYPE_VIRTUAL) && (strpos($template, '/') !== false)) {
// virtual page, but have "/" in template path -> create it's path
$category_path = explode('/', $template);
$template = array_pop($category_path);
$page_category = $this->_getParentCategoryFromPath($category_path, $root_category, $theme_id);
}
$page_name = ($page_type == PAGE_TYPE_TEMPLATE) ? '_Auto: ' . $template : $template;
$page_description = '';
if ($page_type == PAGE_TYPE_TEMPLATE) {
$design_template = strtolower($template); // leading "/" not added !
if ($template_info) {
if (array_key_exists('name', $template_info) && $template_info['name']) {
$page_name = $template_info['name'];
}
if (array_key_exists('desc', $template_info) && $template_info['desc']) {
$page_description = $template_info['desc'];
}
if (array_key_exists('section', $template_info) && $template_info['section']) {
// this will override any global "m_cat_id"
$page_category = $this->_getParentCategoryFromPath(explode('||', $template_info['section']), $root_category, $theme_id);
}
}
}
else {
$design_template = $this->_getDefaultDesign(); // leading "/" added !
}
$object->Clear();
$object->SetDBField('ParentId', $page_category);
$object->SetDBField('Type', $page_type);
$object->SetDBField('Protected', 1); // $page_type == PAGE_TYPE_TEMPLATE
$object->SetDBField('IsMenu', 0);
$object->SetDBField('ThemeId', $theme_id);
// put all templates to then end of list (in their category)
$min_priority = $this->_getNextPriority($page_category, $object->TableName);
$object->SetDBField('Priority', $min_priority);
$object->SetDBField('Template', $design_template);
$object->SetDBField('CachedTemplate', $design_template);
$primary_language = $this->Application->GetDefaultLanguageId();
$current_language = $this->Application->GetVar('m_lang');
$object->SetDBField('l' . $primary_language . '_Name', $page_name);
$object->SetDBField('l' . $current_language . '_Name', $page_name);
$object->SetDBField('l' . $primary_language . '_Description', $page_description);
$object->SetDBField('l' . $current_language . '_Description', $page_description);
return $object->Create();
}
function _getParentCategoryFromPath($category_path, $base_category, $theme_id = null)
{
static $category_ids = Array ();
if (!$category_path) {
return $base_category;
}
if (array_key_exists(implode('||', $category_path), $category_ids)) {
return $category_ids[ implode('||', $category_path) ];
}
$backup_category_id = $this->Application->GetVar('m_cat_id');
$object =& $this->Application->recallObject($this->Prefix . '.rebuild-path', null, Array ('skip_autoload' => true));
/* @var $object CategoriesItem */
$parent_id = $base_category;
$filenames_helper =& $this->Application->recallObject('FilenamesHelper');
/* @var $filenames_helper kFilenamesHelper */
$safe_category_path = array_map(Array (&$filenames_helper, 'replaceSequences'), $category_path);
foreach ($category_path as $category_order => $category_name) {
$this->Application->SetVar('m_cat_id', $parent_id);
// get virtual category first, when possible
$sql = 'SELECT ' . $object->IDField . '
FROM ' . $object->TableName . '
WHERE
(
Filename = ' . $this->Conn->qstr($safe_category_path[$category_order]) . ' OR
Filename = ' . $this->Conn->qstr( $filenames_helper->replaceSequences('_Auto: ' . $category_name) ) . '
) AND
(ParentId = ' . $parent_id . ') AND
(ThemeId = 0 OR ThemeId = ' . $theme_id . ')
ORDER BY ThemeId ASC';
$parent_id = $this->Conn->GetOne($sql);
if ($parent_id === false) {
// page not found
$template = implode('/', array_slice($safe_category_path, 0, $category_order + 1));
// don't process system templates in sub-categories
$system = $this->_templateFound($template, $theme_id) && (strpos($template, '/') === false);
if (!$this->_prepareAutoPage($object, $category_name, $theme_id, $system ? SMS_MODE_FORCE : false)) {
// page was not created
break;
}
$parent_id = $object->GetID();
}
}
$this->Application->SetVar('m_cat_id', $backup_category_id);
$category_ids[ implode('||', $category_path) ] = $parent_id;
return $parent_id;
}
/**
* Returns theme name by it's id. Used in structure page creation.
*
* @param int $theme_id
* @return string
*/
function _getThemeName($theme_id)
{
static $themes = null;
if (!isset($themes)) {
$id_field = $this->Application->getUnitOption('theme', 'IDField');
$table_name = $this->Application->getUnitOption('theme', 'TableName');
$sql = 'SELECT Name, ' . $id_field . '
FROM ' . $table_name . '
WHERE Enabled = 1';
$themes = $this->Conn->GetCol($sql, $id_field);
}
return array_key_exists($theme_id, $themes) ? $themes[$theme_id] : false;
}
/**
* Resets SMS-menu cache
*
* @param kEvent $event
*/
- function OnResetCMSMenuCache(&$event)
+ function OnResetCMSMenuCache($event)
{
if ($this->Application->GetVar('ajax') == 'yes') {
$event->status = kEvent::erSTOP;
}
$this->_resetMenuCache();
$event->SetRedirectParam('action_completed', 1);
}
/**
* Performs reset of category-related caches (menu, structure dropdown, template mapping)
*
* @return void
* @access protected
*/
protected function _resetMenuCache()
{
// reset cms menu cache (all variables are automatically rebuild, when missing)
if ($this->Application->isCachingType(CACHING_TYPE_MEMORY)) {
$this->Application->rebuildCache('master:cms_menu', kCache::REBUILD_LATER, CacheSettings::$cmsMenuRebuildTime);
$this->Application->rebuildCache('master:StructureTree', kCache::REBUILD_LATER, CacheSettings::$structureTreeRebuildTime);
$this->Application->rebuildCache('master:template_mapping', kCache::REBUILD_LATER, CacheSettings::$templateMappingRebuildTime);
}
else {
$this->Application->rebuildDBCache('cms_menu', kCache::REBUILD_LATER, CacheSettings::$cmsMenuRebuildTime);
$this->Application->rebuildDBCache('StructureTree', kCache::REBUILD_LATER, CacheSettings::$structureTreeRebuildTime);
$this->Application->rebuildDBCache('template_mapping', kCache::REBUILD_LATER, CacheSettings::$templateMappingRebuildTime);
}
}
/**
* Updates structure config
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnAfterConfigRead(kEvent &$event)
+ protected function OnAfterConfigRead(kEvent $event)
{
parent::OnAfterConfigRead($event);
if (defined('IS_INSTALL') && IS_INSTALL) {
// skip any processing, because Categories table doesn't exists until install is finished
return ;
}
$site_config_helper =& $this->Application->recallObject('SiteConfigHelper');
/* @var $site_config_helper SiteConfigHelper */
$settings = $site_config_helper->getSettings();
$root_category = $this->Application->getBaseCategory();
// set root category
$section_adjustments = $this->Application->getUnitOption($event->Prefix, 'SectionAdjustments');
$section_adjustments['in-portal:browse'] = Array (
'url' => Array ('m_cat_id' => $root_category),
'late_load' => Array ('m_cat_id' => $root_category),
'onclick' => 'checkCatalog(' . $root_category . ')',
);
$section_adjustments['in-portal:browse_site'] = Array (
'url' => Array ('editing_mode' => $settings['default_editing_mode']),
);
$this->Application->setUnitOption($event->Prefix, 'SectionAdjustments', $section_adjustments);
// prepare structure dropdown
$category_helper =& $this->Application->recallObject('CategoryHelper');
/* @var $category_helper CategoryHelper */
$fields = $this->Application->getUnitOption($event->Prefix, 'Fields');
$fields['ParentId']['default'] = (int)$this->Application->GetVar('m_cat_id');
$fields['ParentId']['options'] = $category_helper->getStructureTreeAsOptions();
// limit design list by theme
$theme_id = $this->_getCurrentThemeId();
$design_sql = $fields['Template']['options_sql'];
$design_sql = str_replace('(tf.FilePath = "/designs")', '(' . implode(' OR ', $this->getDesignFolders()) . ')' . ' AND (t.ThemeId = ' . $theme_id . ')', $design_sql);
$fields['Template']['options_sql'] = $design_sql;
// adds "Inherit From Parent" option to "Template" field
$fields['Template']['options'] = Array (CATEGORY_TEMPLATE_INHERIT => $this->Application->Phrase('la_opt_InheritFromParent'));
$this->Application->setUnitOption($event->Prefix, 'Fields', $fields);
if ($this->Application->isAdmin) {
// don't sort by Front-End sorting fields
$config_mapping = $this->Application->getUnitOption($event->Prefix, 'ConfigMapping');
$remove_keys = Array ('DefaultSorting1Field', 'DefaultSorting2Field', 'DefaultSorting1Dir', 'DefaultSorting2Dir');
foreach ($remove_keys as $remove_key) {
unset($config_mapping[$remove_key]);
}
$this->Application->setUnitOption($event->Prefix, 'ConfigMapping', $config_mapping);
}
else {
// sort by parent path on Front-End only
$list_sortings = $this->Application->getUnitOption($event->Prefix, 'ListSortings', Array ());
$list_sortings['']['ForcedSorting'] = Array ("CurrentSort" => 'asc');
$this->Application->setUnitOption($event->Prefix, 'ListSortings', $list_sortings);
}
// add grids for advanced view (with primary category column)
$grids = $this->Application->getUnitOption($this->Prefix, 'Grids');
$process_grids = Array ('Default', 'Radio');
foreach ($process_grids as $process_grid) {
$grid_data = $grids[$process_grid];
$grid_data['Fields']['CachedNavbar'] = Array ('title' => 'la_col_Path', 'data_block' => 'grid_parent_category_td', 'filter_block' => 'grid_like_filter');
$grids[$process_grid . 'ShowAll'] = $grid_data;
}
$this->Application->setUnitOption($this->Prefix, 'Grids', $grids);
}
/**
* Returns folders, that can contain design templates
*
* @return array
* @access protected
*/
protected function getDesignFolders()
{
$ret = Array ('tf.FilePath = "/designs"', 'tf.FilePath = "/platform/designs"');
foreach ($this->Application->ModuleInfo as $module_info) {
$ret[] = 'tf.FilePath = "/' . $module_info['TemplatePath'] . 'designs"';
}
return array_unique($ret);
}
/**
* Removes this item and it's children (recursive) from structure dropdown
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnAfterItemLoad(kEvent &$event)
+ protected function OnAfterItemLoad(kEvent $event)
{
parent::OnAfterItemLoad($event);
if ( !$this->Application->isAdmin ) {
// calculate priorities dropdown only for admin
return;
}
$object =& $event->getObject();
/* @var $object kDBItem */
// remove this category & it's children from dropdown
$sql = 'SELECT ' . $object->IDField . '
FROM ' . $this->Application->getUnitOption($event->Prefix, 'TableName') . '
WHERE ParentPath LIKE "' . $object->GetDBField('ParentPath') . '%"';
$remove_categories = $this->Conn->GetCol($sql);
$options = $object->GetFieldOption('ParentId', 'options');
foreach ($remove_categories as $remove_category) {
unset($options[$remove_category]);
}
$object->SetFieldOption('ParentId', 'options', $options);
}
/**
* Occurs after creating item
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnAfterItemCreate(kEvent &$event)
+ protected function OnAfterItemCreate(kEvent $event)
{
parent::OnAfterItemCreate($event);
$object =& $event->getObject();
/* @var $object CategoriesItem */
// need to update path after category is created, so category is included in that path
$parent_path = $object->buildParentPath();
$sql = 'UPDATE ' . $object->TableName . '
SET ParentPath = ' . $this->Conn->qstr($parent_path) . '
WHERE CategoryId = ' . $object->GetID();
$this->Conn->Query($sql);
$object->SetDBField('ParentPath', $parent_path);
}
/**
* Enter description here...
*
* @param kEvent $event
*/
- function OnAfterRebuildThemes(&$event)
+ function OnAfterRebuildThemes($event)
{
$sql = 'SELECT t.ThemeId, CONCAT( tf.FilePath, \'/\', tf.FileName ) AS Path, tf.FileMetaInfo
FROM '.TABLE_PREFIX.'ThemeFiles AS tf
LEFT JOIN '.TABLE_PREFIX.'Themes AS t ON t.ThemeId = tf.ThemeId
WHERE t.Enabled = 1 AND tf.FileType = 1
AND (
SELECT COUNT(CategoryId)
FROM ' . TABLE_PREFIX . 'Categories c
WHERE CONCAT(\'/\', c.Template, \'.tpl\') = CONCAT( tf.FilePath, \'/\', tf.FileName ) AND (c.ThemeId = t.ThemeId)
) = 0 ';
$files = $this->Conn->Query($sql, 'Path');
if (!$files) {
// all possible pages are already created
return ;
}
set_time_limit(0);
ini_set('memory_limit', -1);
$dummy =& $this->Application->recallObject($event->Prefix . '.rebuild', null, Array ('skip_autoload' => true));
/* @var $dummy CategoriesItem */
$error_count = 0;
foreach ($files as $a_file => $file_info) {
$status = $this->_prepareAutoPage($dummy, $a_file, $file_info['ThemeId'], SMS_MODE_FORCE, unserialize($file_info['FileMetaInfo'])); // create system page
if (!$status) {
$error_count++;
}
}
if ($this->Application->ConfigValue('QuickCategoryPermissionRebuild')) {
$updater =& $this->Application->makeClass('kPermCacheUpdater');
/* @var $updater kPermCacheUpdater */
$updater->OneStepRun();
}
$this->_resetMenuCache();
if ($error_count) {
// allow user to review error after structure page creation
$event->MasterEvent->redirect = false;
}
}
/**
* Processes OnMassMoveUp, OnMassMoveDown events
*
* @param kEvent $event
*/
- function OnChangePriority(&$event)
+ function OnChangePriority($event)
{
$this->Application->SetVar('priority_prefix', $event->getPrefixSpecial());
$event->CallSubEvent('priority:' . $event->Name);
$this->Application->StoreVar('RefreshStructureTree', 1);
$this->_resetMenuCache();
}
/**
* Completely recalculates priorities in current category
*
* @param kEvent $event
*/
- function OnRecalculatePriorities(&$event)
+ function OnRecalculatePriorities($event)
{
if ($this->Application->CheckPermission('SYSTEM_ACCESS.READONLY', 1)) {
$event->status = kEvent::erFAIL;
return;
}
$this->Application->SetVar('priority_prefix', $event->getPrefixSpecial());
$event->CallSubEvent('priority:' . $event->Name);
$this->_resetMenuCache();
}
/**
* Update Preview Block for FCKEditor
*
* @param kEvent $event
*/
- function OnUpdatePreviewBlock(&$event)
+ function OnUpdatePreviewBlock($event)
{
$event->status = kEvent::erSTOP;
$string = kUtil::unhtmlentities($this->Application->GetVar('preview_content'));
$category_helper =& $this->Application->recallObject('CategoryHelper');
/* @var $category_helper CategoryHelper */
$string = $category_helper->replacePageIds($string);
$this->Application->StoreVar('_editor_preview_content_', $string);
}
/**
* Makes simple search for categories
* based on keywords string
*
* @param kEvent $event
*/
- function OnSimpleSearch(&$event)
+ function OnSimpleSearch($event)
{
$event->redirect = false;
$search_table = TABLE_PREFIX.'ses_'.$this->Application->GetSID().'_'.TABLE_PREFIX.'Search';
$keywords = kUtil::unhtmlentities( trim($this->Application->GetVar('keywords')) );
$query_object =& $this->Application->recallObject('HTTPQuery');
/* @var $query_object kHTTPQuery */
$sql = 'SHOW TABLES LIKE "'.$search_table.'"';
if ( !isset($query_object->Get['keywords']) && !isset($query_object->Post['keywords']) && $this->Conn->Query($sql) ) {
// used when navigating by pages or changing sorting in search results
return;
}
if(!$keywords || strlen($keywords) < $this->Application->ConfigValue('Search_MinKeyword_Length'))
{
$this->Conn->Query('DROP TABLE IF EXISTS '.$search_table);
$this->Application->SetVar('keywords_too_short', 1);
return; // if no or too short keyword entered, doing nothing
}
$this->Application->StoreVar('keywords', $keywords);
$this->saveToSearchLog($keywords, 0); // 0 - simple search, 1 - advanced search
$keywords = strtr($keywords, Array('%' => '\\%', '_' => '\\_'));
$event->setPseudoClass('_List');
$object =& $event->getObject();
/* @var $object kDBList */
$this->Application->SetVar($event->getPrefixSpecial().'_Page', 1);
$lang = $this->Application->GetVar('m_lang');
$items_table = $this->Application->getUnitOption($event->Prefix, 'TableName');
$module_name = 'In-Portal';
$sql = 'SELECT *
FROM ' . $this->Application->getUnitOption('confs', 'TableName') . '
WHERE ModuleName = ' . $this->Conn->qstr($module_name) . ' AND SimpleSearch = 1';
$search_config = $this->Conn->Query($sql, 'FieldName');
$field_list = array_keys($search_config);
$join_clauses = Array();
// field processing
$weight_sum = 0;
$alias_counter = 0;
$custom_fields = $this->Application->getUnitOption($event->Prefix, 'CustomFields');
if ($custom_fields) {
$custom_table = $this->Application->getUnitOption($event->Prefix.'-cdata', 'TableName');
$join_clauses[] = ' LEFT JOIN '.$custom_table.' custom_data ON '.$items_table.'.ResourceId = custom_data.ResourceId';
}
// what field in search config becomes what field in sql (key - new field, value - old field (from searchconfig table))
$search_config_map = Array();
foreach ($field_list as $key => $field) {
$local_table = TABLE_PREFIX.$search_config[$field]['TableName'];
$weight_sum += $search_config[$field]['Priority']; // counting weight sum; used when making relevance clause
// processing multilingual fields
if ( !$search_config[$field]['CustomFieldId'] && $object->GetFieldOption($field, 'formatter') == 'kMultiLanguage' ) {
$field_list[$key.'_primary'] = 'l'.$this->Application->GetDefaultLanguageId().'_'.$field;
$field_list[$key] = 'l'.$lang.'_'.$field;
if (!isset($search_config[$field]['ForeignField'])) {
$field_list[$key.'_primary'] = $local_table.'.'.$field_list[$key.'_primary'];
$search_config_map[ $field_list[$key.'_primary'] ] = $field;
}
}
// processing fields from other tables
$foreign_field = $search_config[$field]['ForeignField'];
if ( $foreign_field ) {
$exploded = explode(':', $foreign_field, 2);
if ($exploded[0] == 'CALC') {
// ignoring having type clauses in simple search
unset($field_list[$key]);
continue;
}
else {
$multi_lingual = false;
if ($exploded[0] == 'MULTI') {
$multi_lingual = true;
$foreign_field = $exploded[1];
}
$exploded = explode('.', $foreign_field); // format: table.field_name
$foreign_table = TABLE_PREFIX.$exploded[0];
$alias_counter++;
$alias = 't'.$alias_counter;
if ($multi_lingual) {
$field_list[$key] = $alias.'.'.'l'.$lang.'_'.$exploded[1];
$field_list[$key.'_primary'] = 'l'.$this->Application->GetDefaultLanguageId().'_'.$field;
$search_config_map[ $field_list[$key] ] = $field;
$search_config_map[ $field_list[$key.'_primary'] ] = $field;
}
else {
$field_list[$key] = $alias.'.'.$exploded[1];
$search_config_map[ $field_list[$key] ] = $field;
}
$join_clause = str_replace('{ForeignTable}', $alias, $search_config[$field]['JoinClause']);
$join_clause = str_replace('{LocalTable}', $items_table, $join_clause);
$join_clauses[] = ' LEFT JOIN '.$foreign_table.' '.$alias.'
ON '.$join_clause;
}
}
else {
// processing fields from local table
if ($search_config[$field]['CustomFieldId']) {
$local_table = 'custom_data';
// search by custom field value on current language
$custom_field_id = array_search($field_list[$key], $custom_fields);
$field_list[$key] = 'l'.$lang.'_cust_'.$custom_field_id;
// search by custom field value on primary language
$field_list[$key.'_primary'] = $local_table.'.l'.$this->Application->GetDefaultLanguageId().'_cust_'.$custom_field_id;
$search_config_map[ $field_list[$key.'_primary'] ] = $field;
}
$field_list[$key] = $local_table.'.'.$field_list[$key];
$search_config_map[ $field_list[$key] ] = $field;
}
}
// keyword string processing
$search_helper =& $this->Application->recallObject('SearchHelper');
/* @var $search_helper kSearchHelper */
$where_clause = Array ();
foreach ($field_list as $field) {
if (preg_match('/^' . preg_quote($items_table, '/') . '\.(.*)/', $field, $regs)) {
// local real field
$filter_data = $search_helper->getSearchClause($object, $regs[1], $keywords, false);
if ($filter_data) {
$where_clause[] = $filter_data['value'];
}
}
elseif (preg_match('/^custom_data\.(.*)/', $field, $regs)) {
$custom_field_name = 'cust_' . $search_config_map[$field];
$filter_data = $search_helper->getSearchClause($object, $custom_field_name, $keywords, false);
if ($filter_data) {
$where_clause[] = str_replace('`' . $custom_field_name . '`', $field, $filter_data['value']);
}
}
else {
$where_clause[] = $search_helper->buildWhereClause($keywords, Array ($field));
}
}
$where_clause = '((' . implode(') OR (', $where_clause) . '))'; // 2 braces for next clauses, see below!
$where_clause = $where_clause . ' AND (' . $items_table . '.Status = ' . STATUS_ACTIVE . ')';
if ($event->MasterEvent && $event->MasterEvent->Name == 'OnListBuild') {
if ($event->MasterEvent->getEventParam('ResultIds')) {
$where_clause .= ' AND '.$items_table.'.ResourceId IN ('.implode(',', $event->MasterEvent->getEventParam('ResultIds')).')';
}
}
// exclude template based sections from search results (ie. registration)
if ( $this->Application->ConfigValue('ExcludeTemplateSectionsFromSearch') ) {
$where_clause .= ' AND ' . $items_table . '.ThemeId = 0';
}
// making relevance clause
$positive_words = $search_helper->getPositiveKeywords($keywords);
$this->Application->StoreVar('highlight_keywords', serialize($positive_words));
$revelance_parts = Array();
reset($search_config);
foreach ($positive_words as $keyword_index => $positive_word) {
$positive_word = $search_helper->transformWildcards($positive_word);
$positive_words[$keyword_index] = $this->Conn->escape($positive_word);
}
foreach ($field_list as $field) {
if (!array_key_exists($field, $search_config_map)) {
$map_key = $search_config_map[$items_table . '.' . $field];
}
else {
$map_key = $search_config_map[$field];
}
$config_elem = $search_config[ $map_key ];
$weight = $config_elem['Priority'];
// search by whole words only ([[:<:]] - word boundary)
/*$revelance_parts[] = 'IF('.$field.' REGEXP "[[:<:]]('.implode(' ', $positive_words).')[[:>:]]", '.$weight.', 0)';
foreach ($positive_words as $keyword) {
$revelance_parts[] = 'IF('.$field.' REGEXP "[[:<:]]('.$keyword.')[[:>:]]", '.$weight.', 0)';
}*/
// search by partial word matches too
$revelance_parts[] = 'IF('.$field.' LIKE "%'.implode(' ', $positive_words).'%", '.$weight_sum.', 0)';
foreach ($positive_words as $keyword) {
$revelance_parts[] = 'IF('.$field.' LIKE "%'.$keyword.'%", '.$weight.', 0)';
}
}
$revelance_parts = array_unique($revelance_parts);
$conf_postfix = $this->Application->getUnitOption($event->Prefix, 'SearchConfigPostfix');
$rel_keywords = $this->Application->ConfigValue('SearchRel_Keyword_'.$conf_postfix) / 100;
$rel_pop = $this->Application->ConfigValue('SearchRel_Pop_'.$conf_postfix) / 100;
$rel_rating = $this->Application->ConfigValue('SearchRel_Rating_'.$conf_postfix) / 100;
$relevance_clause = '('.implode(' + ', $revelance_parts).') / '.$weight_sum.' * '.$rel_keywords;
if ($rel_pop && $object->isField('Hits')) {
$relevance_clause .= ' + (Hits + 1) / (MAX(Hits) + 1) * '.$rel_pop;
}
if ($rel_rating && $object->isField('CachedRating')) {
$relevance_clause .= ' + (CachedRating + 1) / (MAX(CachedRating) + 1) * '.$rel_rating;
}
// building final search query
if (!$this->Application->GetVar('do_not_drop_search_table')) {
$this->Conn->Query('DROP TABLE IF EXISTS '.$search_table); // erase old search table if clean k4 event
$this->Application->SetVar('do_not_drop_search_table', true);
}
$search_table_exists = $this->Conn->Query('SHOW TABLES LIKE "'.$search_table.'"');
if ($search_table_exists) {
$select_intro = 'INSERT INTO '.$search_table.' (Relevance, ItemId, ResourceId, ItemType, EdPick) ';
}
else {
$select_intro = 'CREATE TABLE '.$search_table.' AS ';
}
$edpick_clause = $this->Application->getUnitOption($event->Prefix.'.EditorsPick', 'Fields') ? $items_table.'.EditorsPick' : '0';
$sql = $select_intro.' SELECT '.$relevance_clause.' AS Relevance,
'.$items_table.'.'.$this->Application->getUnitOption($event->Prefix, 'IDField').' AS ItemId,
'.$items_table.'.ResourceId,
'.$this->Application->getUnitOption($event->Prefix, 'ItemType').' AS ItemType,
'.$edpick_clause.' AS EdPick
FROM '.$object->TableName.'
'.implode(' ', $join_clauses).'
WHERE '.$where_clause.'
GROUP BY '.$items_table.'.'.$this->Application->getUnitOption($event->Prefix, 'IDField').' ORDER BY Relevance DESC';
$this->Conn->Query($sql);
if ( !$search_table_exists ) {
$sql = 'ALTER TABLE ' . $search_table . '
ADD INDEX (ResourceId),
ADD INDEX (Relevance)';
$this->Conn->Query($sql);
}
}
/**
* Make record to search log
*
* @param string $keywords
* @param int $search_type 0 - simple search, 1 - advanced search
*/
function saveToSearchLog($keywords, $search_type = 0)
{
// don't save keywords for each module separately, just one time
// static variable can't help here, because each module uses it's own class instance !
if (!$this->Application->GetVar('search_logged')) {
$sql = 'UPDATE '.TABLE_PREFIX.'SearchLogs
SET Indices = Indices + 1
WHERE Keyword = '.$this->Conn->qstr($keywords).' AND SearchType = '.$search_type; // 0 - simple search, 1 - advanced search
$this->Conn->Query($sql);
if ($this->Conn->getAffectedRows() == 0) {
$fields_hash = Array('Keyword' => $keywords, 'Indices' => 1, 'SearchType' => $search_type);
$this->Conn->doInsert($fields_hash, TABLE_PREFIX.'SearchLogs');
}
$this->Application->SetVar('search_logged', 1);
}
}
/**
* Load item if id is available
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function LoadItem(kEvent &$event)
+ protected function LoadItem(kEvent $event)
{
if ( $event->Special != '-virtual' ) {
parent::LoadItem($event);
return;
}
$object =& $event->getObject();
/* @var $object kDBItem */
$id = $this->getPassedID($event);
if ( $object->isLoaded() && !is_array($id) && ($object->GetID() == $id) ) {
// object is already loaded by same id
return;
}
if ( $object->Load($id, null, true) ) {
$actions =& $this->Application->recallObject('kActions');
/* @var $actions Params */
$actions->Set($event->getPrefixSpecial() . '_id', $object->GetID());
}
else {
$object->setID($id);
}
}
/**
* Returns constrain for priority calculations
*
* @param kEvent $event
* @return void
* @see PriorityEventHandler
* @access protected
*/
- protected function OnGetConstrainInfo(kEvent &$event)
+ protected function OnGetConstrainInfo(kEvent $event)
{
$constrain = ''; // for OnSave
$event_name = $event->getEventParam('original_event');
$actual_event_name = $event->getEventParam('actual_event');
if ( $actual_event_name == 'OnSavePriorityChanges' || $event_name == 'OnAfterItemLoad' || $event_name == 'OnAfterItemDelete' ) {
$object =& $event->getObject();
/* @var $object kDBItem */
$constrain = 'ParentId = ' . $object->GetDBField('ParentId');
}
elseif ( $actual_event_name == 'OnPreparePriorities' ) {
$constrain = 'ParentId = ' . $this->Application->GetVar('m_cat_id');
}
elseif ( $event_name == 'OnSave' ) {
$constrain = '';
}
else {
$constrain = 'ParentId = ' . $this->Application->GetVar('m_cat_id');
}
$event->setEventParam('constrain_info', Array ($constrain, ''));
}
/**
* Parses category part of url, build main part of url
*
* @param int $rewrite_mode Mode in what rewrite listener was called. Possbile two modes: REWRITE_MODE_BUILD, REWRITE_MODE_PARSE.
* @param string $prefix Prefix, that listener uses for system integration
* @param Array $params Params, that are used for url building or created during url parsing.
* @param Array $url_parts Url parts to parse (only for parsing).
* @param bool $keep_events Keep event names in resulting url (only for building).
* @return bool|string|Array Return true to continue to next listener; return false (when building) not to rewrite given prefix; return false (when parsing) to stop processing at this listener.
*/
public function CategoryRewriteListener($rewrite_mode = REWRITE_MODE_BUILD, $prefix, &$params, &$url_parts, $keep_events = false)
{
if ($rewrite_mode == REWRITE_MODE_BUILD) {
return $this->_buildMainUrl($prefix, $params, $keep_events);
}
if ( $this->_parseFriendlyUrl($url_parts, $params) ) {
// friendly urls work like exact match only!
return false;
}
$this->_parseCategory($url_parts, $params);
return true;
}
/**
* Build main part of every url
*
* @param string $prefix_special
* @param Array $params
* @param bool $keep_events
* @return string
*/
protected function _buildMainUrl($prefix_special, &$params, $keep_events)
{
$ret = '';
list ($prefix) = explode('.', $prefix_special);
$rewrite_processor =& $this->Application->recallObject('kRewriteUrlProcessor');
/* @var $rewrite_processor kRewriteUrlProcessor */
$processed_params = $rewrite_processor->getProcessedParams($prefix_special, $params, $keep_events);
if ($processed_params === false) {
return '';
}
// add language
if ($processed_params['m_lang'] && ($processed_params['m_lang'] != $rewrite_processor->primaryLanguageId)) {
$language_name = $this->Application->getCache('language_names[%LangIDSerial:' . $processed_params['m_lang'] . '%]');
if ($language_name === false) {
$sql = 'SELECT PackName
FROM ' . TABLE_PREFIX . 'Languages
WHERE LanguageId = ' . $processed_params['m_lang'];
$language_name = $this->Conn->GetOne($sql);
$this->Application->setCache('language_names[%LangIDSerial:' . $processed_params['m_lang'] . '%]', $language_name);
}
$ret .= $language_name . '/';
}
// add theme
if ($processed_params['m_theme'] && ($processed_params['m_theme'] != $rewrite_processor->primaryThemeId)) {
$theme_name = $this->Application->getCache('theme_names[%ThemeIDSerial:' . $processed_params['m_theme'] . '%]');
if ($theme_name === false) {
$sql = 'SELECT Name
FROM ' . TABLE_PREFIX . 'Themes
WHERE ThemeId = ' . $processed_params['m_theme'];
$theme_name = $this->Conn->GetOne($sql);
$this->Application->setCache('theme_names[%ThemeIDSerial:' . $processed_params['m_theme'] . '%]', $theme_name);
}
$ret .= $theme_name . '/';
}
// inject custom url parts made by other rewrite listeners just after language/theme url parts
if ($params['inject_parts']) {
$ret .= implode('/', $params['inject_parts']) . '/';
}
// add category
if ($processed_params['m_cat_id'] > 0 && $params['pass_category']) {
$category_filename = $this->Application->getCategoryCache($processed_params['m_cat_id'], 'filenames');
preg_match('/^Content\/(.*)/i', $category_filename, $regs);
if ($regs) {
$template = array_key_exists('t', $params) ? $params['t'] : false;
if (strtolower($regs[1]) == strtolower($template)) {
// we could have category path like "Content/<template_path>" in this case remove template
$params['pass_template'] = false;
}
$ret .= $regs[1] . '/';
}
$params['category_processed'] = true;
}
// reset category page
$force_page_adding = false;
if (array_key_exists('reset', $params) && $params['reset']) {
unset($params['reset']);
if ($processed_params['m_cat_id']) {
$processed_params['m_cat_page'] = 1;
$force_page_adding = true;
}
}
if ((array_key_exists('category_processed', $params) && $params['category_processed'] && ($processed_params['m_cat_page'] > 1)) || $force_page_adding) {
// category name was added before AND category page number found
$ret = rtrim($ret, '/') . '_' . $processed_params['m_cat_page'] . '/';
}
$template = array_key_exists('t', $params) ? $params['t'] : false;
$category_template = ($processed_params['m_cat_id'] > 0) && $params['pass_category'] ? $this->Application->getCategoryCache($processed_params['m_cat_id'], 'category_designs') : '';
if ((strtolower($template) == '__default__') && ($processed_params['m_cat_id'] == 0)) {
// for "Home" category set template to index when not set
$template = 'index';
}
// remove template from url if it is category index cached template OR site homepage
if (($template == $category_template) || (mb_strtolower($template) == '__default__') || ($template == 'index')) {
// given template is also default template for this category OR '__default__' given OR site homepage
$params['pass_template'] = false;
}
if ($template && $params['pass_template']) {
$ret .= $template . '/';
}
return mb_strtolower( rtrim($ret, '/') );
}
/**
* Checks if whole url_parts matches a whole In-CMS page
*
* @param Array $url_parts
* @param Array $vars
* @return bool
*/
protected function _parseFriendlyUrl($url_parts, &$vars)
{
if (!$url_parts) {
return false;
}
$sql = 'SELECT CategoryId, NamedParentPath
FROM ' . TABLE_PREFIX . 'Categories
WHERE FriendlyURL = ' . $this->Conn->qstr(implode('/', $url_parts));
$friendly = $this->Conn->GetRow($sql);
$rewrite_processor =& $this->Application->recallObject('kRewriteUrlProcessor');
/* @var $rewrite_processor kRewriteUrlProcessor */
if ($friendly) {
$vars['m_cat_id'] = $friendly['CategoryId'];
$vars['t'] = preg_replace('/^Content\//i', '', $friendly['NamedParentPath']);
while ($url_parts) {
$rewrite_processor->partParsed( array_shift($url_parts) );
}
return true;
}
return false;
}
/**
* Extracts category part from url
*
* @param Array $url_parts
* @param Array $vars
* @return bool
*/
protected function _parseCategory($url_parts, &$vars)
{
if (!$url_parts) {
return false;
}
$res = false;
$url_part = array_shift($url_parts);
$category_id = 0;
$last_category_info = false;
$category_path = $url_part == 'content' ? '' : 'content';
$rewrite_processor =& $this->Application->recallObject('kRewriteUrlProcessor');
/* @var $rewrite_processor kRewriteUrlProcessor */
do {
$category_path = trim($category_path . '/' . $url_part, '/');
// bb_<topic_id> -> forums/bb_2
if ( !preg_match('/^bb_[\d]+$/', $url_part) && preg_match('/(.*)_([\d]+)$/', $category_path, $rets) ) {
$category_path = $rets[1];
$vars['m_cat_page'] = $rets[2];
}
$sql = 'SELECT CategoryId, SymLinkCategoryId, NamedParentPath
FROM ' . TABLE_PREFIX . 'Categories
WHERE (LOWER(NamedParentPath) = ' . $this->Conn->qstr($category_path) . ') AND (ThemeId = ' . $vars['m_theme'] . ' OR ThemeId = 0)';
$category_info = $this->Conn->GetRow($sql);
if ($category_info !== false) {
$last_category_info = $category_info;
$rewrite_processor->partParsed($url_part);
$url_part = array_shift($url_parts);
$res = true;
}
} while ($category_info !== false && $url_part);
if ($last_category_info) {
// this category is symlink to other category, so use it's url instead
// (used in case if url prior to symlink adding was indexed by spider or was bookmarked)
if ($last_category_info['SymLinkCategoryId']) {
$sql = 'SELECT CategoryId, NamedParentPath
FROM ' . TABLE_PREFIX . 'Categories
WHERE (CategoryId = ' . $last_category_info['SymLinkCategoryId'] . ')';
$category_info = $this->Conn->GetRow($sql);
if ($category_info) {
// web symlinked category was found use it
// TODO: maybe 302 redirect should be made to symlinked category url (all other url parts should stay)
$last_category_info = $category_info;
}
}
// 1. Set virtual page as template, this will be replaced to physical template later in kApplication::Run.
// 2. Don't set CachedTemplate field as template here, because we will loose original page associated with it's cms blocks!
$vars['t'] = mb_strtolower( preg_replace('/^Content\//i', '', $last_category_info['NamedParentPath']), 'UTF-8' );
$vars['m_cat_id'] = $last_category_info['CategoryId'];
$vars['is_virtual'] = true; // for template from POST, strange code there!
}
else {
$vars['m_cat_id'] = 0;
}
return $res;
}
/**
* Set's new unique resource id to user
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnAfterItemValidate(kEvent &$event)
+ protected function OnAfterItemValidate(kEvent $event)
{
$object =& $event->getObject();
/* @var $object kDBItem */
$resource_id = $object->GetDBField('ResourceId');
if ( !$resource_id ) {
$object->SetDBField('ResourceId', $this->Application->NextResourceId());
}
}
/**
* 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(kEvent &$event)
+ protected function OnBeforeClone(kEvent $event)
{
parent::OnBeforeClone($event);
$object =& $event->getObject();
/* @var $object kDBItem */
$object->SetDBField('ResourceId', 0); // this will reset it
}
}
\ 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 15129)
+++ branches/5.2.x/core/units/themes/themes_eh.php (revision 15130)
@@ -1,203 +1,201 @@
<?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 standard permission mapping
*
* @return void
* @access protected
* @see kEventHandler::$permMapping
*/
protected 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(kEvent &$event)
+ public function CheckPermission(kEvent $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)
+ 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->Application->HandleEvent(new kEvent('adm:OnRebuildThemes'));
}
$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
* @return void
* @access protected
*/
- protected function OnAfterCopyToLive(kEvent &$event)
+ protected function OnAfterCopyToLive(kEvent $event)
{
parent::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(kEvent &$event)
+ protected function OnSave(kEvent $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);
+ $this->Application->HandleEvent(new kEvent('adm:OnRebuildThemes'));
}
}
/**
* Allows to change the theme
*
* @param kEvent $event
*/
- function OnChangeTheme(&$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);
$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(kEvent &$event)
+ protected function SetCustomQuery(kEvent $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/country_states/country_state_eh.php
===================================================================
--- branches/5.2.x/core/units/country_states/country_state_eh.php (revision 15129)
+++ branches/5.2.x/core/units/country_states/country_state_eh.php (revision 15130)
@@ -1,155 +1,155 @@
<?php
/**
* @version $Id$
* @package In-Portal
* @copyright Copyright (C) 1997 - 2010 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 CountryStateEventHandler extends kDBEventHandler {
/**
* Allows to override standard permission mapping
*
* @return void
* @access protected
* @see kEventHandler::$permMapping
*/
protected function mapPermissions()
{
parent::mapPermissions();
$permissions = Array (
'OnGetStatesJSON' => Array ('self' => true),
);
$this->permMapping = array_merge($this->permMapping, $permissions);
}
/**
* Applies edit picker filters
*
* @param kEvent $event
* @return void
* @access protected
* @see kDBEventHandler::OnListBuild()
*/
- protected function SetCustomQuery(kEvent &$event)
+ protected function SetCustomQuery(kEvent $event)
{
parent::SetCustomQuery($event);
$object =& $event->getObject();
/* @var $object kDBList */
if ( ($event->Special == 'selected') || ($event->Special == 'available') ) {
$edit_picker_helper =& $this->Application->recallObject('EditPickerHelper');
/* @var $edit_picker_helper EditPickerHelper */
$edit_picker_helper->applyFilter($event, 'Countries');
// only countries
$object->addFilter('type_filter', '%1$s.Type = ' . DESTINATION_TYPE_COUNTRY);
}
}
/**
* Makes sure, that state country is always specified
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnBeforeItemCreate(kEvent &$event)
+ protected function OnBeforeItemCreate(kEvent $event)
{
parent::OnBeforeItemCreate($event);
$this->_setRequired($event);
}
/**
* Makes sure, that state country is always specified
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnBeforeItemUpdate(kEvent &$event)
+ protected function OnBeforeItemUpdate(kEvent $event)
{
parent::OnBeforeItemUpdate($event);
$this->_setRequired($event);
}
/**
* Makes sure, that state country is always specified
*
* @param kEvent $event
*/
- function _setRequired(&$event)
+ function _setRequired($event)
{
$object =& $event->getObject();
/* @var $object kDBItem */
$field_options = $object->GetFieldOptions('IsoCode');
if ($object->GetDBField('Type') == DESTINATION_TYPE_STATE) {
$object->setRequired('StateCountryId');
$field_options['unique'] = Array ('Type', 'StateCountryId');
}
else {
$object->setRequired('StateCountryId', false);
$field_options['unique'] = Array ('Type');
}
$object->SetFieldOptions('IsoCode', $field_options);
}
/**
* Don't allow to delete countries, that have states
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnBeforeItemDelete(kEvent &$event)
+ protected function OnBeforeItemDelete(kEvent $event)
{
parent::OnBeforeItemDelete($event);
$object =& $event->getObject();
/* @var $object kDBItem */
$cs_helper =& $this->Application->recallObject('CountryStatesHelper');
/* @var $cs_helper kCountryStatesHelper */
if ( $cs_helper->CountryHasStates($object->GetDBField('IsoCode')) ) {
$event->status = kEvent::erFAIL;
return;
}
}
/**
* Returns given country states in JSON format
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnGetStatesJSON(kEvent &$event)
+ protected function OnGetStatesJSON(kEvent $event)
{
$event->status = kEvent::erSTOP;
$cs_helper =& $this->Application->recallObject('CountryStatesHelper');
/* @var $cs_helper kCountryStatesHelper */
$states = $cs_helper->getStates( (string)$this->Application->GetVar('country_iso') );
echo json_encode($states);
}
}
Index: branches/5.2.x/core/units/sections/site_config_eh.php
===================================================================
--- branches/5.2.x/core/units/sections/site_config_eh.php (revision 15129)
+++ branches/5.2.x/core/units/sections/site_config_eh.php (revision 15130)
@@ -1,75 +1,75 @@
<?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 SiteConfigEventHandler extends kEventHandler {
/**
* SiteConfigHelper instance
*
* @var SiteConfigHelper
*/
var $_helper = null;
/**
* [HOOK] Universal hook to modify all configs
*
* @param kEvent $event
*/
- function OnApplySiteConfigChanges(&$event)
+ function OnApplySiteConfigChanges($event)
{
if ( $event->MasterEvent->getEventParam('skip_site_config') ) {
return ;
}
if (!isset($this->_helper)) {
$this->_helper =& $this->Application->recallObject('SiteConfigHelper');
}
$prefix_file = basename( $this->Application->UnitConfigReader->getPrefixFile($event->MasterEvent->Prefix) );
$cut_pos = strrpos($prefix_file, '_config.php');
$prefix_file = substr($prefix_file, 0, $cut_pos) . '_' . $event->MasterEvent->Prefix . '.php';
if (file_exists(SYSTEM_PRESET_PATH . DIRECTORY_SEPARATOR . $prefix_file)) {
if ( $this->Application->getUnitOption($event->MasterEvent->Prefix, 'SiteConfigProcessed') ) {
// don't apply same site config twice during installation
return ;
}
require SYSTEM_PRESET_PATH . DIRECTORY_SEPARATOR . $prefix_file;
}
else {
return ;
}
$change_names = Array (
'remove_sections', 'debug_only_sections', 'remove_buttons',
'hidden_fields', 'virtual_hidden_fields', 'debug_only_fields', 'debug_only_virtual_fields',
'required_fields', 'virtual_required_fields', 'hide_edit_tabs', 'hide_columns'
);
$changes = Array ();
foreach ($change_names as $change_name) {
if (isset($$change_name)) {
$changes[$change_name] = $$change_name;
}
}
// apply changes
$this->_helper->processConfigChanges($event->MasterEvent->Prefix, $changes);
$this->Application->setUnitOption($event->MasterEvent->Prefix, 'SiteConfigProcessed', true);
}
}
\ No newline at end of file
Index: branches/5.2.x/core/units/skins/skin_eh.php
===================================================================
--- branches/5.2.x/core/units/skins/skin_eh.php (revision 15129)
+++ branches/5.2.x/core/units/skins/skin_eh.php (revision 15130)
@@ -1,160 +1,160 @@
<?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 SkinEventHandler extends kDBEventHandler {
/**
* Allows to override standard permission mapping
*
* @return void
* @access protected
* @see kEventHandler::$permMapping
*/
protected function mapPermissions()
{
parent::mapPermissions();
$permissions = Array (
'OnItemBuild' => Array ('self' => true),
);
$this->permMapping = array_merge($this->permMapping, $permissions);
}
/**
* With "primary" special loads primary skin
*
* @param kEvent $event
* @return int
* @access public
*/
- public function getPassedID(kEvent &$event)
+ public function getPassedID(kEvent $event)
{
if ( $event->Special == 'primary' ) {
return Array ('IsPrimary' => 1);
}
return parent::getPassedID($event);
}
/**
* Allows to set selected theme as primary
*
* @param kEvent $event
*/
- function OnSetPrimary(&$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);
}
$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 IsPrimary = 0';
$this->Conn->Query($sql);
$sql = 'UPDATE '.$table_name.'
SET IsPrimary = 1
WHERE '.$id_field.' = '.$id;
$this->Conn->Query($sql);
}
/**
* Don't make cloned skin primary
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnBeforeClone(kEvent &$event)
+ protected function OnBeforeClone(kEvent $event)
{
parent::OnBeforeClone($event);
$object =& $event->getObject();
/* @var $object kDBItem */
$object->SetDBField('IsPrimary', 0);
}
/**
* Re-compile skin, after it's changed (live table only)
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnAfterItemUpdate(kEvent &$event)
+ protected function OnAfterItemUpdate(kEvent $event)
{
parent::OnAfterItemUpdate($event);
$object =& $event->getObject();
/* @var $object kDBItem */
if ( !$object->IsTempTable() ) {
$skin_helper =& $this->Application->recallObject('SkinHelper');
/* @var $skin_helper SkinHelper */
$skin_helper->compile($object);
}
}
/**
* [HOOK] Compile stylesheet file based on theme definitions
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnCompileStylesheet(&$event)
+ protected function OnCompileStylesheet($event)
{
$object =& $event->getObject( Array ('skip_autoload' => true) );
/* @var $object kDBItem */
$object->SwitchToLive();
$ids = $event->MasterEvent->getEventParam('ids');
if ( !is_array($ids) ) {
$ids = explode(',', $ids);
}
if ( !$ids ) {
return ;
}
$skin_helper =& $this->Application->recallObject('SkinHelper');
/* @var $skin_helper SkinHelper */
foreach ($ids as $id) {
$object->Load($id);
$skin_helper->compile($object);
}
}
}
\ No newline at end of file
Index: branches/5.2.x/core/units/promo_blocks/promo_block_eh.php
===================================================================
--- branches/5.2.x/core/units/promo_blocks/promo_block_eh.php (revision 15129)
+++ branches/5.2.x/core/units/promo_blocks/promo_block_eh.php (revision 15130)
@@ -1,349 +1,349 @@
<?php
/**
* @version $Id$
* @package In-Portal
* @copyright Copyright (C) 1997 - 2011 Intechnic. All rights reserved.
* @license GNU/GPL
* In-Portal is Open Source software.
* This means that this software may have been modified pursuant
* the GNU General Public License, and as distributed it includes
* or is derivative of works licensed under the GNU General Public License
* or other free or open source software licenses.
* See http://www.in-portal.org/license for copyright notices and details.
*/
defined('FULL_PATH') or die('restricted access!');
class PromoBlockEventHandler extends kDBEventHandler {
/**
* Define alternative event processing method names
*
* @return void
* @see kEventHandler::$eventMethods
* @access protected
*/
protected function mapEvents()
{
parent::mapEvents();
$events_map = Array (
'OnMassMoveUp' => 'OnChangePriority',
'OnMassMoveDown' => 'OnChangePriority',
);
$this->eventMethods = array_merge($this->eventMethods, $events_map);
}
/**
* Allows to override standard permission mapping
*
* @return void
* @access protected
* @see kEventHandler::$permMapping
*/
protected function mapPermissions()
{
parent::mapPermissions();
$permissions = Array (
'OnItemBuild' => Array ('self' => true),
'OnSetSticky' => Array ('self' => 'view'),
'OnRegisterView' => Array ('self' => true),
'OnFollowLink' => Array ('self' => true),
'OnResetCounters' => Array ('self' => 'add|edit'),
);
$this->permMapping = array_merge($this->permMapping, $permissions);
}
/**
* Sets default value for promo block group
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnPreCreate(kEvent &$event)
+ protected function OnPreCreate(kEvent $event)
{
parent::OnPreCreate($event);
$object =& $event->getObject();
/* @var $object kDBItem */
$promo_block_group =& $this->Application->recallObject('promo-block-group');
/* @var $promo_block_group kDBItem */
$object->SetDBField('PromoBlockGroupId', $promo_block_group->GetID());
}
/**
* Processes OnMassMoveUp, OnMassMoveDown events
*
* @param kEvent $event
*/
- function OnChangePriority(&$event)
+ function OnChangePriority($event)
{
$this->Application->SetVar('priority_prefix', $event->getPrefixSpecial());
$event->CallSubEvent('priority:' . $event->Name);
}
/**
* Apply any custom changes to list's sql query
*
* @param kEvent $event
* @return void
* @access protected
* @see kDBEventHandler::OnListBuild()
*/
- protected function SetCustomQuery(kEvent &$event)
+ protected function SetCustomQuery(kEvent $event)
{
parent::SetCustomQuery($event);
$object =& $event->getObject();
/* @var $object kDBList */
if ( $this->Application->isAdmin ) {
$promo_block_group =& $this->Application->recallObject('promo-block-group');
/* @var $promo_block_group kDBItem */
$object->addFilter('promo_group_filter', '%1$s.PromoBlockGroupId = ' . $promo_block_group->GetID());
return;
}
$group_id = $event->getEventParam('group_id');
if ( !$group_id ) {
$page =& $this->Application->recallObject('st');
/* @var $page CategoriesItem */
$group_id = $page->GetDBField('PromoBlockGroupId');
}
$object->addFilter('status_filter', '%1$s.Status = ' . STATUS_ACTIVE);
$object->addFilter('scheduled_from_filter', '%1$s.ScheduleFromDate IS NULL OR %1$s.ScheduleFromDate <= ' . TIMENOW);
$object->addFilter('scheduled_to_filter', '%1$s.ScheduleToDate IS NULL OR %1$s.ScheduleToDate >= ' . TIMENOW);
$object->addFilter('promo_group_filter', $group_id ? '%1$s.PromoBlockGroupId = ' . $group_id : 'FALSE');
}
/**
* Set's block as sticky
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnSetSticky(kEvent &$event)
+ protected function OnSetSticky(kEvent $event)
{
$object =& $event->getObject( Array('skip_autoload' => true) );
/* @var $object kDBItem */
$ids = $this->StoreSelectedIDs($event);
if ( $ids ) {
$id = array_shift($ids);
$sql = 'UPDATE ' . $object->TableName . '
SET Sticky = 0';
$this->Conn->Query($sql);
$sql = 'UPDATE ' . $object->TableName . '
SET Sticky = 1, Status = ' . STATUS_ACTIVE . '
WHERE BlockId = ' . $id;
$this->Conn->Query($sql);
}
$this->clearSelectedIDs($event);
}
/**
* Set Required fields
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnBeforeItemCreate(kEvent &$event)
+ protected function OnBeforeItemCreate(kEvent $event)
{
parent::OnBeforeItemCreate($event);
$this->_itemChanged($event);
}
/**
* Set Required fields
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnBeforeItemUpdate(kEvent &$event)
+ protected function OnBeforeItemUpdate(kEvent $event)
{
parent::OnBeforeItemUpdate($event);
$this->_itemChanged($event);
}
/**
* Schedule dates
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function _itemChanged(kEvent &$event)
+ protected function _itemChanged(kEvent $event)
{
$object =& $event->getObject();
/* @var $object kDBItem */
$date_from = $object->GetDBField('ScheduleFromDate_date');
$date_to = $object->GetDBField('ScheduleToDate_date');
if ( $date_from && $date_to && $date_from >= $date_to ) {
$object->SetError('ScheduleFromDate_date', 'wrong_date_interval');
}
$object->setRequired('CategoryId', $object->GetDBField('LinkType') == PromoBlockType::INTERNAL);
$object->setRequired('ExternalLink', $object->GetDBField('LinkType') == PromoBlockType::EXTERNAL);
}
/**
* Registers view of the promo block
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnRegisterView(kEvent &$event)
+ protected function OnRegisterView(kEvent $event)
{
$this->_incrementField($event, 'NumberOfViews');
}
/**
* Registers click on the promo block
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnFollowLink(kEvent &$event)
+ protected function OnFollowLink(kEvent $event)
{
$object =& $event->getObject();
/* @var $object kDBItem */
$this->_incrementField($event, 'NumberOfClicks', false);
if ( $object->GetDBField('LinkType') == 1 ) { // Internal
$sql = 'SELECT NamedParentPath
FROM ' . TABLE_PREFIX . 'Categories
WHERE CategoryId = ' . $object->GetDBField('CategoryId');
$event->redirect = $this->Conn->GetOne($sql);
$event->SetRedirectParam('pass', 'm');
}
else {
$ext_url = $object->GetDBField('ExternalLink');
$event->redirect = 'external:' . (preg_match('/^(http|ftp):\\/\\/.*/', $ext_url) ? $ext_url : $this->Application->BaseURL() . $ext_url);
}
}
/**
* Increment given promo block counters
*
* @param kEvent $event
* @param string $field
* @param bool $is_ajax
* @return void
* @access protected
*/
- protected function _incrementField(kEvent &$event, $field, $is_ajax = true)
+ protected function _incrementField(kEvent $event, $field, $is_ajax = true)
{
if ( $is_ajax ) {
$event->status = kEvent::erSTOP;
if ( $this->Application->GetVar('ajax') != 'yes' ) {
return ;
}
}
$object =& $event->getObject();
/* @var $object kDBItem */
if ( !$object->isLoaded() ) {
echo 'FAILED';
return ;
}
// don't use kDBItem::Update to support concurrent view updates from different visitors
$sql = 'UPDATE ' . $object->TableName . '
SET ' . $field . ' = ' . $field . ' + 1
WHERE ' . $object->IDField . ' = ' . $object->GetID();
$this->Conn->Query($sql);
echo 'OK';
}
/**
* Resets promo block counters
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnResetCounters(kEvent &$event)
+ protected function OnResetCounters(kEvent $event)
{
$object =& $event->getObject( Array ('skip_autoload' => true) );
/* @var $object kDBItem */
$ids = $this->StoreSelectedIDs($event);
foreach ($ids as $id) {
$object->Load($id);
$object->SetDBField('NumberOfViews', 0);
$object->SetDBField('NumberOfClicks', 0);
$object->Update();
}
$this->clearSelectedIDs($event);
}
/**
* Occurs, when config was parsed, allows to change config data dynamically
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnAfterConfigRead(kEvent &$event)
+ protected function OnAfterConfigRead(kEvent $event)
{
parent::OnAfterConfigRead($event);
$category_helper =& $this->Application->recallObject('CategoryHelper');
/* @var $category_helper CategoryHelper */
$fields = $this->Application->getUnitOption($event->Prefix, 'Fields');
$fields['CategoryId']['options'] = $category_helper->getStructureTreeAsOptions();
// images multilang fields
$a_image = Array(
'type' => 'string', 'max_len' => 255,
'formatter' => 'kUploadFormatter', 'upload_dir' => IMAGES_PATH . 'promo_blocks/',
'multiple' => 1, 'thumb_format' => 'resize:100x100',
'file_types' => '*.jpg;*.gif;*.png', 'files_description' => '!la_hint_ImageFiles!',
'required' => 1, 'not_null' => 1, 'default' => '',
);
// get active languages
$sql = 'SELECT LanguageId
FROM ' . TABLE_PREFIX . 'Languages';
$languages = $this->Conn->GetCol($sql);
foreach ($languages AS $lang_id) {
$fields['l' . $lang_id . '_Image'] = $a_image;
}
$this->Application->setUnitOption($event->Prefix, 'Fields', $fields);
}
}
Index: branches/5.2.x/core/units/translator/translator_event_handler.php
===================================================================
--- branches/5.2.x/core/units/translator/translator_event_handler.php (revision 15129)
+++ branches/5.2.x/core/units/translator/translator_event_handler.php (revision 15130)
@@ -1,181 +1,181 @@
<?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 standard permission mapping
*
* @return void
* @access protected
* @see kEventHandler::$permMapping
*/
protected 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(kEvent &$event)
+ public function CheckPermission(kEvent $event)
{
list($prefix, ) = $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)
+ 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)
+ 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)
+ 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(kEvent &$event)
+ protected function OnPreSave(kEvent $event)
{
$translator =& $event->getObject();
/* @var $translator kDBItem */
$field_values = $this->getSubmittedFields($event);
$translator->SetFieldsFromHash($field_values, $this->getRequestProtectedFields($field_values));
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)
+ 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/statistics/statistics_event_handler.php
===================================================================
--- branches/5.2.x/core/units/statistics/statistics_event_handler.php (revision 15129)
+++ branches/5.2.x/core/units/statistics/statistics_event_handler.php (revision 15130)
@@ -1,46 +1,46 @@
<?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 StatisticsEventHandler extends kDBEventHandler {
/**
* Allows to show statistics only of requested type
*
* @param kEvent $event
* @return void
* @access protected
* @see kDBEventHandler::OnListBuild()
*/
- protected function SetCustomQuery(kEvent &$event)
+ protected function SetCustomQuery(kEvent $event)
{
parent::SetCustomQuery($event);
$object =& $event->getObject();
/* @var $object kDBList */
if ( $event->Special == 'summary' ) {
$object->addFilter('summary_filter', '%1$s.AdminSummary = 1');
}
$module_list = '';
foreach ($this->Application->ModuleInfo as $module_name => $module_info) {
$module_list .= $this->Conn->qstr($module_name) . ',';
}
$module_list = substr($module_list, 0, -1);
$object->addFilter('status_filter', '%1$s.Module IN (' . $module_list . ')');
}
}
\ No newline at end of file
Index: branches/5.2.x/core/units/related_searches/related_searches_event_handler.php
===================================================================
--- branches/5.2.x/core/units/related_searches/related_searches_event_handler.php (revision 15129)
+++ branches/5.2.x/core/units/related_searches/related_searches_event_handler.php (revision 15130)
@@ -1,39 +1,39 @@
<?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 RelatedSearchEventHandler extends kDBEventHandler
{
/**
* Prepares new kDBItem object
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnNew(kEvent &$event)
+ protected function OnNew(kEvent $event)
{
parent::OnNew($event);
$object =& $event->getObject();
/* @var $object kDBItem */
$table_info = $object->getLinkedInfo();
$source_itemtype = $this->Application->getUnitOption($table_info['ParentPrefix'], 'ItemType');
$object->SetDBField('ItemType', $source_itemtype);
}
}
\ 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 15129)
+++ branches/5.2.x/core/units/mailing_lists/mailing_list_eh.php (revision 15130)
@@ -1,340 +1,340 @@
<?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 standard permission mapping
*
* @return void
* @access protected
* @see kEventHandler::$permMapping
*/
protected 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
* @return void
* @access protected
*/
- protected function OnNew(kEvent &$event)
+ protected function OnNew(kEvent $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(kEvent &$event, $type)
+ protected function customProcessing(kEvent $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 related mails in email queue
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnAfterItemDelete(kEvent &$event)
+ protected function OnAfterItemDelete(kEvent $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)
+ 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(kEvent &$event)
+ protected function OnBeforeItemCreate(kEvent $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
* @return void
* @access protected
*/
- protected function OnAfterItemUpdate(kEvent &$event)
+ protected function OnAfterItemUpdate(kEvent $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)
+ 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)
+ 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)
+ 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/custom_fields/custom_fields_event_handler.php
===================================================================
--- branches/5.2.x/core/units/custom_fields/custom_fields_event_handler.php (revision 15129)
+++ branches/5.2.x/core/units/custom_fields/custom_fields_event_handler.php (revision 15130)
@@ -1,352 +1,352 @@
<?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 CustomFieldsEventHandler extends kDBEventHandler {
/**
* Changes permission section to one from REQUEST, not from config
*
* @param kEvent $event
* @return bool
* @access public
*/
- public function CheckPermission(kEvent &$event)
+ public function CheckPermission(kEvent $event)
{
$sql = 'SELECT Prefix
FROM '.TABLE_PREFIX.'ItemTypes
WHERE ItemType = '.$this->Conn->qstr( $this->Application->GetVar('cf_type') );
$main_prefix = $this->Conn->GetOne($sql);
$section = $this->Application->getUnitOption($main_prefix.'.custom', 'PermSection');
$event->setEventParam('PermSection', $section);
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(kEvent &$event)
+ protected function SetCustomQuery(kEvent $event)
{
parent::SetCustomQuery($event);
$object =& $event->getObject();
/* @var $object kDBList */
$item_type = $this->Application->GetVar('cf_type');
if ( !$item_type ) {
$prefix = $event->getEventParam('SourcePrefix');
$item_type = $this->Application->getUnitOption($prefix, 'ItemType');
}
if ( $event->Special == 'general' ) {
$object->addFilter('generaltab_filter', '%1$s.OnGeneralTab = 1');
}
if ( $item_type ) {
$hidden_fields = $this->Conn->qstrArray($this->_getHiddenFields($event));
if ( $hidden_fields ) {
$object->addFilter('hidden_filter', '%1$s.FieldName NOT IN (' . implode(',', $hidden_fields) . ')');
}
$object->addFilter('itemtype_filter', '%1$s.Type = ' . $item_type);
}
if ( !($this->Application->isDebugMode() && $this->Application->isAdminUser) ) {
$object->addFilter('user_filter', '%1$s.IsSystem = 0');
}
}
/**
* Returns prefix, that custom fields are printed for
*
* @param kEvent $event
* @return string
*/
- function _getSourcePrefix(&$event)
+ function _getSourcePrefix($event)
{
$prefix = $event->getEventParam('SourcePrefix');
if (!$prefix) {
$sql = 'SELECT Prefix
FROM ' . TABLE_PREFIX . 'ItemTypes
WHERE ItemType = ' . $this->Conn->qstr( $this->Application->GetVar('cf_type') );
$prefix = $this->Conn->GetOne($sql);
}
return $prefix;
}
/**
* Get custom fields, that should no be shown anywhere
*
* @param kEvent $event
* @return Array
* @access protected
*/
- protected function _getHiddenFields(&$event)
+ protected function _getHiddenFields($event)
{
$prefix = $this->_getSourcePrefix($event);
$hidden_fields = Array ();
$virtual_fields = $this->Application->getUnitOption($prefix, 'VirtualFields', Array ());
$custom_fields = $this->Application->getUnitOption($prefix, 'CustomFields', Array ());
/* @var $custom_fields Array */
foreach ($custom_fields as $custom_field) {
$check_field = 'cust_' . $custom_field;
$show_mode = array_key_exists('show_mode', $virtual_fields[$check_field]) ? $virtual_fields[$check_field]['show_mode'] : true;
if ( ($show_mode === false) || (($show_mode === smDEBUG) && !(defined('DEBUG_MODE') && DEBUG_MODE)) ) {
$hidden_fields[] = $custom_field;
}
}
return $hidden_fields;
}
/**
* Prevents from duplicate item creation
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnBeforeItemCreate(kEvent &$event)
+ protected function OnBeforeItemCreate(kEvent $event)
{
parent::OnBeforeItemCreate($event);
$object =& $event->getObject();
/* @var $object kDBItem */
$sql = 'SELECT COUNT(*)
FROM ' . $this->Application->getUnitOption($event->Prefix, 'TableName') . '
WHERE FieldName = ' . $this->Conn->qstr($object->GetDBField('FieldName')) . ' AND Type = ' . $object->GetDBField('Type');
$found = $this->Conn->GetOne($sql);
if ( $found ) {
$event->status = kEvent::erFAIL;
$object->SetError('FieldName', 'duplicate', 'la_error_CustomExists');
}
}
/**
* Occurs after deleting item, id of deleted item
* is stored as 'id' param of event
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnAfterItemDelete(kEvent &$event)
+ protected function OnAfterItemDelete(kEvent $event)
{
parent::OnAfterItemDelete($event);
$object =& $event->getObject();
/* @var $object kDBItem */
$main_prefix = $this->getPrefixByItemType($object->GetDBField('Type'));
$ml_helper =& $this->Application->recallObject('kMultiLanguageHelper');
/* @var $ml_helper kMultiLanguageHelper */
// call main item config to clone cdata table
$this->Application->getUnitOption($main_prefix, 'TableName');
$ml_helper->deleteField($main_prefix . '-cdata', $event->getEventParam('id'));
}
/**
* Get config prefix based on item type
*
* @param int $item_type
* @return string
* @access protected
*/
protected function getPrefixByItemType($item_type)
{
$sql = 'SELECT Prefix
FROM ' . TABLE_PREFIX . 'ItemTypes
WHERE ItemType = ' . $item_type;
return $this->Conn->GetOne($sql);
}
/**
* Creates new database columns, once custom field is successfully created
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnSaveCustomField(&$event)
+ protected function OnSaveCustomField($event)
{
if ( $event->MasterEvent->status != kEvent::erSUCCESS ) {
return ;
}
$object =& $event->getObject();
/* @var $object kDBItem */
$main_prefix = $this->getPrefixByItemType($object->GetDBField('Type'));
$ml_helper =& $this->Application->recallObject('kMultiLanguageHelper');
/* @var $ml_helper kMultiLanguageHelper */
// call main item config to clone cdata table
define('CUSTOM_FIELD_ADDED', 1); // used in cdata::scanCustomFields method
$this->Application->getUnitOption($main_prefix, 'TableName');
$ml_helper->createFields($main_prefix . '-cdata');
}
/**
* 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(kEvent &$event)
+ protected function OnMassDelete(kEvent $event)
{
parent::OnMassDelete($event);
$event->SetRedirectParam('opener', 's');
}
/**
* 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(kEvent &$event)
+ protected function OnPreCreate(kEvent $event)
{
parent::OnPreCreate($event);
$object =& $event->getObject();
/* @var $object kDBItem */
$object->SetDBField('Type', $this->Application->GetVar('cf_type'));
}
/**
* Prepares ValueList field's value as xml for editing
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnAfterItemLoad(kEvent &$event)
+ protected function OnAfterItemLoad(kEvent $event)
{
parent::OnAfterItemLoad($event);
$object =& $event->getObject();
/* @var $object kDBItem */
if ( !in_array($object->GetDBField('ElementType'), $this->_getMultiElementTypes()) ) {
return ;
}
$custom_field_helper =& $this->Application->recallObject('InpCustomFieldsHelper');
/* @var $custom_field_helper InpCustomFieldsHelper */
$options = $custom_field_helper->GetValuesHash($object->GetDBField('ValueList'), VALUE_LIST_SEPARATOR, false);
$records = Array ();
$option_key = key($options);
if ( $option_key === '' || $option_key == 0 ) {
// remove 1st empty option, and add it later, when options will be saved, but allow string option keys
unset($options[$option_key]); // keep index, don't use array_unshift!
}
foreach ($options as $option_key => $option_title) {
$records[] = Array ('OptionKey' => $option_key, 'OptionTitle' => $option_title);
}
$minput_helper =& $this->Application->recallObject('MInputHelper');
/* @var $minput_helper MInputHelper */
$xml = $minput_helper->prepareMInputXML($records, Array ('OptionKey', 'OptionTitle'));
$object->SetDBField('Options', $xml);
}
/**
* Returns custom field element types, that will use minput control
*
* @return Array
* @access protected
*/
protected function _getMultiElementTypes()
{
return Array ('select', 'multiselect', 'radio');
}
/**
* Saves minput content to ValueList field
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnBeforeItemUpdate(kEvent &$event)
+ protected function OnBeforeItemUpdate(kEvent $event)
{
parent::OnBeforeItemUpdate($event);
$object =& $event->getObject();
/* @var $object kDBItem */
if ( !in_array($object->GetDBField('ElementType'), $this->_getMultiElementTypes()) ) {
return ;
}
$minput_helper =& $this->Application->recallObject('MInputHelper');
/* @var $minput_helper MInputHelper */
$ret = $object->GetDBField('ElementType') == 'select' ? Array ('' => '=+') : Array ();
$records = $minput_helper->parseMInputXML($object->GetDBField('Options'));
if ( $object->GetDBField('SortValues') ) {
usort($records, Array (&$this, '_sortValues'));
ksort($records);
}
foreach ($records as $record) {
if ( substr($record['OptionKey'], 0, 3) == 'SQL' ) {
$ret[] = $record['OptionTitle'];
}
else {
$ret[] = $record['OptionKey'] . '=' . $record['OptionTitle'];
}
}
$object->SetDBField('ValueList', implode(VALUE_LIST_SEPARATOR, $ret));
}
function _sortValues($record_a, $record_b)
{
return strcasecmp($record_a['OptionTitle'], $record_b['OptionTitle']);
}
}
\ No newline at end of file
Index: branches/5.2.x/core/units/users/users_event_handler.php
===================================================================
--- branches/5.2.x/core/units/users/users_event_handler.php (revision 15129)
+++ branches/5.2.x/core/units/users/users_event_handler.php (revision 15130)
@@ -1,1948 +1,1948 @@
<?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 UsersEventHandler extends kDBEventHandler
{
/**
* Allows to override standard permission mapping
*
* @return void
* @access protected
* @see kEventHandler::$permMapping
*/
protected function mapPermissions()
{
parent::mapPermissions();
$permissions = Array (
// admin
'OnSetPersistantVariable' => Array('self' => 'view'), // because setting to logged in user only
'OnUpdateRootPassword' => Array('self' => true),
'OnUpdatePassword' => Array('self' => true),
'OnSaveSelected' => Array ('self' => 'view'),
'OnGeneratePassword' => Array ('self' => 'view'),
// front
'OnRefreshForm' => Array('self' => true),
'OnForgotPassword' => Array('self' => true),
'OnSubscribeQuery' => Array('self' => true),
'OnSubscribeUser' => Array('self' => true),
'OnRecommend' => Array('self' => true),
'OnItemBuild' => Array('self' => true),
'OnMassResetSettings' => Array('self' => 'edit'),
'OnMassCloneUsers' => Array('self' => 'add'),
);
$this->permMapping = array_merge($this->permMapping, $permissions);
}
/**
* Returns fields, that are not allowed to be changed from request
*
* @param Array $hash
* @return Array
* @access protected
*/
protected function getRequestProtectedFields($hash)
{
$fields = parent::getRequestProtectedFields($hash);
$fields = array_merge($fields, Array ('PrevEmails', 'ResourceId', 'IPAddress', 'IsBanned', 'PwResetConfirm', 'PwRequestTime', 'OldStyleLogin'));
if ( !$this->Application->isAdmin ) {
$fields = array_merge($fields, Array ('UserType', 'Status', 'EmailVerified', 'IsBanned'));
}
return $fields;
}
/**
* Builds item (loads if needed)
*
* Pattern: Prototype Manager
*
* @param kEvent $event
* @access protected
*/
- protected function OnItemBuild(kEvent &$event)
+ protected function OnItemBuild(kEvent $event)
{
parent::OnItemBuild($event);
$object =& $event->getObject();
/* @var $object kDBItem */
if ( $event->Special == 'forgot' || $object->getFormName() == 'registration' ) {
$this->_makePasswordRequired($event);
}
}
/**
* Shows only admins when required
*
* @param kEvent $event
* @return void
* @access protected
* @see kDBEventHandler::OnListBuild()
*/
- protected function SetCustomQuery(kEvent &$event)
+ protected function SetCustomQuery(kEvent $event)
{
parent::SetCustomQuery($event);
$object =& $event->getObject();
/* @var $object kDBList */
if ( $event->Special == 'regular' ) {
$object->addFilter('primary_filter', '%1$s.UserType = ' . UserType::USER);
}
if ( $event->Special == 'admins' ) {
$object->addFilter('primary_filter', '%1$s.UserType = ' . UserType::ADMIN);
}
if ( !$this->Application->isAdminUser ) {
$object->addFilter('status_filter', '%1$s.Status = ' . STATUS_ACTIVE);
}
if ( $event->Special == 'online' ) {
$object->addFilter('online_users_filter', 's.PortalUserId IS NOT NULL');
}
if ( $event->Special == 'group' ) {
$group_id = $this->Application->GetVar('g_id');
if ( $group_id !== false ) {
// show only users, that user doesn't belong to current group
$sql = 'SELECT PortalUserId
FROM ' . $this->Application->GetTempName(TABLE_PREFIX . 'UserGroupRelations', 'prefix:g') . '
WHERE GroupId = ' . (int)$group_id;
$user_ids = $this->Conn->GetCol($sql);
if ( $user_ids ) {
$object->addFilter('already_member_filter', '%1$s.PortalUserId NOT IN (' . implode(',', $user_ids) . ')');
}
}
}
}
/**
* Checks user permission to execute given $event
*
* @param kEvent $event
* @return bool
* @access public
*/
- public function CheckPermission(kEvent &$event)
+ public function CheckPermission(kEvent $event)
{
if ( $event->Name == 'OnLogin' || $event->Name == 'OnLoginAjax' || $event->Name == 'OnLogout' ) {
// permission is checked in OnLogin event directly
return true;
}
if ( $event->Name == 'OnResetRootPassword' ) {
return defined('DBG_RESET_ROOT') && DBG_RESET_ROOT;
}
if ( $event->Name == 'OnLoginAs' ) {
$admin_session =& $this->Application->recallObject('Session.admin');
/* @var $admin_session Session */
return $admin_session->LoggedIn();
}
if ( !$this->Application->isAdminUser ) {
$user_id = $this->Application->RecallVar('user_id');
$items_info = $this->Application->GetVar($event->getPrefixSpecial(true));
if ( ($event->Name == 'OnCreate' || $event->Name == 'OnRegisterAjax') && $user_id == USER_GUEST ) {
// "Guest" can create new users
return true;
}
if ( $event->Name == 'OnUpdate' && $user_id > 0 ) {
$user_dummy =& $this->Application->recallObject($event->Prefix . '.-item', null, Array ('skip_autoload' => true));
/* @var $user_dummy UsersItem */
foreach ($items_info as $id => $field_values) {
if ( $id != $user_id ) {
// registered users can update their record only
return false;
}
$user_dummy->Load($id);
$status_field = array_shift($this->Application->getUnitOption($event->Prefix, 'StatusField'));
if ( $user_dummy->GetDBField($status_field) != STATUS_ACTIVE ) {
// not active user is not allowed to update his record (he could not activate himself manually)
return false;
}
if ( isset($field_values[$status_field]) && $user_dummy->GetDBField($status_field) != $field_values[$status_field] ) {
// user can't change status by himself
return false;
}
}
return true;
}
if ( $event->Name == 'OnResetLostPassword' && $event->Special == 'forgot' && $user_id == USER_GUEST ) {
// non-logged in users can reset their password, when reset code is valid
return is_numeric($this->getPassedID($event));
}
if ( $event->Name == 'OnUpdate' && $user_id <= 0 ) {
// guests are not allowed to update their record, because they don't have it :)
return false;
}
}
return parent::CheckPermission($event);
}
/**
* Handles session expiration (redirects to valid template)
*
* @param kEvent $event
*/
- function OnSessionExpire(&$event)
+ function OnSessionExpire($event)
{
$this->Application->resetCounters('UserSessions');
// place 2 of 2 (also in kHTTPQuery::getRedirectParams)
$admin_url_params = Array (
'm_cat_id' => 0, // category means nothing on admin login screen
'm_wid' => '', // remove wid, otherwise parent window may add wid to its name breaking all the frameset (for <a> targets)
'pass' => 'm', // don't pass any other (except "m") prefixes to admin session expiration template
'expired' => 1, // expiration mark to show special error on login screen
'no_pass_through' => 1, // this way kApplication::HREF won't add them again
);
if ($this->Application->isAdmin) {
$this->Application->Redirect('index', $admin_url_params, '', 'index.php');
}
if ($this->Application->GetVar('admin') == 1) {
// Front-End showed in admin's right frame
$session_admin =& $this->Application->recallObject('Session.admin');
/* @var $session_admin Session */
if (!$session_admin->LoggedIn()) {
// front-end session created from admin session & both expired
$this->Application->DeleteVar('admin');
$this->Application->Redirect('index', $admin_url_params, '', 'admin/index.php');
}
}
// Front-End session expiration
$get = $this->Application->HttpQuery->getRedirectParams();
$t = $this->Application->GetVar('t');
$get['js_redirect'] = $this->Application->ConfigValue('UseJSRedirect');
$this->Application->Redirect($t ? $t : 'index', $get);
}
/**
* [SCHEDULED TASK] Deletes expired sessions
*
* @param kEvent $event
*/
- function OnDeleteExpiredSessions(&$event)
+ function OnDeleteExpiredSessions($event)
{
if (defined('IS_INSTALL') && IS_INSTALL) {
return ;
}
$this->Application->Session->DeleteExpired();
}
/**
* Checks user data and logs it in if allowed
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnLogin(&$event)
+ protected function OnLogin($event)
{
$object =& $event->getObject( Array ('form_name' => 'login') );
/* @var $object kDBItem */
$field_values = $this->getSubmittedFields($event);
$object->SetFieldsFromHash($field_values, $this->getRequestProtectedFields($field_values));
$username = $object->GetDBField('UserLogin');
$password = $object->GetDBField('UserPassword');
$remember_login = $object->GetDBField('UserRememberLogin') == 1;
$user_helper =& $this->Application->recallObject('UserHelper');
/* @var $user_helper UserHelper */
$user_helper->event =& $event;
$result = $user_helper->loginUser($username, $password, false, $remember_login);
if ($result != LoginResult::OK) {
$event->status = kEvent::erFAIL;
$object->SetError('UserLogin', $result == LoginResult::NO_PERMISSION ? 'no_permission' : 'invalid_password');
}
if ( is_object($event->MasterEvent) && ($event->MasterEvent->Name == 'OnLoginAjax') ) {
// used to insert just logged-in user e-mail on "One Step Checkout" form in "Modern Store" theme
$user =& $user_helper->getUserObject();
$event->SetRedirectParam('user_email', $user->GetDBField('Email'));
}
}
/**
* Performs user login from ajax request
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnLoginAjax(&$event)
+ protected function OnLoginAjax($event)
{
$ajax_form_helper =& $this->Application->recallObject('AjaxFormHelper');
/* @var $ajax_form_helper AjaxFormHelper */
$ajax_form_helper->transitEvent($event, 'OnLogin'); //, Array ('do_refresh' => 1));
}
/**
* [HOOK] Auto-Logins Front-End user when "Remember Login" cookie is found
*
* @param kEvent $event
*/
- function OnAutoLoginUser(&$event)
+ function OnAutoLoginUser($event)
{
$remember_login_cookie = $this->Application->GetVar('remember_login');
if (!$remember_login_cookie || $this->Application->isAdmin || $this->Application->LoggedIn()) {
return ;
}
$user_helper =& $this->Application->recallObject('UserHelper');
/* @var $user_helper UserHelper */
$user_helper->loginUser('', '', false, false, $remember_login_cookie);
}
/**
* Called when user logs in using old in-portal
*
* @param kEvent $event
*/
- function OnInpLogin(&$event)
+ function OnInpLogin($event)
{
$sync_manager =& $this->Application->recallObject('UsersSyncronizeManager', null, Array(), Array ('InPortalSyncronize'));
/* @var $sync_manager UsersSyncronizeManager */
$sync_manager->performAction('LoginUser', $event->getEventParam('user'), $event->getEventParam('pass') );
if ($event->redirect && is_string($event->redirect)) {
// some real template specified instead of true
$this->Application->Redirect($event->redirect, $event->getRedirectParams());
}
}
/**
* Called when user logs in using old in-portal
*
* @param kEvent $event
*/
- function OnInpLogout(&$event)
+ function OnInpLogout($event)
{
$sync_manager =& $this->Application->recallObject('UsersSyncronizeManager', null, Array(), Array ('InPortalSyncronize'));
/* @var $sync_manager UsersSyncronizeManager */
$sync_manager->performAction('LogoutUser');
}
/**
* Performs user logout
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnLogout(&$event)
+ protected function OnLogout($event)
{
$user_helper =& $this->Application->recallObject('UserHelper');
/* @var $user_helper UserHelper */
$user_helper->event =& $event;
$user_helper->logoutUser();
}
/**
* Redirects user after successful registration to confirmation template (on Front only)
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnAfterItemCreate(kEvent &$event)
+ protected function OnAfterItemCreate(kEvent $event)
{
parent::OnAfterItemCreate($event);
$this->afterItemChanged($event);
$this->assignToPrimaryGroup($event);
}
/**
* Performs user registration
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnCreate(kEvent &$event)
+ protected function OnCreate(kEvent $event)
{
if ( $this->Application->isAdmin ) {
parent::OnCreate($event);
return ;
}
$object =& $event->getObject( Array('form_name' => 'registration') );
/* @var $object UsersItem */
$field_values = $this->getSubmittedFields($event);
$user_email = getArrayValue($field_values, 'Email');
$subscriber_id = $user_email ? $this->getSubscriberByEmail($user_email) : false;
if ( $subscriber_id ) {
// update existing subscriber
$object->Load($subscriber_id);
$object->SetDBField('PrimaryGroupId', $this->Application->ConfigValue('User_NewGroup'));
$this->Application->SetVar($event->getPrefixSpecial(true), Array ($object->GetID() => $field_values));
}
$object->SetFieldsFromHash($field_values, $this->getRequestProtectedFields($field_values));
$status = $object->isLoaded() ? $object->Update() : $object->Create();
if ( !$status ) {
$event->status = kEvent::erFAIL;
$event->redirect = false;
$object->setID( (int)$object->GetID() );
}
$this->setNextTemplate($event, true);
if ( ($event->status == kEvent::erSUCCESS) && $event->redirect ) {
$this->assignToPrimaryGroup($event);
$object->SendEmailEvents();
$this->autoLoginUser($event);
}
}
/**
* Processes user registration from ajax request
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnRegisterAjax(kEvent &$event)
+ protected function OnRegisterAjax(kEvent $event)
{
$ajax_form_helper =& $this->Application->recallObject('AjaxFormHelper');
/* @var $ajax_form_helper AjaxFormHelper */
$ajax_form_helper->transitEvent($event, 'OnCreate', Array ('do_refresh' => 1));
}
/**
* Returns subscribed user ID by given e-mail address
*
* @param string $email
* @return int|bool
* @access protected
*/
protected function getSubscriberByEmail($email)
{
$verify_user =& $this->Application->recallObject('u.verify', null, Array ('skip_autoload' => true));
/* @var $verify_user UsersItem */
$verify_user->Load($email, 'Email');
return $verify_user->isLoaded() && $verify_user->isSubscriberOnly() ? $verify_user->GetID() : false;
}
/**
* Login user if possible, if not then redirect to corresponding template
*
* @param kEvent $event
*/
- function autoLoginUser(&$event)
+ function autoLoginUser($event)
{
$object =& $event->getObject();
/* @var $object UsersItem */
if ( $object->GetDBField('Status') == STATUS_ACTIVE ) {
$user_helper =& $this->Application->recallObject('UserHelper');
/* @var $user_helper UserHelper */
$user =& $user_helper->getUserObject();
$user->Load($object->GetID());
if ( $user_helper->checkLoginPermission() ) {
$user_helper->loginUserById( $user->GetID() );
}
}
}
/**
* Set's new unique resource id to user
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnBeforeItemCreate(kEvent &$event)
+ protected function OnBeforeItemCreate(kEvent $event)
{
parent::OnBeforeItemCreate($event);
$this->beforeItemChanged($event);
$cs_helper =& $this->Application->recallObject('CountryStatesHelper');
/* @var $cs_helper kCountryStatesHelper */
$object =& $event->getObject();
/* @var $object UsersItem */
if ( !$object->isSubscriberOnly() ) {
// don't check state-to-country relations for subscribers
$cs_helper->CheckStateField($event, 'State', 'Country');
}
if ( $object->getFormName() != 'login' ) {
$this->_makePasswordRequired($event);
}
$cs_helper->PopulateStates($event, 'State', 'Country');
$this->setUserGroup($object);
$user_helper =& $this->Application->recallObject('UserHelper');
/* @var $user_helper UserHelper */
if ( !$user_helper->checkBanRules($object) ) {
$object->SetError('Username', 'banned');
}
$object->SetDBField('IPAddress', $_SERVER['REMOTE_ADDR']);
if ( !$this->Application->isAdmin ) {
$object->SetDBField('FrontLanguage', $this->Application->GetVar('m_lang'));
}
}
/**
* Sets primary group of the user
*
* @param kDBItem $object
*/
protected function setUserGroup(&$object)
{
if ($object->Special == 'subscriber') {
$object->SetDBField('PrimaryGroupId', $this->Application->ConfigValue('User_SubscriberGroup'));
return ;
}
// set primary group to user
if ( !$this->Application->isAdminUser ) {
$group_id = $object->GetDBField('PrimaryGroupId');
if ($group_id) {
// check, that group is allowed for Front-End
$sql = 'SELECT GroupId
FROM ' . TABLE_PREFIX . 'UserGroups
WHERE GroupId = ' . (int)$group_id . ' AND FrontRegistration = 1';
$group_id = $this->Conn->GetOne($sql);
}
if (!$group_id) {
// when group not selected OR not allowed -> use default group
$object->SetDBField('PrimaryGroupId', $this->Application->ConfigValue('User_NewGroup'));
}
}
}
/**
* Assigns a user to it's primary group
*
* @param kEvent $event
*/
- protected function assignToPrimaryGroup(&$event)
+ protected function assignToPrimaryGroup($event)
{
$object =& $event->getObject();
/* @var $object kDBItem */
$primary_group_id = $object->GetDBField('PrimaryGroupId');
if ($primary_group_id) {
$ug_table = TABLE_PREFIX . 'UserGroupRelations';
if ( $object->IsTempTable() ) {
$ug_table = $this->Application->GetTempName($ug_table, 'prefix:' . $event->Prefix);
}
$fields_hash = Array (
'PortalUserId' => $object->GetID(),
'GroupId' => $primary_group_id,
);
$this->Conn->doInsert($fields_hash, $ug_table, 'REPLACE');
}
}
/**
* Set's new unique resource id to user
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnAfterItemValidate(kEvent &$event)
+ protected function OnAfterItemValidate(kEvent $event)
{
$object =& $event->getObject();
/* @var $object kDBItem */
$resource_id = $object->GetDBField('ResourceId');
if ( !$resource_id ) {
$object->SetDBField('ResourceId', $this->Application->NextResourceId());
}
}
/**
* Enter description here...
*
* @param kEvent $event
*/
- function OnRecommend(&$event)
+ function OnRecommend($event)
{
$object =& $event->getObject( Array ('form_name' => 'recommend') );
/* @var $object kDBItem */
$field_values = $this->getSubmittedFields($event);
$object->SetFieldsFromHash($field_values, $this->getRequestProtectedFields($field_values));
if ( !$object->ValidateField('RecommendEmail') ) {
$event->status = kEvent::erFAIL;
return ;
}
$send_params = Array (
'to_email' => $object->GetDBField('RecommendEmail'),
'to_name' => $object->GetDBField('RecommendEmail'),
);
$user_id = $this->Application->RecallVar('user_id');
$email_event =& $this->Application->EmailEventUser('USER.SUGGEST', $user_id, $send_params);
$email_event =& $this->Application->EmailEventAdmin('USER.SUGGEST');
if ( $email_event->status == kEvent::erSUCCESS ) {
$event->SetRedirectParam('pass', 'all');
$event->redirect = $this->Application->GetVar('template_success');
}
else {
$event->status = kEvent::erFAIL;
$object->SetError('RecommendEmail', 'send_error');
}
}
/**
* Saves address changes and mades no redirect
*
* @param kEvent $event
*/
- function OnUpdateAddress(&$event)
+ function OnUpdateAddress($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 ) {
$object->Load($id);
}
$object->SetFieldsFromHash($field_values, $this->getRequestProtectedFields($field_values));
$object->setID($id);
$object->Validate();
}
$cs_helper =& $this->Application->recallObject('CountryStatesHelper');
/* @var $cs_helper kCountryStatesHelper */
$cs_helper->PopulateStates($event, 'State', 'Country');
$event->redirect = false;
}
/**
* Validate subscriber's email & store it to session -> redirect to confirmation template
*
* @param kEvent $event
*/
- function OnSubscribeQuery(&$event)
+ function OnSubscribeQuery($event)
{
$object =& $event->getObject( Array ('form_name' => 'subscription') );
/* @var $object UsersItem */
$field_values = $this->getSubmittedFields($event);
$object->SetFieldsFromHash($field_values, $this->getRequestProtectedFields($field_values));
if ( !$object->ValidateField('SubscriberEmail') ) {
$event->status = kEvent::erFAIL;
return ;
}
$user_email = $object->GetDBField('SubscriberEmail');
$object->Load($user_email, 'Email');
$event->SetRedirectParam('subscriber_email', $user_email);
if ( $object->isLoaded() && $object->isSubscribed() ) {
$event->redirect = $this->Application->GetVar('unsubscribe_template');
}
else {
$event->redirect = $this->Application->GetVar('subscribe_template');
}
$event->SetRedirectParam('pass', 'm');
}
/**
* Subscribe/Unsubscribe user based on email stored in previous step
*
* @param kEvent $event
*/
- function OnSubscribeUser(&$event)
+ function OnSubscribeUser($event)
{
$object =& $event->getObject( Array ('form_name' => 'subscription') );
/* @var $object UsersItem */
$user_email = $this->Application->GetVar('subscriber_email');
$object->SetDBField('SubscriberEmail', $user_email);
if ( !$object->ValidateField('SubscriberEmail') ) {
$event->status = kEvent::erFAIL;
return ;
}
$this->RemoveRequiredFields($object);
$object->Load($user_email, 'Email');
if ( $object->isLoaded() ) {
if ( $object->isSubscribed() ) {
if ( $event->getEventParam('no_unsubscribe') ) {
// for customization code from FormsEventHandler
return ;
}
if ( $object->isSubscriberOnly() ) {
$temp_handler =& $this->Application->recallObject($event->Prefix . '_TempHandler', 'kTempTablesHandler');
/* @var $temp_handler kTempTablesHandler */
$temp_handler->DeleteItems($event->Prefix, '', Array($object->GetID()));
}
else {
$this->RemoveSubscriberGroup( $object->GetID() );
}
$event->redirect = $this->Application->GetVar('unsubscribe_ok_template');
}
else {
$this->AddSubscriberGroup($object);
$event->redirect = $this->Application->GetVar('subscribe_ok_template');
}
}
else {
$object->generatePassword();
$object->SetDBField('Email', $user_email);
if ( $object->isRequired('Username') ) {
$object->SetDBField('Username', $user_email);
}
$object->SetDBField('Status', STATUS_ACTIVE); // make user subscriber Active by default
if ( $object->Create() ) {
$this->AddSubscriberGroup($object);
$event->redirect = $this->Application->GetVar('subscribe_ok_template');
}
}
}
/**
* Adding user to subscribers group
*
* @param UsersItem $object
*/
function AddSubscriberGroup(&$object)
{
if ( !$object->isSubscriberOnly() ) {
$fields_hash = Array (
'PortalUserId' => $object->GetID(),
'GroupId' => $this->Application->ConfigValue('User_SubscriberGroup'),
);
$this->Conn->doInsert($fields_hash, TABLE_PREFIX . 'UserGroupRelations');
}
$this->Application->EmailEventAdmin('USER.SUBSCRIBE');
$this->Application->EmailEventUser('USER.SUBSCRIBE', $object->GetID());
}
/**
* Removing user from subscribers group
*
* @param int $user_id
*/
function RemoveSubscriberGroup($user_id)
{
$group_id = $this->Application->ConfigValue('User_SubscriberGroup');
$sql = 'DELETE FROM ' . TABLE_PREFIX . 'UserGroupRelations
WHERE PortalUserId = ' . $user_id . ' AND GroupId = ' . $group_id;
$this->Conn->Query($sql);
$this->Application->EmailEventAdmin('USER.UNSUBSCRIBE');
$this->Application->EmailEventUser('USER.UNSUBSCRIBE', $user_id);
}
/**
* Validates forgot password form and sends password reset confirmation e-mail
*
* @param kEvent $event
* @return void
*/
- function OnForgotPassword(&$event)
+ function OnForgotPassword($event)
{
$object =& $event->getObject( Array ('form_name' => 'forgot_password') );
/* @var $object kDBItem */
$field_values = $this->getSubmittedFields($event);
$object->SetFieldsFromHash($field_values, $this->getRequestProtectedFields($field_values));
$user_object =& $this->Application->recallObject('u.tmp', null, Array('skip_autoload' => true));
/* @var $user_object UsersItem */
$found = $allow_reset = false;
$username = $object->GetDBField('ForgotLogin');
$email = $object->GetDBField('ForgotEmail');
if ( strlen($username) ) {
$user_object->Load($username, 'Username');
}
elseif ( strlen($email) ) {
$user_object->Load($email, 'Email');
}
if ( $user_object->isLoaded() ) {
$min_pwd_reset_delay = $this->Application->ConfigValue('Users_AllowReset');
$found = ($user_object->GetDBField('Status') == STATUS_ACTIVE) && strlen( $user_object->GetDBField('Password') );
if ( !$user_object->GetDBField('PwResetConfirm') ) {
// no reset made -> allow
$allow_reset = true;
}
else {
// reset made -> wait N minutes, then allow
$allow_reset = adodb_mktime() > $user_object->GetDBField('PwRequestTime') + $min_pwd_reset_delay;
}
}
if ($found && $allow_reset) {
$this->Application->EmailEventUser('USER.PSWDC', $user_object->GetID());
$event->redirect = $this->Application->GetVar('template_success');
return ;
}
if ( !strlen($username) && !strlen($email) ) {
$object->SetError('ForgotLogin', 'required');
$object->SetError('ForgotEmail', 'required');
}
else {
if ( strlen($username) ) {
$object->SetError('ForgotLogin', $found ? 'reset_denied' : 'unknown_username');
}
if ( strlen($email) ) {
$object->SetError('ForgotEmail', $found ? 'reset_denied' : 'unknown_email');
}
}
if ( !$object->ValidateField('ForgotLogin') || !$object->ValidateField('ForgotEmail') ) {
$event->status = kEvent::erFAIL;
}
}
/**
* Updates kDBItem
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnUpdate(kEvent &$event)
+ protected function OnUpdate(kEvent $event)
{
parent::OnUpdate($event);
if ( !$this->Application->isAdmin ) {
$this->setNextTemplate($event);
}
}
/**
* Checks state against country
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnBeforeItemUpdate(kEvent &$event)
+ protected function OnBeforeItemUpdate(kEvent $event)
{
parent::OnBeforeItemUpdate($event);
$this->beforeItemChanged($event);
$cs_helper =& $this->Application->recallObject('CountryStatesHelper');
/* @var $cs_helper kCountryStatesHelper */
$cs_helper->CheckStateField($event, 'State', 'Country');
$cs_helper->PopulateStates($event, 'State', 'Country');
$object =& $event->getObject();
/* @var $object kDBItem */
if ( $event->Special == 'forgot' ) {
$object->SetDBField('PwResetConfirm', '');
$object->SetDBField('PwRequestTime_date', NULL);
$object->SetDBField('PwRequestTime_time', NULL);
}
$changed_fields = array_keys($object->GetChangedFields());
if ( $changed_fields && !in_array('Modified', $changed_fields) ) {
$object->SetDBField('Modified_date', adodb_mktime());
$object->SetDBField('Modified_time', adodb_mktime());
}
if ( !$this->Application->isAdmin && in_array('Email', $changed_fields) && ($event->Special != 'email-restore') ) {
$object->SetDBField('EmailVerified', 0);
}
}
/**
* Occurs before item is changed
*
* @param kEvent $event
*/
- function beforeItemChanged(&$event)
+ function beforeItemChanged($event)
{
$object =& $event->getObject();
/* @var $object UsersItem */
if ( !$this->Application->isAdmin && $object->getFormName() == 'registration' ) {
// sets new user's status based on config options
$status_map = Array (1 => STATUS_ACTIVE, 2 => STATUS_DISABLED, 3 => STATUS_PENDING, 4 => STATUS_PENDING);
$object->SetDBField('Status', $status_map[ $this->Application->ConfigValue('User_Allow_New') ]);
if ( $this->Application->ConfigValue('User_Password_Auto') ) {
$object->generatePassword( rand(5, 8) );
}
if ( $this->Application->ConfigValue('RegistrationCaptcha') ) {
$captcha_helper =& $this->Application->recallObject('CaptchaHelper');
/* @var $captcha_helper kCaptchaHelper */
$captcha_helper->validateCode($event, false);
}
if ( $event->Name == 'OnBeforeItemUpdate' ) {
// when a subscriber-only users performs normal registration, then assign him to Member group
$this->setUserGroup($object);
}
}
}
/**
* Sets redirect template based on user status & user request contents
*
* @param kEvent $event
* @param bool $for_registration
*/
- function setNextTemplate(&$event, $for_registration = false)
+ function setNextTemplate($event, $for_registration = false)
{
$event->SetRedirectParam('opener', 's');
$object =& $event->getObject();
/* @var $object UsersItem */
$next_template = false;
if ( $object->GetDBField('Status') == STATUS_ACTIVE && $this->Application->GetVar('next_template') ) {
$next_template = $this->Application->GetVar('next_template');
}
elseif ( $for_registration ) {
switch ( $this->Application->ConfigValue('User_Allow_New') ) {
case 1: // Immediate
$next_template = $this->Application->GetVar('registration_confirm_template');
break;
case 3: // Upon Approval
case 4: // Email Activation
$next_template = $this->Application->GetVar('registration_confirm_pending_template');
break;
}
}
if ($next_template) {
$event->redirect = $next_template;
}
}
/**
* Delete users from groups if their membership is expired
*
* @param kEvent $event
*/
- function OnCheckExpiredMembership(&$event)
+ function OnCheckExpiredMembership($event)
{
// send pre-expiration reminders: begin
$pre_expiration = adodb_mktime() + $this->Application->ConfigValue('User_MembershipExpirationReminder') * 3600 * 24;
$sql = 'SELECT PortalUserId, GroupId
FROM '.TABLE_PREFIX.'UserGroupRelations
WHERE (MembershipExpires IS NOT NULL) AND (ExpirationReminderSent = 0) AND (MembershipExpires < '.$pre_expiration.')';
$skip_clause = $event->getEventParam('skip_clause');
if ($skip_clause) {
$sql .= ' AND !('.implode(') AND !(', $skip_clause).')';
}
$records = $this->Conn->Query($sql);
if ($records) {
$conditions = Array();
foreach ($records as $record) {
$this->Application->EmailEventUser('USER.MEMBERSHIP.EXPIRATION.NOTICE', $record['PortalUserId']);
$this->Application->EmailEventAdmin('USER.MEMBERSHIP.EXPIRATION.NOTICE');
$conditions[] = '(PortalUserId = '.$record['PortalUserId'].' AND GroupId = '.$record['GroupId'].')';
}
$sql = 'UPDATE '.TABLE_PREFIX.'UserGroupRelations
SET ExpirationReminderSent = 1
WHERE '.implode(' OR ', $conditions);
$this->Conn->Query($sql);
}
// send pre-expiration reminders: end
// remove users from groups with expired membership: begin
$sql = 'SELECT PortalUserId
FROM '.TABLE_PREFIX.'UserGroupRelations
WHERE (MembershipExpires IS NOT NULL) AND (MembershipExpires < '.adodb_mktime().')';
$user_ids = $this->Conn->GetCol($sql);
if ($user_ids) {
foreach ($user_ids as $id) {
$this->Application->EmailEventUser('USER.MEMBERSHIP.EXPIRED', $id);
$this->Application->EmailEventAdmin('USER.MEMBERSHIP.EXPIRED');
}
}
$sql = 'DELETE FROM '.TABLE_PREFIX.'UserGroupRelations
WHERE (MembershipExpires IS NOT NULL) AND (MembershipExpires < '.adodb_mktime().')';
$this->Conn->Query($sql);
// remove users from groups with expired membership: end
}
/**
* Used to keep user registration form data, while showing affiliate registration form fields
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnRefreshForm(&$event)
+ protected function OnRefreshForm($event)
{
$event->redirect = false;
$item_info = $this->Application->GetVar( $event->getPrefixSpecial(true) );
list($id, $field_values) = each($item_info);
$object =& $event->getObject( Array ('skip_autoload' => true) );
/* @var $object kDBItem */
$object->setID($id);
$object->IgnoreValidation = true;
$object->SetFieldsFromHash($field_values, $this->getRequestProtectedFields($field_values));
}
/**
* Sets persistant variable
*
* @param kEvent $event
*/
- function OnSetPersistantVariable(&$event)
+ function OnSetPersistantVariable($event)
{
$field = $this->Application->GetVar('field');
$value = $this->Application->GetVar('value');
$this->Application->StorePersistentVar($field, $value);
$force_tab = $this->Application->GetVar('SetTab');
if ($force_tab) {
$this->Application->StoreVar('force_tab', $force_tab);
}
}
/**
* Return user from order by special .ord
*
* @param kEvent $event
* @return int
* @access public
*/
- public function getPassedID(kEvent &$event)
+ public function getPassedID(kEvent $event)
{
switch ($event->Special) {
case 'ord':
$order =& $this->Application->recallObject('ord');
/* @var $order OrdersItem */
return $order->GetDBField('PortalUserId');
break;
case 'profile':
$id = $this->Application->GetVar('user_id');
if ( !$id ) {
// if none user_id given use current user id
$id = $this->Application->RecallVar('user_id');
}
return $id;
break;
case 'forgot':
$user_helper =& $this->Application->recallObject('UserHelper');
/* @var $user_helper UserHelper */
$id = $user_helper->validateUserCode($this->Application->GetVar('user_key'), 'forgot_password');
if ( is_numeric($id) ) {
return $id;
}
break;
}
if ( preg_match('/^(login|register|recommend|subscribe|forgot)/', $event->Special) ) {
// this way we can have 2+ objects stating with same special, e.g. "u.login-sidebox" and "u.login-main"
return USER_GUEST;
}
return parent::getPassedID($event);
}
/**
* Allows to change root password
*
* @param kEvent $event
*/
- function OnUpdateRootPassword(&$event)
+ function OnUpdateRootPassword($event)
{
return $this->OnUpdatePassword($event);
}
/**
* Allows to change root password
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnUpdatePassword(&$event)
+ protected function OnUpdatePassword($event)
{
$items_info = $this->Application->GetVar($event->getPrefixSpecial(true));
if ( !$items_info ) {
return;
}
list ($id, $field_values) = each($items_info);
$user_id = $this->Application->RecallVar('user_id');
if ( $id == $user_id && ($user_id > 0 || $user_id == USER_ROOT) ) {
$user_dummy =& $this->Application->recallObject($event->Prefix . '.-item', null, Array ('skip_autoload' => true));
/* @var $user_dummy kDBItem */
$user_dummy->Load($id);
$status_field = array_shift( $this->Application->getUnitOption($event->Prefix, 'StatusField') );
if ( $user_dummy->GetDBField($status_field) != STATUS_ACTIVE ) {
// not active user is not allowed to update his record (he could not activate himself manually)
return ;
}
}
if ( $user_id == USER_ROOT ) {
$object =& $event->getObject(Array ('skip_autoload' => true));
/* @var $object UsersItem */
// put salt to user's config
$field_options = $object->GetFieldOptions('RootPassword');
$field_options['salt'] = 'b38';
// this is internal hack to allow root/root passwords for dev
if ( $this->Application->isDebugMode() && $field_values['RootPassword'] == 'root' ) {
$field_options['min_length'] = 4;
}
$object->SetFieldOptions('RootPassword', $field_options);
$verify_options = $object->GetFieldOptions('VerifyRootPassword');
$verify_options['salt'] = 'b38';
$object->SetFieldOptions('VerifyRootPassword', $verify_options);
$this->RemoveRequiredFields($object);
$object->SetDBField('RootPassword', $this->Application->ConfigValue('RootPass'));
$object->SetFieldsFromHash($field_values, $this->getRequestProtectedFields($field_values));
$object->setID(-1);
if ( $object->Validate() ) {
// validation on, password match too
$fields_hash = Array ('VariableValue' => $object->GetDBField('RootPassword'));
$conf_table = $this->Application->getUnitOption('conf', 'TableName');
$this->Conn->doUpdate($fields_hash, $conf_table, 'VariableName = "RootPass"');
$event->SetRedirectParam('opener', 'u');
}
else {
$event->status = kEvent::erFAIL;
$event->redirect = false;
return ;
}
}
else {
$object =& $event->getObject();
$object->SetFieldsFromHash($field_values, $this->getRequestProtectedFields($field_values));
if ( !$object->Update() ) {
$event->status = kEvent::erFAIL;
$event->redirect = false;
}
}
$event->SetRedirectParam('opener', 'u');
}
/**
* Resets grid settings, remembered in each user record
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnMassResetSettings(&$event)
+ protected function OnMassResetSettings($event)
{
if ( $this->Application->CheckPermission('SYSTEM_ACCESS.READONLY', 1) ) {
$event->status = kEvent::erFAIL;
return;
}
$ids = $this->StoreSelectedIDs($event);
$default_user_id = $this->Application->ConfigValue('DefaultSettingsUserId');
if ( in_array($default_user_id, $ids) ) {
array_splice($ids, array_search($default_user_id, $ids), 1);
}
if ( $ids ) {
$q = 'DELETE FROM ' . TABLE_PREFIX . 'UserPersistentSessionData WHERE PortalUserId IN (' . join(',', $ids) . ') AND
(VariableName LIKE "%_columns_%"
OR
VariableName LIKE "%_filter%"
OR
VariableName LIKE "%_PerPage%")';
$this->Conn->Query($q);
}
$this->clearSelectedIDs($event);
}
/**
* Checks, that currently loaded item is allowed for viewing (non permission-based)
*
* @param kEvent $event
* @return bool
* @access protected
*/
- protected function checkItemStatus(kEvent &$event)
+ protected function checkItemStatus(kEvent $event)
{
$object =& $event->getObject();
/* @var $object kDBItem */
if ( !$object->isLoaded() ) {
return true;
}
$virtual_users = Array (USER_ROOT, USER_GUEST);
return ($object->GetDBField('Status') == STATUS_ACTIVE) || in_array($object->GetID(), $virtual_users);
}
/**
* Sends approved/declined email event on user status change
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnAfterItemUpdate(kEvent &$event)
+ protected function OnAfterItemUpdate(kEvent $event)
{
parent::OnAfterItemUpdate($event);
$this->afterItemChanged($event);
$object =& $event->getObject();
/* @var $object UsersItem */
if ( !$this->Application->isAdmin && ($event->Special != 'email-restore') ) {
$this->sendEmailChangeEvent($event);
}
if ( !$this->Application->isAdmin || $object->IsTempTable() ) {
return;
}
$this->sendStatusChangeEvent($object->GetID(), $object->GetOriginalField('Status'), $object->GetDBField('Status'));
}
/**
* Occurs, after item is changed
*
* @param kEvent $event
*/
- protected function afterItemChanged(&$event)
+ protected function afterItemChanged($event)
{
$this->saveUserImages($event);
$object =& $event->getObject();
/* @var $object UsersItem */
if ( $object->GetDBField('EmailPassword') && $object->GetDBField('Password_plain') ) {
$email_passwords = $this->Application->RecallVar('email_passwords');
$email_passwords = $email_passwords ? unserialize($email_passwords) : Array ();
$email_passwords[ $object->GetID() ] = $object->GetDBField('Password_plain');
$this->Application->StoreVar('email_passwords', serialize($email_passwords));
}
// update user subscription status (via my profile or new user registration)
if ( !$this->Application->isAdmin && !$object->isSubscriberOnly() ) {
if ( $object->GetDBField('SubscribeToMailing') && !$object->isSubscribed() ) {
$this->AddSubscriberGroup($object);
}
elseif ( !$object->GetDBField('SubscribeToMailing') && $object->isSubscribed() ) {
$this->RemoveSubscriberGroup( $object->GetID() );
}
}
}
/**
* Stores user's original Status before overwriting with data from temp table
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnBeforeDeleteFromLive(kEvent &$event)
+ protected function OnBeforeDeleteFromLive(kEvent $event)
{
parent::OnBeforeDeleteFromLive($event);
$user_id = $event->getEventParam('id');
$user_status = $this->Application->GetVar('user_status', Array ());
if ( $user_id > 0 ) {
$user_status[$user_id] = $this->getUserStatus($user_id);
$this->Application->SetVar('user_status', $user_status);
}
}
/**
* Sends approved/declined email event on user status change (in temp tables during editing)
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnAfterCopyToLive(kEvent &$event)
+ protected function OnAfterCopyToLive(kEvent $event)
{
parent::OnAfterCopyToLive($event);
$temp_id = $event->getEventParam('temp_id');
$email_passwords = $this->Application->RecallVar('email_passwords');
if ( $email_passwords ) {
$email_passwords = unserialize($email_passwords);
if ( isset($email_passwords[$temp_id]) ) {
$object =& $event->getObject();
/* @var $object kDBItem */
$object->SwitchToLive();
$object->Load( $event->getEventParam('id') );
$object->SetField('Password', $email_passwords[$temp_id]);
$object->SetField('VerifyPassword', $email_passwords[$temp_id]);
$this->Application->EmailEventUser($temp_id > 0 ? 'USER.NEW.PASSWORD': 'USER.ADD.BYADMIN', $object->GetID());
unset($email_passwords[$temp_id]);
$this->Application->StoreVar('email_passwords', serialize($email_passwords));
}
}
if ( $temp_id > 0 ) {
// only send status change e-mail on user update
$new_status = $this->getUserStatus($temp_id);
$user_status = $this->Application->GetVar('user_status');
$this->sendStatusChangeEvent($temp_id, $user_status[$temp_id], $new_status);
}
}
/**
* Returns user status (active, pending, disabled) based on ID and temp mode setting
*
* @param int $user_id
* @return int
*/
function getUserStatus($user_id)
{
$id_field = $this->Application->getUnitOption($this->Prefix, 'IDField');
$table_name = $this->Application->getUnitOption($this->Prefix, 'TableName');
$sql = 'SELECT Status
FROM '.$table_name.'
WHERE '.$id_field.' = '.$user_id;
return $this->Conn->GetOne($sql);
}
/**
* Sends approved/declined email event on user status change
*
* @param int $user_id
* @param int $prev_status
* @param int $new_status
*/
function sendStatusChangeEvent($user_id, $prev_status, $new_status)
{
$status_events = Array (
STATUS_ACTIVE => 'USER.APPROVE',
STATUS_DISABLED => 'USER.DENY',
);
$email_event = isset($status_events[$new_status]) ? $status_events[$new_status] : false;
if (($prev_status != $new_status) && $email_event) {
$this->Application->EmailEventUser($email_event, $user_id);
$this->Application->EmailEventAdmin($email_event);
}
// deletes sessions from users, that are no longer active
if (($prev_status != $new_status) && ($new_status != STATUS_ACTIVE)) {
$sql = 'SELECT SessionKey
FROM ' . TABLE_PREFIX . 'UserSessions
WHERE PortalUserId = ' . $user_id;
$session_ids = $this->Conn->GetCol($sql);
$this->Application->Session->DeleteSessions($session_ids);
}
}
/**
* Sends restore/validation email event on user email change
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function sendEmailChangeEvent(kEvent &$event)
+ protected function sendEmailChangeEvent(kEvent $event)
{
$object =& $event->getObject();
/* @var $object UsersItem */
$new_email = $object->GetDBField('Email');
$prev_email = $object->GetOriginalField('Email');
if ( !$new_email || ($prev_email == $new_email) ) {
return;
}
$prev_emails = $object->GetDBField('PrevEmails');
$prev_emails = $prev_emails ? unserialize($prev_emails) : Array ();
$fields_hash = Array (
'PrevEmails' => serialize($prev_emails),
'EmailVerified' => 0,
);
$user_id = $object->GetID();
if ( $prev_email ) {
$hash = md5(TIMENOW + $user_id);
$prev_emails[$hash] = $prev_email;
$fields_hash['PrevEmails'] = serialize($prev_emails);
$send_params = Array (
'hash' => $hash,
'to_email' => $prev_email,
'to_name' => trim($object->GetDBField('FirstName') . ' ' . $object->GetDBField('LastName')),
);
$this->Application->EmailEventUser('USER.EMAIL.CHANGE.UNDO', null, $send_params);
}
if ( $new_email ) {
$this->Application->EmailEventUser('USER.EMAIL.CHANGE.VERIFY', $user_id);
}
// direct DB update, since USER.EMAIL.CHANGE.VERIFY puts verification code in user record, that we don't want to loose
$this->Conn->doUpdate($fields_hash, $object->TableName, 'PortalUserId = ' . $user_id);
}
/**
* OnAfterConfigRead for users
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnAfterConfigRead(kEvent &$event)
+ protected function OnAfterConfigRead(kEvent $event)
{
parent::OnAfterConfigRead($event);
$forms = $this->Application->getUnitOption($event->Prefix, 'Forms');
$form_fields =& $forms['default']['Fields'];
// 1. arrange user registration countries
$site_helper =& $this->Application->recallObject('SiteHelper');
/* @var $site_helper SiteHelper */
$first_country = $site_helper->getDefaultCountry('', false);
if ($first_country === false) {
$first_country = $this->Application->ConfigValue('User_Default_Registration_Country');
}
if ($first_country) {
// update user country dropdown sql
$form_fields['Country']['options_sql'] = preg_replace('/ORDER BY (.*)/', 'ORDER BY IF (CountryStateId = '.$first_country.', 1, 0) DESC, \\1', $form_fields['Country']['options_sql']);
}
$max_username = $this->Application->ConfigValue('MaxUserName');
$form_fields['Username']['min_len'] = $this->Application->ConfigValue('Min_UserName');
$form_fields['Username']['max_len'] = $max_username ? $max_username : 255;
// 2. set default user registration group
$form_fields['PrimaryGroupId']['default'] = $this->Application->ConfigValue('User_NewGroup');
// 3. allow avatar upload on Front-End
$file_helper =& $this->Application->recallObject('FileHelper');
/* @var $file_helper FileHelper */
$file_helper->createItemFiles($event->Prefix, true); // create image fields
if ($this->Application->isAdminUser) {
// 4. when in administrative console, then create all users with Active status
$form_fields['Status']['default'] = STATUS_ACTIVE;
// 5. remove groups tab on editing forms when AdvancedUserManagement config variable not set
if (!$this->Application->ConfigValue('AdvancedUserManagement')) {
$edit_tab_presets = $this->Application->getUnitOption($event->Prefix, 'EditTabPresets');
foreach ($edit_tab_presets as $preset_name => $preset_tabs) {
if (array_key_exists('groups', $preset_tabs)) {
unset($edit_tab_presets[$preset_name]['groups']);
if (count($edit_tab_presets[$preset_name]) == 1) {
// only 1 tab left -> remove it too
$edit_tab_presets[$preset_name] = Array ();
}
}
}
$this->Application->setUnitOption($event->Prefix, 'EditTabPresets', $edit_tab_presets);
}
}
if ( $this->Application->ConfigValue('RegistrationUsernameRequired') ) {
// Username becomes required only, when it's used in registration process
$form_fields['Username']['required'] = 1;
}
$this->Application->setUnitOption($event->Prefix, 'Forms', $forms);
}
/**
* OnMassCloneUsers
*
* @param kEvent $event
*/
- function OnMassCloneUsers(&$event)
+ function OnMassCloneUsers($event)
{
if ($this->Application->CheckPermission('SYSTEM_ACCESS.READONLY', 1)) {
$event->status = kEvent::erFAIL;
return;
}
$temp_handler =& $this->Application->recallObject($event->Prefix.'_TempHandler', 'kTempTablesHandler');
/* @var $temp_handler kTempTablesHandler */
$ids = $this->StoreSelectedIDs($event);
$temp_handler->CloneItems($event->Prefix, '', $ids);
$this->clearSelectedIDs($event);
}
/**
* When cloning users, reset password (set random)
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnBeforeClone(kEvent &$event)
+ protected function OnBeforeClone(kEvent $event)
{
parent::OnBeforeClone($event);
$object =& $event->getObject();
/* @var $object UsersItem */
$object->generatePassword();
$object->SetDBField('ResourceId', 0); // this will reset it
// change email because it should be unique
$object->NameCopy(Array (), $object->GetID(), 'Email', 'copy%1$s.%2$s');
}
/**
* Saves selected ids to session
*
* @param kEvent $event
*/
- function OnSaveSelected(&$event)
+ function OnSaveSelected($event)
{
$this->StoreSelectedIDs($event);
// remove current ID, otherwise group selector will use it in filters
$this->Application->DeleteVar($event->getPrefixSpecial(true) . '_id');
}
/**
* Sets primary group of selected users
*
* @param kEvent $event
*/
- function OnProcessSelected(&$event)
+ function OnProcessSelected($event)
{
$event->SetRedirectParam('opener', 'u');
$user_ids = $this->getSelectedIDs($event, true);
$this->clearSelectedIDs($event);
$dst_field = $this->Application->RecallVar('dst_field');
if ($dst_field != 'PrimaryGroupId') {
return ;
}
$group_ids = $this->Application->GetVar('g');
$primary_group_id = $group_ids ? array_shift( array_keys($group_ids) ) : false;
if (!$user_ids || !$primary_group_id) {
return ;
}
$table_name = $this->Application->getUnitOption('ug', 'TableName');
// 1. mark group as primary
$sql = 'UPDATE ' . TABLE_PREFIX . 'Users
SET PrimaryGroupId = ' . $primary_group_id . '
WHERE PortalUserId IN (' . implode(',', $user_ids) . ')';
$this->Conn->Query($sql);
$sql = 'SELECT PortalUserId
FROM ' . $table_name . '
WHERE (GroupId = ' . $primary_group_id . ') AND (PortalUserId IN (' . implode(',', $user_ids) . '))';
$existing_members = $this->Conn->GetCol($sql);
// 2. add new members to a group
$new_members = array_diff($user_ids, $existing_members);
foreach ($new_members as $user_id) {
$fields_hash = Array (
'GroupId' => $primary_group_id,
'PortalUserId' => $user_id,
);
$this->Conn->doInsert($fields_hash, $table_name);
}
}
/**
* Loads user images
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnAfterItemLoad(kEvent &$event)
+ protected function OnAfterItemLoad(kEvent $event)
{
parent::OnAfterItemLoad($event);
// linking existing images for item with virtual fields
$image_helper =& $this->Application->recallObject('ImageHelper');
/* @var $image_helper ImageHelper */
$object =& $event->getObject();
/* @var $object UsersItem */
$image_helper->LoadItemImages($object);
$cs_helper =& $this->Application->recallObject('CountryStatesHelper');
/* @var $cs_helper kCountryStatesHelper */
$cs_helper->PopulateStates($event, 'State', 'Country');
// get user subscription status
$object->SetDBField('SubscribeToMailing', $object->isSubscribed() ? 1 : 0);
if ( !$this->Application->isAdmin ) {
$list = $this->Application->recallObject('lang.enabled', 'lang_List');
/* @var $list kDBList */
$list->GoFirst();
$languages = Array ();
while (!$list->EOL()) {
$languages[$list->GetID()] = $list->GetField('LocalName');
$list->GoNext();
}
$object->SetFieldOption('FrontLanguage', 'options', $languages);
}
}
/**
* Save user images
*
* @param kEvent $event
*/
- function saveUserImages(&$event)
+ function saveUserImages($event)
{
if (!$this->Application->isAdmin) {
$image_helper =& $this->Application->recallObject('ImageHelper');
/* @var $image_helper ImageHelper */
$object =& $event->getObject();
/* @var $object kDBItem */
// process image upload in virtual fields
$image_helper->SaveItemImages($object);
}
}
/**
* Makes password required for new users
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnPreCreate(kEvent &$event)
+ protected function OnPreCreate(kEvent $event)
{
parent::OnPreCreate($event);
if ( $event->status != kEvent::erSUCCESS ) {
return;
}
$object =& $event->getObject();
/* @var $object kDBItem */
$user_type = $this->Application->GetVar('user_type');
if ( $user_type ) {
$object->SetDBField('UserType', $user_type);
if ( $user_type == UserType::ADMIN ) {
$object->SetDBField('PrimaryGroupId', $this->Application->ConfigValue('User_AdminGroup'));
}
}
if ( $this->Application->ConfigValue('User_Password_Auto') ) {
$object->SetDBField('EmailPassword', 1);
}
$this->_makePasswordRequired($event);
}
/**
* Makes password required for new users
*
* @param kEvent $event
*/
- function _makePasswordRequired(&$event)
+ function _makePasswordRequired($event)
{
$object =& $event->getObject();
/* @var $object kDBItem */
$required_fields = Array ('Password', 'Password_plain', 'VerifyPassword', 'VerifyPassword_plain');
$object->setRequired($required_fields);
}
/**
* Load item if id is available
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function LoadItem(kEvent &$event)
+ protected function LoadItem(kEvent $event)
{
$id = $this->getPassedID($event);
if ( $id < 0 ) {
// when root, guest and so on
$object =& $event->getObject();
/* @var $object kDBItem */
$object->Clear($id);
return;
}
parent::LoadItem($event);
}
/**
* Occurs just after login (for hooking)
*
* @param kEvent $event
*/
- function OnAfterLogin(&$event)
+ function OnAfterLogin($event)
{
}
/**
* Occurs just before logout (for hooking)
*
* @param kEvent $event
*/
- function OnBeforeLogout(&$event)
+ function OnBeforeLogout($event)
{
}
/**
* Generates password
*
* @param kEvent $event
*/
- function OnGeneratePassword(&$event)
+ function OnGeneratePassword($event)
{
$event->status = kEvent::erSTOP;
if ( $this->Application->isAdminUser ) {
echo kUtil::generatePassword();
}
}
/**
* Changes user's password and logges him in
*
* @param kEvent $event
*/
- function OnResetLostPassword(&$event)
+ function OnResetLostPassword($event)
{
$object =& $event->getObject();
/* @var $object kDBItem */
$event->CallSubEvent('OnUpdate');
if ( $event->status == kEvent::erSUCCESS ) {
$user_helper =& $this->Application->recallObject('UserHelper');
/* @var $user_helper UserHelper */
$user =& $user_helper->getUserObject();
$user->Load( $object->GetID() );
if ( $user_helper->checkLoginPermission() ) {
$user_helper->loginUserById( $user->GetID() );
}
}
}
/**
* Generates new Root password and email it
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnResetRootPassword(&$event)
+ protected function OnResetRootPassword($event)
{
$password_formatter =& $this->Application->recallObject('kPasswordFormatter');
/* @var $password_formatter kPasswordFormatter */
$new_root_password = kUtil::generatePassword();
$new_root_password_encrypted = $password_formatter->EncryptPassword($new_root_password, 'b38');
$this->Application->SetConfigValue('RootPass', $new_root_password_encrypted);
$this->Application->EmailEventAdmin('ROOT.RESET.PASSWORD', null, Array ('password' => $new_root_password));
$event->SetRedirectParam('reset', 1);
$event->SetRedirectParam('pass', 'm');
}
/**
* Perform login of user, selected in Admin Console, on Front-End in a separate window
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnLoginAs(kEvent &$event)
+ protected function OnLoginAs(kEvent $event)
{
$user_helper =& $this->Application->recallObject('UserHelper');
/* @var $user_helper UserHelper */
$user =& $user_helper->getUserObject();
$user->Load( $this->Application->GetVar('user_id') );
if ( !$user->isLoaded() ) {
return ;
}
if ( $user_helper->checkLoginPermission() ) {
$user_helper->loginUserById( $user->GetID() );
}
}
}
Index: branches/5.2.x/core/units/favorites/favorites_eh.php
===================================================================
--- branches/5.2.x/core/units/favorites/favorites_eh.php (revision 15129)
+++ branches/5.2.x/core/units/favorites/favorites_eh.php (revision 15130)
@@ -1,111 +1,111 @@
<?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 standard permission mapping
*
* @return void
* @access protected
* @see kEventHandler::$permMapping
*/
protected 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)
+ 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(kEvent &$event)
+ protected function OnBeforeItemCreate(kEvent $event)
{
parent::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)
+ 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 15129)
+++ branches/5.2.x/core/units/files/file_eh.php (revision 15130)
@@ -1,111 +1,111 @@
<?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 standard permission mapping
*
* @return void
* @access protected
* @see kEventHandler::$permMapping
*/
protected 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(kEvent &$event)
+ protected function OnBeforeItemCreate(kEvent $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(kEvent &$event)
+ protected function OnBeforeItemUpdate(kEvent $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(kEvent &$event)
+ protected function SetCustomQuery(kEvent $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)
+ 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/helpers/clipboard_helper.php
===================================================================
--- branches/5.2.x/core/units/helpers/clipboard_helper.php (revision 15129)
+++ branches/5.2.x/core/units/helpers/clipboard_helper.php (revision 15130)
@@ -1,60 +1,60 @@
<?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 kClipboardHelper extends kHelper {
/**
* Set's clipboard mode
*
* @param kEvent $event
* @param string $mode
* @param Array $ids
*/
- function setClipboard(&$event, $mode, $ids)
+ function setClipboard($event, $mode, $ids)
{
// clipboard = { prefix1 = { cut = {idsA}, copy = {idsB} }, ... prefixN = { cut = {idsC}, copy = {idsD} } }
$object = $event->getObject();
$clipboard = $this->Application->RecallVar('clipboard');
$clipboard = $clipboard ? unserialize($clipboard) : Array();
$prefix = $event->getPrefixSpecial();
// 1. add $ids to mode key for prefix (make sure the unique)
$this_mode_ids =& $clipboard[$prefix][$mode];
if (!is_array($this_mode_ids)) {
$this_mode_ids = $ids;
}
else {
$this_mode_ids = array_unique( array_merge($this_mode_ids, $ids) );
}
// 2. remove that ids from all other modes
$other_mode_ids =& $clipboard[$prefix][$mode == 'cut' ? 'copy' : 'cut'];
if (!is_array($other_mode_ids)) {
$other_mode_ids = Array();
}
else {
$other_mode_ids = array_diff($other_mode_ids, $this_mode_ids);
}
$this->Application->StoreVar('clipboard', serialize($clipboard));
/*// do not go up - STAY
$event->SetRedirectParam('opener', 's');
$event->SetRedirectParam('pass_events', true);*/
}
}
\ No newline at end of file
Index: branches/5.2.x/core/units/helpers/search_helper.php
===================================================================
--- branches/5.2.x/core/units/helpers/search_helper.php (revision 15129)
+++ branches/5.2.x/core/units/helpers/search_helper.php (revision 15130)
@@ -1,805 +1,805 @@
<?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 kSearchHelper extends kHelper {
/**
* Perform Exact Search flag
*
* @var bool
* @access protected
*/
protected $_performExactSearch = true;
public function __construct()
{
parent::__construct();
$this->_performExactSearch = $this->Application->ConfigValue('PerformExactSearch');
}
/**
* Splits search phrase into keyword using quotes,plus and minus sings and spaces as split criteria
*
* @param string $keyword
* @return Array
* @access public
*/
public function splitKeyword($keyword)
{
if ( $this->Application->ConfigValue('CheckStopWords') ) {
$keyword_after_remove = $this->_removeStopWords($keyword);
if ( $keyword_after_remove ) {
// allow to search through stop word grid
$keyword = $keyword_after_remove;
}
}
$final = Array ();
$quotes_re = '/([+\-]?)"(.*?)"/';
$no_quotes_re = '/([+\-]?)([^ ]+)/';
preg_match_all($quotes_re, $keyword, $res);
foreach ($res[2] as $index => $kw) {
$final[$kw] = $res[1][$index];
}
$keyword = preg_replace($quotes_re, '', $keyword);
preg_match_all($no_quotes_re, $keyword, $res);
foreach ($res[2] as $index => $kw) {
$final[$kw] = $res[1][$index];
}
if ( $this->_performExactSearch ) {
foreach ($final AS $kw => $plus_minus) {
if ( !$plus_minus ) {
$final[$kw] = '+';
}
}
}
return $final;
}
function getPositiveKeywords($keyword)
{
$keywords = $this->splitKeyword($keyword);
$ret = Array();
foreach ($keywords as $keyword => $sign) {
if ($sign == '+' || $sign == '') {
$ret[] = $keyword;
}
}
return $ret;
}
/**
* Replace wildcards to match MySQL
*
* @param string $keyword
* @return string
*/
function transformWildcards($keyword)
{
return str_replace(Array ('%', '_', '*', '?') , Array ('\%', '\_', '%', '_'), $keyword);
}
function buildWhereClause($keyword, $fields)
{
$keywords = $this->splitKeyword( $this->transformWildcards($keyword) );
$normal_conditions = $plus_conditions = $minus_conditions = Array();
foreach ($keywords as $keyword => $sign) {
$keyword = $this->Conn->escape($keyword);
switch ($sign) {
case '+':
$plus_conditions[] = implode(" LIKE '%" . $keyword . "%' OR ", $fields) . " LIKE '%" . $keyword . "%'";
break;
case '-':
$condition = Array ();
foreach ($fields as $field) {
$condition[] = $field . " NOT LIKE '%" . $keyword . "%' OR " . $field . ' IS NULL';
}
$minus_conditions[] = '(' . implode(') AND (', $condition) . ')';
break;
case '':
$normal_conditions[] = implode(" LIKE '%" . $keyword . "%' OR ", $fields) . " LIKE '%" . $keyword . "%'";
break;
}
}
// building where clause
if ($normal_conditions) {
$where_clause = '(' . implode(') OR (', $normal_conditions) . ')';
}
else {
$where_clause = '1';
}
if ($plus_conditions) {
$where_clause = '(' . $where_clause . ') AND (' . implode(') AND (', $plus_conditions) . ')';
}
if ($minus_conditions) {
$where_clause = '(' . $where_clause . ') AND (' . implode(') AND (', $minus_conditions) . ')';
}
return $where_clause;
}
/**
* Returns additional information about search field
*
* @param kDBList $object
* @param string $field_name
* @return Array
*/
function _getFieldInformation(&$object, $field_name)
{
$sql_filter_type = $object->isVirtualField($field_name) ? 'having' : 'where';
$field_options = $object->GetFieldOptions($field_name);
$table_name = '';
$field_type = isset($field_options['type']) ? $field_options['type'] : 'string';
if (preg_match('/(.*)\.(.*)/', $field_name, $regs)) {
$table_name = '`'.$regs[1].'`.'; // field from external table
$field_name = $regs[2];
}
elseif ($sql_filter_type == 'where') {
$table_name = '`'.$object->TableName.'`.'; // field from local table
}
$table_name = ($sql_filter_type == 'where') ? $table_name : '';
// replace wid inside table name to WID_MARK constant value
$is_temp_table = preg_match('/(.*)'.TABLE_PREFIX.'ses_'.$this->Application->GetSID().'(_[\d]+){0,1}_edit_(.*)/', $table_name, $regs);
if ($is_temp_table) {
$table_name = $regs[1].TABLE_PREFIX.'ses_'.EDIT_MARK.'_edit_'.$regs[3]; // edit_mark will be replaced with sid[_main_wid] in AddFilters
}
return Array ($field_name, $field_type, $table_name, $sql_filter_type);
}
/**
* Removes stop words from keyword
*
* @param string $keyword
* @return string
*/
function _removeStopWords($keyword)
{
static $stop_words = Array ();
if (!$stop_words) {
$sql = 'SELECT StopWord
FROM ' . $this->Application->getUnitOption('stop-word', 'TableName') . '
ORDER BY LENGTH(StopWord) DESC, StopWord ASC';
$stop_words = $this->Conn->GetCol($sql);
foreach ($stop_words as $index => $stop_word) {
$stop_words[$index] = '/(^| )' . preg_quote($stop_word, '/') . '( |$)/';
}
}
$keyword = preg_replace($stop_words, ' ', $keyword);
return trim( preg_replace('/[ ]+/', ' ', $keyword) );
}
/**
* Performs new search on a given grid
*
* @param kEvent $event
* @return void
* @access public
*/
- public function performSearch(&$event)
+ public function performSearch($event)
{
$object =& $event->getObject();
/* @var $object kDBItem */
// process search keyword
$search_keyword = $this->Application->GetVar($event->getPrefixSpecial(true) . '_search_keyword');
$this->Application->StoreVar($event->getPrefixSpecial() . '_search_keyword', $search_keyword);
$custom_filter = $this->processCustomFilters($event);
if ( !$search_keyword && $custom_filter === false ) {
$this->resetSearch($event);
return ;
}
if ( $search_keyword ) {
$this->processAutomaticFilters($event, $search_keyword, $custom_filter);
}
}
/**
* Creates filtering sql clauses based on given search restrictions
*
* @param kEvent $event
* @param string $search_keyword
* @param Array $custom_filter
* @return void
*/
- function processAutomaticFilters(&$event, $search_keyword, $custom_filter)
+ function processAutomaticFilters($event, $search_keyword, $custom_filter)
{
$grid_name = $this->Application->GetVar('grid_name');
$grids = $this->Application->getUnitOption($event->Prefix, 'Grids');
$search_fields = array_keys($grids[$grid_name]['Fields']);
$search_filter = Array();
$object =& $event->getObject();
/* @var $object kDBList */
foreach ($search_fields as $search_field) {
$custom_search = isset($custom_filter[$search_field]);
$filter_data = $this->getSearchClause($object, $search_field, $search_keyword, $custom_search);
if ($filter_data) {
$search_filter[$search_field] = $filter_data;
}
else {
unset($search_filter[$search_field]);
}
}
$this->Application->StoreVar($event->getPrefixSpecial().'_search_filter', serialize($search_filter) );
}
/**
* Returns search clause for any particular field
*
* @param kDBList $object
* @param string $field_name
* @param string $search_keyword what we are searching (false, when building custom filter clause)
* @param string $custom_search already found using custom filter
* @return Array
*/
function getSearchClause(&$object, $field_name, $search_keyword, $custom_search)
{
if ($object->isVirtualField($field_name) && !$object->isCalculatedField($field_name)) {
// Virtual field, that is shown in grid, but it doesn't have corresponding calculated field.
// Happens, when field value is calculated on the fly (during grid display) and it is not searchable.
return '';
}
$search_keywords = $this->splitKeyword($search_keyword);
list ($field_name, $field_type, $table_name, $sql_filter_type) = $this->_getFieldInformation($object, $field_name);
$filter_value = '';
// get field clause by formatter name and/or parameters
$field_options = $object->GetFieldOptions($field_name);
$formatter = getArrayValue($field_options, 'formatter');
switch ($formatter) {
case 'kOptionsFormatter':
$search_keys = Array();
if ($custom_search === false) {
// if keywords passed through simple search filter (on each grid)
$use_phrases = getArrayValue($field_options, 'use_phrases');
$multiple = array_key_exists('multiple', $field_options) && $field_options['multiple'];
foreach ($field_options['options'] as $key => $val) {
$match_to = mb_strtolower($use_phrases ? $this->Application->Phrase($val) : $val);
foreach ($search_keywords as $keyword => $sign) {
// doesn't support wildcards
if (strpos($match_to, mb_strtolower($keyword)) === false) {
if ($sign == '+') {
$filter_value = $table_name.'`'.$field_name.'` = NULL';
break;
}
else {
continue;
}
}
if ($sign == '+' || $sign == '') {
// don't add single quotes to found option ids when multiselect (but escape string anyway)
$search_keys[$key] = $multiple ? $this->Conn->escape($key) : $this->Conn->qstr($key);
}
elseif($sign == '-') {
// if same value if found as exclusive too, then remove from search result
unset($search_keys[$key]);
}
}
}
}
if ($search_keys) {
if ($multiple) {
$filter_value = $table_name.'`'.$field_name.'` LIKE "%|' . implode('|%" OR ' . $table_name.'`'.$field_name.'` LIKE "%|', $search_keys) . '|%"';
}
else {
$filter_value = $table_name.'`'.$field_name.'` IN ('.implode(',', $search_keys).')';
}
}
$field_processed = true;
break;
case 'kDateFormatter':
// if date is searched using direct filter, then do nothing here, otherwise search using LIKE clause
$field_processed = ($custom_search !== false) ? true : false;
break;
default:
$field_processed = false;
break;
}
// if not already processed by formatter, then get clause by field type
if (!$field_processed && $search_keywords) {
switch($field_type)
{
case 'int':
case 'integer':
case 'numeric':
$search_keys = Array();
foreach ($search_keywords as $keyword => $sign) {
if (!is_numeric($keyword) || ($sign == '-')) {
continue;
}
$search_keys[] = $this->Conn->qstr($keyword);
}
if ($search_keys) {
$filter_value = $table_name.'`'.$field_name.'` IN ('.implode(',', $search_keys).')';
}
break;
case 'double':
case 'float':
case 'real':
$search_keys = Array();
foreach ($search_keywords as $keyword => $sign) {
$keyword = str_replace(',', '.', $keyword);
if (!is_numeric($keyword) || ($sign == '-')) continue;
$search_keys[] = 'ABS('.$table_name.'`'.$field_name.'` - '.$this->Conn->qstr($keyword).') <= 0.0001';
}
if ($search_keys) {
$filter_value = '('.implode(') OR (', $search_keys).')';
}
break;
case 'string':
$filter_value = $this->buildWhereClause($search_keyword, Array($table_name.'`'.$field_name.'`'));
break;
}
}
if ($filter_value) {
return Array('type' => $sql_filter_type, 'value' => $filter_value);
}
return false;
}
/**
* Processes custom filters from submit
*
* @param kEvent $event
* @return Array|bool
*/
- function processCustomFilters(&$event)
+ function processCustomFilters($event)
{
$grid_name = $this->Application->GetVar('grid_name');
// update "custom filter" with values from submit: begin
$view_name = $this->Application->RecallVar($event->getPrefixSpecial().'_current_view');
$custom_filters = $this->Application->RecallPersistentVar($event->getPrefixSpecial().'_custom_filter.'.$view_name/*, ALLOW_DEFAULT_SETTINGS*/);
if ($custom_filters) {
$custom_filters = unserialize($custom_filters);
$custom_filter = isset($custom_filters[$grid_name]) ? $custom_filters[$grid_name] : Array ();
}
else {
$custom_filter = Array ();
}
// submit format custom_filters[prefix_special][field]
$submit_filters = $this->Application->GetVar('custom_filters');
if ($submit_filters) {
$submit_filters = getArrayValue($submit_filters, $event->getPrefixSpecial(), $grid_name);
if ($submit_filters) {
foreach ($submit_filters as $field_name => $field_options) {
list ($filter_type, $field_value) = each($field_options);
$is_empty = strlen(is_array($field_value) ? implode('', $field_value) : $field_value) == 0;
if ($is_empty) {
if (isset($custom_filter[$field_name])) {
// use isset, because non-existing key will cause "php notice"!
unset($custom_filter[$field_name][$filter_type]); // remove filter
if (!$custom_filter[$field_name]) {
// if no filters left for field, then delete record at all
unset($custom_filter[$field_name]);
}
}
}
else {
$custom_filter[$field_name][$filter_type]['submit_value'] = $field_value;
}
}
}
}
if ($custom_filter) {
$custom_filters[$grid_name] = $custom_filter;
}
else {
unset($custom_filters[$grid_name]);
}
// update "custom filter" with values from submit: end
if (!$custom_filter) {
// in case when no filters specified, there are nothing to process
$this->Application->StorePersistentVar($event->getPrefixSpecial().'_custom_filter.'.$view_name, serialize($custom_filters) );
return false;
}
$object =& $event->getObject(); // don't recall it each time in getCustomFilterSearchClause
$grid_info = $this->Application->getUnitOption($event->Prefix.'.'.$grid_name, 'Grids');
foreach ($custom_filter as $field_name => $field_options) {
list ($filter_type, $field_options) = each($field_options);
$field_options['grid_options'] = $grid_info['Fields'][$field_name];
$field_options = $this->getCustomFilterSearchClause($object, $field_name, $filter_type, $field_options);
if ($field_options['value']) {
unset($field_options['grid_options']);
$custom_filter[$field_name][$filter_type] = $field_options;
}
}
$custom_filters[$grid_name] = $custom_filter;
$this->Application->StorePersistentVar($event->getPrefixSpecial().'_custom_filter.'.$view_name, serialize($custom_filters) );
return $custom_filter;
}
/**
* Checks, that range filters "To" part is defined for given grid
*
* @param string $prefix_special
* @param string $grid_name
* @return bool
*/
function rangeFiltersUsed($prefix_special, $grid_name)
{
static $cache = Array ();
$cache_key = $prefix_special . $grid_name;
if (array_key_exists($cache_key, $cache)) {
return $cache[$cache_key];
}
$view_name = $this->Application->RecallVar($prefix_special . '_current_view');
$custom_filters = $this->Application->RecallPersistentVar($prefix_special . '_custom_filter.' . $view_name/*, ALLOW_DEFAULT_SETTINGS*/);
if (!$custom_filters) {
// filters not defined for given prefix
$cache[$cache_key] = false;
return false;
}
$custom_filters = unserialize($custom_filters);
if (!is_array($custom_filters) || !array_key_exists($grid_name, $custom_filters)) {
// filters not defined for given grid
$cache[$cache_key] = false;
return false;
}
$range_filter_defined = false;
$custom_filter = $custom_filters[$grid_name];
foreach ($custom_filter as $field_name => $field_options) {
list ($filter_type, $field_options) = each($field_options);
if (strpos($filter_type, 'range') === false) {
continue;
}
$to_value = (string)$field_options['submit_value']['to'];
if ($to_value !== '') {
$range_filter_defined = true;
break;
}
}
$cache[$cache_key] = $range_filter_defined;
return $range_filter_defined;
}
/**
* Return numeric range filter value + checking that it's number
*
* @param Array $value array containing range filter value
* @return unknown
*/
function getRangeValue($value)
{
// fix user typing error, since MySQL only sees "." as decimal separator
$value = str_replace(',', '.', $value);
return strlen($value) && is_numeric($value) ? $this->Conn->qstr($value) : false;
}
/**
* Returns filter clause
*
* @param kDBItem $object
* @param string $field_name
* @param string $filter_type
* @param Array $field_options
* @return Array
*/
function getCustomFilterSearchClause(&$object, $field_name, $filter_type, $field_options)
{
// this is usually used for mutlilingual fields and date fields
if (isset($field_options['grid_options']['sort_field'])) {
$field_name = $field_options['grid_options']['sort_field'];
}
list ($field_name, $field_type, $table_name, $sql_filter_type) = $this->_getFieldInformation($object, $field_name);
$filter_value = '';
switch ($filter_type) {
case 'range':
$from = $this->getRangeValue($field_options['submit_value']['from']);
$to = $this->getRangeValue($field_options['submit_value']['to']);
if ( $from !== false && $to !== false ) {
// add range filter
$filter_value = $table_name . '`' . $field_name . '` >= ' . $from . ' AND ' . $table_name . '`' . $field_name . '` <= ' . $to;
}
elseif ( $field_type == 'int' || $field_type == 'integer' ) {
if ( $from !== false ) {
// add equals filter on $from
$filter_value = $table_name . '`' . $field_name . '` = ' . $from;
}
elseif ( $to !== false ) {
// add equals filter on $to
$filter_value = $table_name . '`' . $field_name . '` = ' . $to;
}
}
else {
// MySQL can't compare values in "float" type columns using "=" operator
if ( $from !== false ) {
// add equals filter on $from
$filter_value = 'ABS(' . $table_name . '`' . $field_name . '` - ' . $from . ') <= 0.0001';
}
elseif ( $to !== false ) {
// add equals filter on $to
$filter_value = 'ABS(' . $table_name . '`' . $field_name . '` - ' . $to . ') <= 0.0001';
}
}
break;
case 'date_range':
$from = $this->processRangeField($object, $field_name, $field_options['submit_value'], 'from');
$to = $this->processRangeField($object, $field_name, $field_options['submit_value'], 'to');
$day_seconds = 23 * 60 * 60 + 59 * 60 + 59;
if ($from !== false && $to === false) {
$from = strtotime(date('Y-m-d', $from) . ' 00:00:00', $from); // reset to morning
$to = $from + $day_seconds;
}
elseif ($from === false && $to !== false) {
$to = strtotime(date('Y-m-d', $to) . ' 23:59:59', $to); // reset to evening
$from = $to - $day_seconds;
}
if ($from !== false && $to !== false) {
$filter_value = $table_name.'`'.$field_name.'` >= '.$from.' AND '.$table_name.'`'.$field_name.'` <= '.$to;
}
break;
case 'equals':
case 'options':
$field_value = strlen($field_options['submit_value']) ? $this->Conn->qstr($field_options['submit_value']) : false;
if ($field_value) {
$filter_value = $table_name.'`'.$field_name.'` = '.$field_value;
}
break;
case 'picker':
$field_value = strlen($field_options['submit_value']) ? $this->Conn->escape($field_options['submit_value']) : false;
if ($field_value) {
$filter_value = $table_name.'`'.$field_name.'` LIKE "%|'.$field_value.'|%"';
}
break;
case 'multioptions':
$field_value = $field_options['submit_value'];
if ( $field_value ) {
$field_value = explode('|', substr($field_value, 1, -1));
$multiple = $object->GetFieldOption($field_name, 'multiple');
$field_value = $this->Conn->qstrArray($field_value, $multiple ? 'escape' : 'qstr');
if ( $multiple ) {
$filter_value = $table_name . '`' . $field_name . '` LIKE "%|' . implode('|%" OR ' . $table_name . '`' . $field_name . '` LIKE "%|', $field_value) . '|%"';
}
else {
$filter_value = $table_name . '`' . $field_name . '` IN (' . implode(',', $field_value) . ')';
}
}
break;
case 'like':
$filter_value = $this->buildWhereClause($field_options['submit_value'], Array($table_name.'`'.$field_name.'`'));
break;
default:
break;
}
$field_options['sql_filter_type'] = $sql_filter_type;
$field_options['value'] = $filter_value;
return $field_options;
}
/**
* Enter description here...
*
* @param kdbItem $object
* @param string $search_field
* @param string $value
* @param string $type
*/
function processRangeField(&$object, $search_field, $value, $type)
{
if ( !strlen($value[$type]) ) {
return false;
}
$options = $object->GetFieldOptions($search_field);
$dt_separator = array_key_exists('date_time_separator', $options) ? $options['date_time_separator'] : ' ';
$value[$type] = trim($value[$type], $dt_separator); // trim any
$tmp_value = explode($dt_separator, $value[$type], 2);
if ( count($tmp_value) == 1 ) {
$time_format = $this->_getInputTimeFormat($options);
if ( $time_format ) {
// time is missing, but time format available -> guess time and add to date
$time = ($type == 'from') ? adodb_mktime(0, 0, 0) : adodb_mktime(23, 59, 59);
$time = adodb_date($time_format, $time);
$value[$type] .= $dt_separator . $time;
}
}
$formatter =& $this->Application->recallObject($options['formatter']);
/* @var $formatter kFormatter */
$value_ts = $formatter->Parse($value[$type], $search_field, $object);
if ( $object->GetErrorPseudo($search_field) ) {
// invalid format -> ignore this date in search
$object->RemoveError($search_field);
return false;
}
return $value_ts;
}
/**
* Returns InputTimeFormat using given field options
*
* @param Array $field_options
* @return string
*/
function _getInputTimeFormat($field_options)
{
if ( array_key_exists('input_time_format', $field_options) ) {
return $field_options['input_time_format'];
}
$lang_current =& $this->Application->recallObject('lang.current');
/* @var $lang_current LanguagesItem */
return $lang_current->GetDBField('InputTimeFormat');
}
/**
* Resets current search
*
* @param kEvent $event
*/
- function resetSearch(&$event)
+ function resetSearch($event)
{
$this->Application->RemoveVar($event->getPrefixSpecial().'_search_filter');
$this->Application->RemoveVar($event->getPrefixSpecial().'_search_keyword');
$view_name = $this->Application->RecallVar($event->getPrefixSpecial().'_current_view');
$this->Application->RemovePersistentVar($event->getPrefixSpecial().'_custom_filter.'.$view_name);
}
/**
* Creates filters based on "types" & "except" parameters from PrintList
*
* @param kEvent $event
* @param Array $type_clauses
* @param string $types
* @param string $except_types
*/
- function SetComplexFilter(&$event, &$type_clauses, $types, $except_types)
+ function SetComplexFilter($event, &$type_clauses, $types, $except_types)
{
$includes_or_filter =& $this->Application->makeClass('kMultipleFilter', Array (kDBList::FLT_TYPE_OR));
/* @var $includes_or_filter kMultipleFilter */
$excepts_and_filter =& $this->Application->makeClass('kMultipleFilter', Array (kDBList::FLT_TYPE_AND));
/* @var $excepts_and_filter kMultipleFilter */
$includes_or_filter_h =& $this->Application->makeClass('kMultipleFilter', Array (kDBList::FLT_TYPE_OR));
/* @var $includes_or_filter_h kMultipleFilter */
$excepts_and_filter_h =& $this->Application->makeClass('kMultipleFilter', Array (kDBList::FLT_TYPE_AND));
/* @var $excepts_and_filter_h kMultipleFilter */
if ( $types ) {
$types = explode(',', $types);
foreach ($types as $type) {
$type = trim($type);
if ( isset($type_clauses[$type]) ) {
if ( $type_clauses[$type]['having_filter'] ) {
$includes_or_filter_h->addFilter('filter_' . $type, $type_clauses[$type]['include']);
}
else {
$includes_or_filter->addFilter('filter_' . $type, $type_clauses[$type]['include']);
}
}
}
}
if ( $except_types ) {
$except_types = explode(',', $except_types);
foreach ($except_types as $type) {
$type = trim($type);
if ( isset($type_clauses[$type]) ) {
if ( $type_clauses[$type]['having_filter'] ) {
$excepts_and_filter_h->addFilter('filter_' . $type, $type_clauses[$type]['except']);
}
else {
$excepts_and_filter->addFilter('filter_' . $type, $type_clauses[$type]['except']);
}
}
}
}
$object =& $event->getObject();
/* @var $object kDBList */
$object->addFilter('includes_filter', $includes_or_filter);
$object->addFilter('excepts_filter', $excepts_and_filter);
$object->addFilter('includes_filter_h', $includes_or_filter_h, kDBList::HAVING_FILTER);
$object->addFilter('excepts_filter_h', $excepts_and_filter_h, kDBList::HAVING_FILTER);
}
}
\ No newline at end of file
Index: branches/5.2.x/core/units/helpers/ajax_form_helper.php
===================================================================
--- branches/5.2.x/core/units/helpers/ajax_form_helper.php (revision 15129)
+++ branches/5.2.x/core/units/helpers/ajax_form_helper.php (revision 15130)
@@ -1,85 +1,85 @@
<?php
class AjaxFormHelper extends kHelper {
/**
* Sets error info as parameters in response object
* Expects that event status is not erSUCCESS
*
* @param kEvent $event
* @param Array $response
*/
- public function prepareJSONErrors(&$event, &$response)
+ public function prepareJSONErrors($event, &$response)
{
$object =& $event->getObject();
/* @var $object kDBItem */
$response['status'] = 'FAILED';
$response['field_errors'] = $this->getErrorMessages($object);
}
/**
* Returns object errors
*
* @param kDBItem $object
* @return Array
*/
public function getErrorMessages(&$object)
{
$error_msgs = Array ();
$field_errors = array_keys( $object->GetFieldErrors() );
foreach ($field_errors as $field) {
if ( !$object->GetErrorPseudo($field) ) {
continue;
}
if ( $object->GetFieldOption($field, 'formatter') == 'kMultiLanguage') {
$field = 'l' . $this->Application->GetVar('m_lang') . '_' . $field;
}
$error_field = $object->GetFieldOption($field, 'error_field', false, $field);
$error_msgs[$field] = $object->GetErrorMsg($error_field);
}
return $error_msgs;
}
/**
* Sends JSON-encoded response as event result to the browser
*
* @param kEvent $event
* @param Array $response
*/
- public function sendResponse(&$event, $response)
+ public function sendResponse($event, $response)
{
$json_helper =& $this->Application->recallObject('JSONHelper');
/* @var $json_helper JSONHelper */
echo $json_helper->encode($response);
$event->status = kEvent::erSTOP;
}
/**
* Calls given event and returns nice JSON output
*
* @param kEvent $event
* @param string $call_event
* @param Array $params
*/
- public function transitEvent(&$event, $call_event, $params = Array ())
+ public function transitEvent($event, $call_event, $params = Array ())
{
$params['status'] = 'OK';
$event->CallSubEvent($call_event);
if ( $event->status != kEvent::erSUCCESS ) {
$this->prepareJSONErrors($event, $params);
}
else {
$params = array_merge($params, $event->getRedirectParams());
}
$this->sendResponse($event, $params);
}
}
\ No newline at end of file
Index: branches/5.2.x/core/units/helpers/user_helper.php
===================================================================
--- branches/5.2.x/core/units/helpers/user_helper.php (revision 15129)
+++ branches/5.2.x/core/units/helpers/user_helper.php (revision 15130)
@@ -1,598 +1,598 @@
<?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 UserHelper extends kHelper {
/**
* Event to be used during login processings
*
* @var kEvent
*/
var $event = null;
/**
* Performs user login and returns the result
*
* @param string $username
* @param string $password
* @param bool $dry_run
* @param bool $remember_login
* @param string $remember_login_cookie
* @return int
*/
function loginUser($username, $password, $dry_run = false, $remember_login = false, $remember_login_cookie = '')
{
if (!isset($this->event)) {
$this->event = new kEvent('u:OnLogin');
}
if (!$password && !$remember_login_cookie) {
return LoginResult::INVALID_PASSWORD;
}
$object =& $this->getUserObject();
// process "Save Username" checkbox
if ($this->Application->isAdmin) {
$save_username = $this->Application->GetVar('cb_save_username') ? $username : '';
$this->Application->Session->SetCookie('save_username', $save_username, strtotime('+1 year'));
// cookie will be set on next refresh, but refresh won't occur if
// login error present, so duplicate cookie in kHTTPQuery
$this->Application->SetVar('save_username', $save_username);
}
// logging in "root" (admin only)
$super_admin = ($username == 'super-root') && $this->verifySuperAdmin();
if ($this->Application->isAdmin && ($username == 'root') || ($super_admin && $username == 'super-root')) {
$root_password = $this->Application->ConfigValue('RootPass');
$password_formatter =& $this->Application->recallObject('kPasswordFormatter');
/* @var $password_formatter kPasswordFormatter */
if ($root_password != $password_formatter->EncryptPassword($password, 'b38')) {
return LoginResult::INVALID_PASSWORD;
}
$user_id = USER_ROOT;
$object->Clear($user_id);
$object->SetDBField('Username', 'root');
if (!$dry_run) {
$this->loginUserById($user_id, $remember_login_cookie);
if ($super_admin) {
$this->Application->StoreVar('super_admin', 1);
}
// reset counters
$this->Application->resetCounters('UserSessions');
$this->_processLoginRedirect('root', $password);
$this->_processInterfaceLanguage();
}
return LoginResult::OK;
}
$user_id = $this->getUserId($username, $password, $remember_login_cookie);
if ($user_id) {
$object->Load($user_id);
if (!$this->checkBanRules($object)) {
return LoginResult::BANNED;
}
if ($object->GetDBField('Status') == STATUS_ACTIVE) {
if ( !$this->checkLoginPermission() ) {
return LoginResult::NO_PERMISSION;
}
if (!$dry_run) {
$this->loginUserById($user_id, $remember_login_cookie);
if ($remember_login) {
// remember username & password when "Remember Login" checkbox us checked (when user is using login form on Front-End)
$this->Application->Session->SetCookie('remember_login', $username . '|' . md5($password), strtotime('+1 month'));
}
if (!$remember_login_cookie) {
// reset counters
$this->Application->resetCounters('UserSessions');
$this->_processLoginRedirect($username, $password);
$this->_processInterfaceLanguage();
}
}
return LoginResult::OK;
}
else {
$pending_template = $this->Application->GetVar('pending_disabled_template');
if ($pending_template !== false && !$dry_run) {
// when user found, but it's not yet approved redirect hit to notification template
$this->event->redirect = $pending_template;
return LoginResult::OK;
}
else {
// when no notification template given return an error
return LoginResult::INVALID_PASSWORD;
}
}
}
if (!$dry_run) {
$this->event->SetRedirectParam('pass', 'all');
// $this->event->SetRedirectParam('pass_category', 1); // to test
}
return LoginResult::INVALID_PASSWORD;
}
/**
* Login user by it's id
*
* @param int $user_id
* @param bool $remember_login_cookie
*/
function loginUserById($user_id, $remember_login_cookie = false)
{
$object =& $this->getUserObject();
$this->Application->StoreVar('user_id', $user_id);
$this->Application->SetVar('u.current_id', $user_id);
$this->Application->Session->SetField('PortalUserId', $user_id);
if ($user_id != USER_ROOT) {
$groups = $this->Application->RecallVar('UserGroups');
$this->Application->Session->SetField('GroupId', reset( explode(',', $groups) ));
$this->Application->Session->SetField('GroupList', $groups);
$this->Application->Session->SetField('TimeZone', $object->GetDBField('TimeZone'));
}
$this->Application->LoadPersistentVars();
if (!$remember_login_cookie) {
// don't change last login time when auto-login is used
$this_login = (int)$this->Application->RecallPersistentVar('ThisLogin');
$this->Application->StorePersistentVar('LastLogin', $this_login);
$this->Application->StorePersistentVar('ThisLogin', adodb_mktime());
}
- $this->Application->HandleEvent($dummy, 'u:OnAfterLogin');
+ $this->Application->HandleEvent(new kEvent('u:OnAfterLogin'));
}
/**
* Checks login permission
*
* @return bool
*/
function checkLoginPermission()
{
$object =& $this->getUserObject();
$ip_restrictions = $object->GetDBField('IPRestrictions');
if ( $ip_restrictions && !$this->Application->isDebugMode() && !kUtil::ipMatch($ip_restrictions, "\n") ) {
return false;
}
$groups = $object->getMembershipGroups(true);
if ( !$groups ) {
$groups = Array ();
}
$default_group = $this->getUserTypeGroup();
if ( $default_group !== false ) {
array_push($groups, $default_group);
}
// store groups, because kApplication::CheckPermission will use them!
array_push($groups, $this->Application->ConfigValue('User_LoggedInGroup'));
$groups = array_unique($groups);
$this->Application->StoreVar('UserGroups', implode(',', $groups), true); // true for optional
return $this->Application->CheckPermission($this->Application->isAdmin ? 'ADMIN' : 'LOGIN', 1);
}
/**
* Returns default user group for it's type
*
* @return bool|string
* @access protected
*/
protected function getUserTypeGroup()
{
$group_id = false;
$object =& $this->getUserObject();
if ( $object->GetDBField('UserType') == UserType::USER ) {
$group_id = $this->Application->ConfigValue('User_NewGroup');
}
elseif ( $object->GetDBField('UserType') == UserType::ADMIN ) {
$group_id = $this->Application->ConfigValue('User_AdminGroup');
}
$ip_restrictions = $this->getGroupsWithIPRestrictions();
if ( !isset($ip_restrictions[$group_id]) || kUtil::ipMatch($ip_restrictions[$group_id], "\n") ) {
return $group_id;
}
return false;
}
/**
* Returns groups with IP restrictions
*
* @return Array
* @access public
*/
public function getGroupsWithIPRestrictions()
{
static $cache = null;
if ( $this->Application->isDebugMode() ) {
return Array ();
}
if ( !isset($cache) ) {
$sql = 'SELECT IPRestrictions, GroupId
FROM ' . TABLE_PREFIX . 'UserGroups
WHERE IPRestrictions IS NOT NULL';
$cache = $this->Conn->GetCol($sql, 'GroupId');
}
return $cache;
}
/**
* Performs user logout
*
*/
function logoutUser()
{
if (!isset($this->event)) {
$this->event = new kEvent('u:OnLogout');
}
$sync_manager =& $this->Application->recallObject('UsersSyncronizeManager', null, Array(), Array ('InPortalSyncronize'));
/* @var $sync_manager UsersSyncronizeManager */
$sync_manager->performAction('LogoutUser');
- $this->Application->HandleEvent($dummy, 'u:OnBeforeLogout');
+ $this->Application->HandleEvent(new kEvent('u:OnBeforeLogout'));
$user_id = USER_GUEST;
$this->Application->SetVar('u.current_id', $user_id);
$object =& $this->Application->recallObject('u.current', null, Array('skip_autoload' => true));
/* @var $object UsersItem */
$object->Load($user_id);
$this->Application->DestroySession();
$this->Application->StoreVar('user_id', $user_id, true);
$this->Application->Session->SetField('PortalUserId', $user_id);
$group_list = $this->Application->ConfigValue('User_GuestGroup') . ',' . $this->Application->ConfigValue('User_LoggedInGroup');
$this->Application->StoreVar('UserGroups', $group_list, true);
$this->Application->Session->SetField('GroupList', $group_list);
if ($this->Application->ConfigValue('UseJSRedirect')) {
$this->event->SetRedirectParam('js_redirect', 1);
}
$this->Application->resetCounters('UserSessions');
$this->Application->Session->SetCookie('remember_login', '', strtotime('-1 hour'));
// don't pass user prefix on logout, since resulting url will have broken "env"
$this->event->SetRedirectParam('pass', MOD_REWRITE ? 'm' : 'all');
}
/**
* Returns user id based on given criteria
*
* @param string $username
* @param string $password
* @param string $remember_login_cookie
* @return int
*/
function getUserId($username, $password, $remember_login_cookie)
{
$password = md5($password);
if ($remember_login_cookie) {
list ($username, $password) = explode('|', $remember_login_cookie); // 0 - username, 1 - md5(password)
}
$sql = 'SELECT PortalUserId
FROM ' . TABLE_PREFIX . 'Users
WHERE (Email = %1$s OR Username = %1$s) AND (Password = %2$s)';
return $this->Conn->GetOne( sprintf($sql, $this->Conn->qstr($username), $this->Conn->qstr($password) ) );
}
/**
* Process all required data and redirect logged-in user
*
* @param string $username
* @param string $password
*/
function _processLoginRedirect($username, $password)
{
// set next template
$next_template = $this->Application->GetVar('next_template');
if ($next_template) {
$this->event->redirect = $next_template;
}
// process IIS redirect
if ($this->Application->ConfigValue('UseJSRedirect')) {
$this->event->SetRedirectParam('js_redirect', 1);
}
// synchronize login
$sync_manager =& $this->Application->recallObject('UsersSyncronizeManager', null, Array(), Array ('InPortalSyncronize'));
/* @var $sync_manager UsersSyncronizeManager */
$sync_manager->performAction('LoginUser', $username, $password);
}
/**
* Sets correct interface language after successful login, based on user settings
*
* @return void
* @access protected
*/
protected function _processInterfaceLanguage()
{
$language_field = $this->Application->isAdmin ? 'AdminLanguage' : 'FrontLanguage';
$primary_language_field = $this->Application->isAdmin ? 'AdminInterfaceLang' : 'PrimaryLang';
$is_root = $this->Application->RecallVar('user_id') == USER_ROOT;
$object =& $this->getUserObject();
$user_language_id = $is_root ? $this->Application->RecallPersistentVar($language_field) : $object->GetDBField($language_field);
$sql = 'SELECT LanguageId, IF(LanguageId = ' . (int)$user_language_id . ', 2, ' . $primary_language_field . ') AS SortKey
FROM ' . TABLE_PREFIX . 'Languages
WHERE Enabled = 1
HAVING SortKey <> 0
ORDER BY SortKey DESC';
$language_info = $this->Conn->GetRow($sql);
$language_id = $language_info && $language_info['LanguageId'] ? $language_info['LanguageId'] : $user_language_id;
if ( $user_language_id != $language_id ) {
// first login OR language was deleted or disabled
if ( $is_root ) {
$this->Application->StorePersistentVar($language_field, $language_id);
}
else {
$object->SetDBField($language_field, $language_id);
$object->Update();
}
}
$this->event->SetRedirectParam('m_lang', $language_id); // data
$this->Application->Session->SetField('Language', $language_id); // interface
}
/**
* Checks that user is allowed to use super admin mode
*
* @return bool
*/
function verifySuperAdmin()
{
$sa_mode = kUtil::ipMatch(defined('SA_IP') ? SA_IP : '');
return $sa_mode || $this->Application->isDebugMode();
}
/**
* Returns user object, used during login processing
*
* @return UsersItem
* @access public
*/
public function &getUserObject()
{
$prefix_special = $this->Application->isAdmin ? 'u.current' : 'u'; // "u" used on front not to change theme
$object =& $this->Application->recallObject($prefix_special, null, Array('skip_autoload' => true));
/* @var $object UsersItem */
return $object;
}
/**
* Checks, if given user fields matches at least one of defined ban rules
*
* @param kDBItem $object
* @return bool
*/
function checkBanRules(&$object)
{
$table = $this->Application->getUnitOption('ban-rule', 'TableName');
if (!$this->Conn->TableFound($table)) {
// when ban table not found -> assume user is ok by default
return true;
}
$sql = 'SELECT *
FROM ' . $table . '
WHERE ItemType = 6 AND Status = ' . STATUS_ACTIVE . '
ORDER BY Priority DESC';
$rules = $this->Conn->Query($sql);
$found = false;
foreach ($rules as $rule) {
$field = $rule['ItemField'];
$this_value = mb_strtolower( $object->GetDBField($field) );
$test_value = mb_strtolower( $rule['ItemValue'] );
switch ( $rule['ItemVerb'] ) {
case 1: // is
if ($this_value == $test_value) {
$found = true;
}
break;
case 2: // is not
if ($this_value != $test_value) {
$found = true;
}
break;
case 3: // contains
if ( strstr($this_value, $test_value) ) {
$found = true;
}
break;
case 4: // not contains
if ( !strstr($this_value, $test_value) ) {
$found = true;
}
break;
case 7: // exists
if ( strlen($this_value) > 0 ) {
$found = true;
}
break;
case 8: // unique
if ( $this->_checkValueExist($field, $this_value) ) {
$found = true;
}
break;
}
if ( $found ) {
// check ban rules, until one of them matches
if ( $rule['RuleType'] ) {
// invert rule type
$found = false;
}
break;
}
}
return !$found;
}
/**
* Checks if value is unique in Users table against the specified field
*
* @param string $field
* @param string $value
* @return string
*/
function _checkValueExist($field, $value)
{
$sql = 'SELECT *
FROM ' . $this->Application->getUnitOption('u', 'TableName') . '
WHERE '. $field .' = ' . $this->Conn->qstr($value);
return $this->Conn->GetOne($sql);
}
public function validateUserCode($user_code, $code_type, $expiration_timeout = null)
{
$expiration_timeouts = Array (
'forgot_password' => 'config:Users_AllowReset',
'activation' => 'config:UserEmailActivationTimeout',
'verify_email' => 'config:Users_AllowReset',
'custom' => '',
);
if ( !$user_code ) {
return 'code_is_not_valid';
}
$sql = 'SELECT PwRequestTime, PortalUserId
FROM ' . TABLE_PREFIX . 'Users
WHERE PwResetConfirm = ' . $this->Conn->qstr( trim($user_code) );
$user_info = $this->Conn->GetRow($sql);
if ( $user_info === false ) {
return 'code_is_not_valid';
}
$expiration_timeout = isset($expiration_timeout) ? $expiration_timeout : $expiration_timeouts[$code_type];
if ( preg_match('/^config:(.*)$/', $expiration_timeout, $regs) ) {
$expiration_timeout = $this->Application->ConfigValue( $regs[1] );
}
if ( $expiration_timeout && $user_info['PwRequestTime'] < strtotime('-' . $expiration_timeout . ' minutes') ) {
return 'code_expired';
}
return $user_info['PortalUserId'];
}
/**
* Restores user's email, returns error label, if error occurred
*
* @param string $hash
* @return string
* @access public
*/
public function restoreEmail($hash)
{
if ( !preg_match('/^[a-f0-9]{32}$/', $hash) ) {
return 'invalid_hash';
}
$sql = 'SELECT PortalUserId, PrevEmails
FROM ' . TABLE_PREFIX . 'Users
WHERE PrevEmails LIKE ' . $this->Conn->qstr('%' . $hash . '%');
$user_info = $this->Conn->GetRow($sql);
if ( $user_info === false ) {
return 'invalid_hash';
}
$prev_emails = $user_info['PrevEmails'];
$prev_emails = $prev_emails ? unserialize($prev_emails) : Array ();
if ( !isset($prev_emails[$hash]) ) {
return 'invalid_hash';
}
$email_to_restore = $prev_emails[$hash];
unset($prev_emails[$hash]);
$object =& $this->Application->recallObject('u.email-restore', null, Array ('skip_autoload' => true));
/* @var $object UsersItem */
$object->Load($user_info['PortalUserId']);
$object->SetDBField('PrevEmails', serialize($prev_emails));
$object->SetDBField('Email', $email_to_restore);
$object->SetDBField('EmailVerified', 1);
return $object->Update() ? '' : 'restore_impossible';
}
}
Index: branches/5.2.x/core/units/helpers/controls/minput_helper.php
===================================================================
--- branches/5.2.x/core/units/helpers/controls/minput_helper.php (revision 15129)
+++ branches/5.2.x/core/units/helpers/controls/minput_helper.php (revision 15130)
@@ -1,227 +1,227 @@
<?php
/**
* @version $Id$
* @package In-Portal
* @copyright Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
* @license GNU/GPL
* In-Portal is Open Source software.
* This means that this software may have been modified pursuant
* the GNU General Public License, and as distributed it includes
* or is derivative of works licensed under the GNU General Public License
* or other free or open source software licenses.
* See http://www.in-portal.org/license for copyright notices and details.
*/
defined('FULL_PATH') or die('restricted access!');
class MInputHelper extends kHelper {
/**
* Returns table for given prefix
*
* @param string $prefix
* @param bool $temp
* @return string
* @access protected
*/
protected function getTable($prefix, $temp = false)
{
$table_name = $this->Application->getUnitOption($prefix, 'TableName');
return $temp ? $this->Application->GetTempName($table_name, 'prefix:' . $prefix) : $table_name;
}
function prepareMInputXML($records, $use_fields)
{
$xml = '';
foreach ($records as $record) {
$xml .= '<record>';
foreach ($record as $field_name => $field_value) {
if (!in_array($field_name, $use_fields)) {
continue;
}
$xml .= '<field name="' . $field_name . '">' . htmlspecialchars($field_value) . '</field>';
}
$xml .= '</record>';
}
return $xml ? '<records>'.$xml.'</records>' : '';
}
/**
* Returns validation errors in XML format
*
* @param kDBItem $object
* @param Array $fields_hash
* @return string
*/
function prepareErrorsXML(&$object, $fields_hash)
{
$xml = '';
$errors = Array ();
foreach ($fields_hash as $field_name => $field_value) {
if (!$object->ValidateField($field_name)) {
$field_options = $object->GetFieldOptions($field_name);
$error_field = array_key_exists('error_field', $field_options) ? $field_options['error_field'] : $field_name;
$errors[$error_field] = '<field name="'.$error_field.'">'.$object->GetErrorMsg($error_field, false).'</field>';
}
}
return '<errors>'.implode('', $errors).'</errors>';
}
/**
* Validates MInput control fields
*
* @param kEvent $event
*/
- function OnValidateMInputFields(&$event)
+ function OnValidateMInputFields($event)
{
$object =& $event->getObject();
/* @var $object kDBItem */
$items_info = $this->Application->GetVar($event->getPrefixSpecial(true));
if ($items_info) {
list ($id, $field_values) = each($items_info);
foreach ($field_values as $field_name => $field_value) {
$object->SetField($field_name, $field_value);
}
$event_mapping = Array (
'AddRecord' => 'OnBeforeItemCreate',
'SaveRecord' => 'OnBeforeItemUpdate',
);
$request_type = $this->Application->GetVar('request_type');
if (array_key_exists($request_type, $event_mapping)) {
$event->CallSubEvent($event_mapping[$request_type]);
}
echo $this->prepareErrorsXML($object, $field_values);
}
$event->status = kEvent::erSTOP;
}
function parseMInputXML($xml)
{
$xml_helper =& $this->Application->recallObject('kXMLHelper');
/* @var $xml_helper kXMLHelper */
$root_node =& $xml_helper->Parse($xml);
$root_node =& $root_node->FindChild('records');
if ( !$root_node || !$root_node->firstChild ) {
return false;
}
$records = Array ();
$current_node = $root_node->firstChild;
/* @var $current_node kXMLNode */
do {
$record = Array ();
$sub_node =& $current_node->firstChild;
/* @var $current_node kXMLNode */
do {
$record[ $sub_node->Attributes['NAME'] ] = $sub_node->Data;
} while ( ($sub_node =& $sub_node->NextSibling()) );
$records[] = $record;
} while ( ($current_node =& $current_node->NextSibling()) );
return $records;
}
/**
* Loads selected values from sub_prefix to main item virtual field.
* Called from OnAfterItemLoad of main prefix.
*
* @param kEvent $event
* @param string $store_field main item's field name, to store values into
* @param string $sub_prefix prefix used to store info about selected items
* @param Array $use_fields fields, used in value string building
*/
- function LoadValues(&$event, $store_field, $sub_prefix, $use_fields)
+ function LoadValues($event, $store_field, $sub_prefix, $use_fields)
{
$object =& $event->getObject();
/* @var $object kDBItem */
$sub_item =& $this->Application->recallObject($sub_prefix, null, Array('skip_autoload' => true));
/* @var $sub_item kDBItem */
$foreign_key = $this->Application->getUnitOption($sub_prefix, 'ForeignKey');
$sql = 'SELECT *
FROM '.$this->getTable($sub_prefix, $object->IsTempTable()).'
WHERE '.$foreign_key.' = '.$object->GetID();
$selected_items = $this->Conn->Query($sql);
$field_names = array_keys( $sub_item->GetFieldValues() );
foreach ($selected_items as $key => $fields_hash) {
$sub_item->Clear();
$sub_item->SetDBFieldsFromHash($fields_hash);
// to fill *_date and *_time fields from main date fields
$sub_item->UpdateFormattersSubFields();
foreach ($field_names as $field) {
$field_options = $sub_item->GetFieldOptions($field);
$formatter = array_key_exists('formatter', $field_options) ? $field_options['formatter'] : false;
if ($formatter == 'kDateFormatter') {
$selected_items[$key][$field] = $sub_item->GetField($field, $field_options['input_format']);
}
else {
$selected_items[$key][$field] = $sub_item->GetDBField($field);
}
}
}
$object->SetDBField($store_field, $this->prepareMInputXML($selected_items, $use_fields));
}
/**
* Saves data from minput control to subitem table (used from subitem hook)
*
* @param kEvent $sub_event
* @param string $store_field
*/
function SaveValues(&$sub_event, $store_field)
{
$main_object =& $sub_event->MasterEvent->getObject();
/* @var $main_object kDBItem */
$affected_field = $main_object->GetDBField($store_field);
$object =& $this->Application->recallObject($sub_event->getPrefixSpecial(), null, Array ('skip_autoload' => true));
/* @var $object kDBItem */
$sub_table = $object->TableName;
$foreign_key = $this->Application->getUnitOption($sub_event->Prefix, 'ForeignKey');
$sql = 'DELETE FROM '.$sub_table.'
WHERE '.$foreign_key.' = '.$main_object->GetID();
$this->Conn->Query($sql);
if ($affected_field) {
$records = $this->parseMInputXML($affected_field);
$main_id = $main_object->GetID();
foreach ($records as $fields_hash) {
$object->Clear();
$fields_hash[$foreign_key] = $main_id;
$object->SetDBFieldsFromHash($fields_hash);
$object->Create();
}
}
}
}
\ No newline at end of file
Index: branches/5.2.x/core/units/helpers/controls/edit_picker_helper.php
===================================================================
--- branches/5.2.x/core/units/helpers/controls/edit_picker_helper.php (revision 15129)
+++ branches/5.2.x/core/units/helpers/controls/edit_picker_helper.php (revision 15130)
@@ -1,186 +1,186 @@
<?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 EditPickerHelper extends kHelper {
function getTable($prefix, $temp=false)
{
$table_name = $this->Application->getUnitOption($prefix, 'TableName');
return $temp ? $this->Application->GetTempName($table_name, 'prefix:'.$prefix) : $table_name;
}
/**
* Applies filter for multiple lists in inp_edit_picker control.
* Called from SetCustomQuery of prefix, that contains all available items.
*
* @param kEvent $event
* @param string $storage_field main item's field name, where values are located
*/
- function applyFilter(&$event, $storage_field)
+ function applyFilter($event, $storage_field)
{
if ($event->Special != 'selected' && $event->Special != 'available') {
return ;
}
if ($storage_field != $event->getEventParam('link_to_field')) {
return ;
}
$object =& $event->getObject();
/* @var $object kDBList */
$main_object =& $this->Application->recallObject($event->getEventParam('link_to_prefix'));
/* @var $main_object kDBItem */
$selected_items = $main_object->GetDBField($storage_field);
if ($selected_items) {
$filter_type = $event->Special == 'selected' ? 'IN' : 'NOT IN';
$selected_items = explode('|', substr($selected_items, 1, -1));
$filter_clause = '%1$s.' . $object->IDField.' '.$filter_type.' ('.implode(',', $selected_items).')';
}
else {
$filter_clause = ($event->Special == 'selected') ? 'FALSE' : 'TRUE';
}
$constrain = $this->_getConstrain($main_object, $storage_field, 'filter');
if ($constrain) {
$filter_clause .= ' AND (' . $constrain . ')';
}
$object->addFilter('edit_picker_filter', $filter_clause);
}
/**
* Loads selected values from sub_prefix to main item virtual field.
* Called from OnAfterItemLoad of main prefix.
*
* @param kEvent $event
* @param string $store_field main item's field name, to store values into
* @param string $source_field prefix and it's field used to store info about selected items (format: prefix.field)
*/
- function LoadValues(&$event, $store_field, $source_field)
+ function LoadValues($event, $store_field, $source_field)
{
$object =& $event->getObject();
/* @var $object kDBItem */
list ($sub_prefix, $sub_prefix_field) = explode('.', $source_field);
$foreign_key = $this->Application->getUnitOption($sub_prefix, 'ForeignKey');
$sql = 'SELECT '.$sub_prefix_field.'
FROM '.$this->getTable($sub_prefix, $object->IsTempTable()).'
WHERE '.$foreign_key.' = '.$object->GetID();
$constrain = $this->_getConstrain($object, $store_field, 'load');
if ($constrain) {
$sql .= ' AND (' . $sub_prefix_field . ' IN (' . $constrain . '))';
}
$selected_items = array_unique($this->Conn->GetCol($sql));
$object->SetDBField($store_field, $selected_items ? '|'.implode('|', $selected_items).'|' : '');
}
/**
* Saves value to sub-item's table
*
* @param kEvent $sub_event
* @param string $store_field main item's field name, to get values from
* @param string $sub_prefix_field check already existing records by this field
*/
function SaveValues(&$sub_event, $store_field, $sub_prefix_field)
{
$main_object =& $sub_event->MasterEvent->getObject();
/* @var $main_object kDBItem */
$affected_field = $main_object->GetDBField($store_field);
$object =& $this->Application->recallObject($sub_event->getPrefixSpecial(), null, Array('skip_autoload' => true));
/* @var $object kDBItem */
$sub_table = $object->TableName;
$foreign_key = $this->Application->getUnitOption($sub_event->Prefix, 'ForeignKey');
// 1. get previous values from db
$sql = 'SELECT ' . $sub_prefix_field . '
FROM ' . $sub_table . '
WHERE '.$foreign_key.' = '.$main_object->GetID();
$constrain = $this->_getConstrain($main_object, $store_field, 'save');
if ($constrain) {
$sql .= ' AND (' . $sub_prefix_field . ' IN (' . $constrain . '))';
}
$old_values = $this->Conn->GetCol($sql);
// 2. get new values from form
$new_values = $affected_field ? explode('|', substr($affected_field, 1, -1)) : Array ();
$records_to_add = array_diff($new_values, $old_values);
$records_to_delete = array_diff($old_values, $new_values);
if ($records_to_delete && $main_object->isLoaded()) {
$where_clause = Array (
$foreign_key . ' = ' . $main_object->GetID(),
$sub_prefix_field . ' IN (' . implode(',', $records_to_delete) . ')',
);
$sql = 'SELECT ' . $object->IDField . '
FROM ' . $sub_table . '
WHERE (' . implode(') AND (', $where_clause) . ')';
$delete_ids = $this->Conn->GetCol($sql);
foreach ($delete_ids as $delete_id) {
$object->Delete($delete_id);
}
}
if ($records_to_add) {
$main_id = $main_object->GetID();
foreach ($records_to_add as $add_id) {
$object->Clear();
$object->SetDBField($foreign_key, $main_id);
$object->SetDBField($sub_prefix_field, $add_id);
$object->Create();
}
}
}
/**
* Returns constrain for picker options query
- *
+ *
* @param kDBItem $object
* @param string $store_field
* @param string $mode
* @return bool|string
*/
function _getConstrain(&$object, $store_field, $mode = 'filter')
{
$field_options = $object->GetFieldOptions($store_field);
$constrain = array_key_exists('option_constrain', $field_options) ? $field_options['option_constrain']
: false;
if ( $mode == 'filter' ) {
// filter on edit form
return $constrain;
}
elseif ( $constrain ) {
// load or save
return sprintf($field_options['options_sql'], $field_options['option_key_field']);
}
return false;
}
}
\ No newline at end of file
Index: branches/5.2.x/core/units/helpers/controls/controls_config.php
===================================================================
--- branches/5.2.x/core/units/helpers/controls/controls_config.php (revision 15129)
+++ branches/5.2.x/core/units/helpers/controls/controls_config.php (revision 15130)
@@ -1,25 +1,25 @@
<?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!');
$config = Array(
'Prefix' => 'control-helpers',
'EventHandlerClass' => Array('class' => 'kEventHandler', 'file' => '', 'build_event' => 'OnBuild'),
'RegisterClasses' => Array(
- Array('pseudo'=>'MInputHelper','class'=>'MInputHelper','file'=>'minput_helper.php','build_event'=>'','require_classes'=>'kHelper'),
- Array('pseudo' => 'EditPickerHelper', 'class' => 'EditPickerHelper', 'file' => 'edit_picker_helper.php', 'build_event' => '', 'require_classes' => Array('kHelper')),
+ Array('pseudo' => 'MInputHelper', 'class' => 'MInputHelper', 'file' => 'minput_helper.php', 'build_event' => ''),
+ Array('pseudo' => 'EditPickerHelper', 'class' => 'EditPickerHelper', 'file' => 'edit_picker_helper.php', 'build_event' => ''),
),
);
\ No newline at end of file
Index: branches/5.2.x/core/units/helpers/deployment_helper.php
===================================================================
--- branches/5.2.x/core/units/helpers/deployment_helper.php (revision 15129)
+++ branches/5.2.x/core/units/helpers/deployment_helper.php (revision 15130)
@@ -1,607 +1,604 @@
<?php
/**
* @version $Id$
* @package In-Portal
* @copyright Copyright (C) 1997 - 2011 Intechnic. All rights reserved.
* @license GNU/GPL
* In-Portal is Open Source software.
* This means that this software may have been modified pursuant
* the GNU General Public License, and as distributed it includes
* or is derivative of works licensed under the GNU General Public License
* or other free or open source software licenses.
* See http://www.in-portal.org/license for copyright notices and details.
*/
defined('FULL_PATH') or die('restricted access!');
class DeploymentHelper extends kHelper {
/**
* How many symbols from sql should be shown
*/
const SQL_TRIM_LENGTH = 120;
/**
* Name of module, that is processed right now
*
* @var string
* @access private
*/
private $moduleName = '';
/**
* List of sqls, associated with each revision (from project_upgrades.sql file)
*
* @var Array
* @access private
*/
private $revisionSqls = Array ();
/**
* List of revision titles as user typed them (from project_upgrades.sql file)
* @var Array
*/
private $revisionTitles = Array ();
/**
* Revision dependencies
*
* @var Array
* @access private
*/
private $revisionDependencies = Array ();
/**
* Numbers of revisions, that were already applied
*
* @var Array
* @access private
*/
private $appliedRevisions = Array ();
/**
* Don't change database, but only check syntax of project_upgrades.sql file and mark all revisions discovered as applied
*
* @var bool
* @access private
*/
private $dryRun = false;
/**
* Remembers script invocation method
*
* @var bool
* @access public
*/
public $isCommandLine = false;
/**
* IP Address of script invoker
*
* @var string
*/
public $ip = '';
public function __construct()
{
parent::__construct();
set_time_limit(0);
ini_set('memory_limit', -1);
$this->isCommandLine = isset($GLOBALS['argv']) && count($GLOBALS['argv']);
if ( !$this->isCommandLine ) {
$this->ip = $_SERVER['REMOTE_ADDR'];
}
elseif ( isset($GLOBALS['argv'][3]) ) {
$this->ip = $GLOBALS['argv'][3];
}
}
/**
* Adds message to script execution log
*
* @param string $message
* @param bool $new_line
* @return void
* @access private
*/
private function toLog($message, $new_line = true)
{
$log_file = (defined('RESTRICTED') ? RESTRICTED : WRITEABLE) . '/project_upgrades.log';
$fp = fopen($log_file, 'a');
fwrite($fp, $message . ($new_line ? "\n" : ''));
fclose($fp);
chmod($log_file, 0666);
}
/**
* Loads already applied revisions list of current module
*
* @return void
* @access private
*/
private function loadAppliedRevisions()
{
$sql = 'SELECT AppliedDBRevisions
FROM ' . TABLE_PREFIX . 'Modules
WHERE Name = ' . $this->Conn->qstr($this->moduleName);
$revisions = $this->Conn->GetOne($sql);
$this->appliedRevisions = $revisions ? explode(',', $revisions) : Array ();
}
/**
* Saves applied revision numbers to current module record
*
* @return void
* @access private
*/
private function saveAppliedRevisions()
{
// maybe optimize
sort($this->appliedRevisions);
$fields_hash = Array (
'AppliedDBRevisions' => implode(',', $this->appliedRevisions),
);
$this->Conn->doUpdate($fields_hash, TABLE_PREFIX . 'Modules', '`Name` = ' . $this->Conn->qstr($this->moduleName));
}
/**
* Deploys changes from all installed modules
*
* @param bool $dry_run
* @return bool
* @access public
*/
public function deployAll($dry_run = false)
{
if ( !$this->isCommandLine ) {
echo '<pre style="font-size: 10pt; color: #BBB; background-color: black; border: 2px solid darkgreen; padding: 8px;">' . PHP_EOL;
}
$ret = true;
$this->dryRun = $dry_run;
$this->toLog(PHP_EOL . '[' . adodb_date('Y-m-d H:i:s') . '] === ' . $this->ip . ' ===');
foreach ($this->Application->ModuleInfo as $module_name => $module_info) {
$this->moduleName = $module_name;
if ( !file_exists($this->getModuleFile('project_upgrades.sql')) ) {
continue;
}
$ret = $ret && $this->deploy($module_name);
}
if ( $ret && !$this->dryRun ) {
$this->resetCaches();
$this->refreshThemes();
}
if ( !$this->isCommandLine ) {
echo '</pre>' . PHP_EOL;
}
return $ret;
}
/**
* Deploys pending changes to a site
*
* @param string $module_name
* @return bool
* @access private
*/
private function deploy($module_name)
{
echo $this->colorText('Deploying Module "' . $module_name . '":', 'cyan', true) . PHP_EOL;
if ( !$this->upgradeDatabase() ) {
return false;
}
if ( !$this->dryRun ) {
$this->importLanguagePack();
}
echo $this->colorText('Done with Module "' . $module_name . '".', 'green', true) . PHP_EOL . PHP_EOL;
return true;
}
/**
* Import latest languagepack (without overwrite)
*
* @return void
* @access private
*/
private function importLanguagePack()
{
$language_import_helper =& $this->Application->recallObject('LanguageImportHelper');
/* @var $language_import_helper LanguageImportHelper */
echo 'Importing LanguagePack ... ';
$filename = $this->getModuleFile('english.lang');
$language_import_helper->performImport($filename, '|0|1|2|', $this->moduleName, LANG_SKIP_EXISTING);
$this->displayStatus('OK');
}
/**
* Resets unit and section cache
*
* @return void
* @access private
*/
private function resetCaches()
{
// 2. reset unit config cache (so new classes get auto-registered)
echo 'Resetting Unit Config Cache ... ';
- $admin_event = new kEvent('adm:OnResetConfigsCache');
- $this->Application->HandleEvent($admin_event);
+ $this->Application->HandleEvent(new kEvent('adm:OnResetConfigsCache'));
$this->displayStatus('OK');
// 3. reset sections cache
echo 'Resetting Sections Cache ... ';
- $admin_event = new kEvent('adm:OnResetSections');
- $this->Application->HandleEvent($admin_event);
+ $this->Application->HandleEvent(new kEvent('adm:OnResetSections'));
$this->displayStatus('OK');
}
/**
* Rebuild theme files
*
* @return void
* @access private
*/
private function refreshThemes()
{
echo 'Rebuilding Theme Files ... ';
- $admin_event = new kEvent('adm:OnRebuildThemes');
- $this->Application->HandleEvent($admin_event);
+ $this->Application->HandleEvent(new kEvent('adm:OnRebuildThemes'));
$this->displayStatus('OK');
}
/**
* Runs database upgrade script
*
* @return bool
* @access private
*/
private function upgradeDatabase()
{
$this->loadAppliedRevisions();
$this->Conn->errorHandler = Array (&$this, 'handleSqlError');
echo 'Verifying Database Revisions ... ';
if ( !$this->collectDatabaseRevisions() || !$this->checkRevisionDependencies() ) {
return false;
}
$this->displayStatus('OK');
$applied = $this->applyRevisions();
$this->saveAppliedRevisions();
return $applied;
}
/**
* Collects database revisions from "project_upgrades.sql" file.
*
* @return bool
* @access private
*/
private function collectDatabaseRevisions()
{
$filename = $this->getModuleFile('project_upgrades.sql');
if ( !file_exists($filename) ) {
return true;
}
$sqls = file_get_contents($filename);
preg_match_all("/# r([\d]+)([^\:]*):.*?(\n|$)/s", $sqls, $matches, PREG_SET_ORDER + PREG_OFFSET_CAPTURE);
if ( !$matches ) {
$this->displayStatus('FAILED' . PHP_EOL . 'No Database Revisions Found');
return false;
}
foreach ($matches as $index => $match) {
$revision = $match[1][0];
if ( $this->revisionApplied($revision) ) {
// skip applied revisions
continue;
}
if ( isset($this->revisionSqls[$revision]) ) {
// duplicate revision among non-applied ones
$this->displayStatus('FAILED' . PHP_EOL . 'Duplicate revision #' . $revision . ' found');
return false;
}
// get revision sqls
$start_pos = $match[0][1] + strlen($match[0][0]);
$end_pos = isset($matches[$index + 1]) ? $matches[$index + 1][0][1] : strlen($sqls);
$revision_sqls = substr($sqls, $start_pos, $end_pos - $start_pos);
if ( !$revision_sqls ) {
// resision without sqls
continue;
}
$this->revisionTitles[$revision] = trim($match[0][0]);
$this->revisionSqls[$revision] = $revision_sqls;
$revision_lependencies = $this->parseRevisionDependencies($match[2][0]);
if ( $revision_lependencies ) {
$this->revisionDependencies[$revision] = $revision_lependencies;
}
}
ksort($this->revisionSqls);
ksort($this->revisionDependencies);
return true;
}
/**
* Checks that all dependent revisions are either present now OR were applied before
*
* @return bool
* @access private
*/
private function checkRevisionDependencies()
{
foreach ($this->revisionDependencies as $revision => $revision_dependencies) {
foreach ($revision_dependencies as $revision_dependency) {
if ( $this->revisionApplied($revision_dependency) ) {
// revision dependend upon already applied -> depencency fulfilled
continue;
}
if ( $revision_dependency >= $revision ) {
$this->displayStatus('FAILED' . PHP_EOL . 'Revision #' . $revision . ' has incorrect dependency to revision #' . $revision_dependency . '. Only dependencies to older revisions are allowed!');
return false;
}
if ( !isset($this->revisionSqls[$revision_dependency]) ) {
$this->displayStatus('FAILED' . PHP_EOL . 'Revision #' . $revision . ' depends on missing revision #' . $revision_dependency . '!');
return false;
}
}
}
return true;
}
/**
* Runs all pending sqls
*
* @return bool
* @access private
*/
private function applyRevisions()
{
if ( !$this->revisionSqls ) {
return true;
}
if ( $this->dryRun ) {
$this->appliedRevisions = array_merge($this->appliedRevisions, array_keys($this->revisionSqls));
return true;
}
echo 'Upgrading Database ... ' . PHP_EOL;
foreach ($this->revisionSqls as $revision => $sqls) {
echo PHP_EOL . $this->colorText($this->revisionTitles[$revision], 'gray', true) . PHP_EOL; // 'Processing DB Revision: #' . $revision . ' ... ';
$sqls = str_replace("\r\n", "\n", $sqls); // convert to linux line endings
$no_comment_sqls = preg_replace("/#\s([^;]*?)\n/is", "# \\1;\n", $sqls); // add ";" to each comment end to ensure correct split
$sqls = explode(";\n", $no_comment_sqls . "\n"); // ensures that last sql won't have ";" in it
$sqls = array_map('trim', $sqls);
foreach ($sqls as $sql) {
if ( substr($sql, 0, 1) == '#' ) {
// output comment as is
$this->toLog($sql);
echo $this->colorText($sql, 'purple') . PHP_EOL;
continue;
}
elseif ( $sql ) {
$this->toLog($sql . ' ... ', false);
echo mb_substr(trim(preg_replace('/(\n|\t| )+/is', ' ', $sql)), 0, self::SQL_TRIM_LENGTH) . ' ... ';
$this->Conn->Query($sql);
if ( $this->Conn->hasError() ) {
// consider revisions with errors applied
$this->appliedRevisions[] = $revision;
return false;
}
else {
$this->toLog('OK (' . $this->Conn->getAffectedRows() . ')');
$this->displayStatus('OK (' . $this->Conn->getAffectedRows() . ')');
}
}
}
$this->appliedRevisions[] = $revision;
}
echo PHP_EOL;
return true;
}
/**
* Error handler for sql errors
*
* @param int $code
* @param string $msg
* @param string $sql
* @return bool
* @access public
*/
public function handleSqlError($code, $msg, $sql)
{
$this->toLog('FAILED' . PHP_EOL . 'SQL Error #' . $code . ': ' . $msg);
$this->displayStatus('FAILED' . PHP_EOL . 'SQL Error #' . $code . ': ' . $msg);
echo 'Please execute rest of SQLs in this Revision by hand and run deployment script again.' . PHP_EOL;
return true;
}
/**
* Checks if given revision was already applied
*
* @param int $revision
* @return bool
* @access private
*/
private function revisionApplied($revision)
{
foreach ($this->appliedRevisions as $applied_revision) {
// revision range
$applied_revision = explode('-', $applied_revision, 2);
if ( !isset($applied_revision[1]) ) {
// convert single revision to revision range
$applied_revision[1] = $applied_revision[0];
}
if ( $revision >= $applied_revision[0] && $revision <= $applied_revision[1] ) {
return true;
}
}
return false;
}
/**
* Returns path to given file in current module install folder
*
* @param string $filename
* @return string
* @access private
*/
private function getModuleFile($filename)
{
$module_folder = $this->Application->findModule('Name', $this->moduleName, 'Path');
return FULL_PATH . DIRECTORY_SEPARATOR . $module_folder . 'install/' . $filename;
}
/**
* Extracts revisions from string in format "(1,3,5464,23342,3243)"
*
* @param string $string
* @return Array
* @access private
*/
private function parseRevisionDependencies($string)
{
if ( !$string ) {
return Array ();
}
$string = explode(',', substr($string, 1, -1));
return array_map('trim', $string);
}
/**
* Applies requested color and bold attributes to given text string
*
* @param string $text
* @param string $color
* @param bool $bold
* @return string
* @access private
*/
private function colorText($text, $color, $bold = false)
{
if ( $this->isCommandLine ) {
$color_map = Array (
'black' => 30, // dark gray (in bold)
'blue' => 34, // light blue (in bold)
'green' => 32, // light green (in bold)
'cyan' => 36, // light cyan (in bold)
'red' => 31, // light red (in bold)
'purple' => 35, // light purple (in bold)
'brown' => 33, // yellow (in bold)
'gray' => 37, // white (in bold)
);
return "\033[" . ($bold ? 1 : 0) . ";" . $color_map[$color] . "m" . $text . "\033[0m";
}
$html_color_map = Array (
'black' => Array ('normal' => '#000000', 'bold' => '#666666'),
'blue' => Array ('normal' => '#00009C', 'bold' => '#3C3CFF'),
'green' => Array ('normal' => '#009000', 'bold' => '#00FF00'),
'cyan' => Array ('normal' => '#009C9C', 'bold' => '#00FFFF'),
'red' => Array ('normal' => '#9C0000', 'bold' => '#FF0000'),
'purple' => Array ('normal' => '#900090', 'bold' => '#F99CF9'),
'brown' => Array ('normal' => '#C9C909', 'bold' => '#FFFF00'),
'gray' => Array ('normal' => '#909090', 'bold' => '#FFFFFF'),
);
$html_color = $html_color_map[$color][$bold ? 'bold' : 'normal'];
return '<span style="color: ' . $html_color . '">' . $text . '</span>';
}
/**
* Makes given text bold
*
* @param string $text
* @return string
* @access private
*/
private function boldText($text)
{
if ( $this->isCommandLine ) {
return "\033[1m" . $text . "\033[0m";
}
return '<strong>' . $text . '</strong>';
}
/**
* Displays last command execution status
*
* @param string $status_text
* @param bool $new_line
* @return void
* @access private
*/
private function displayStatus($status_text, $new_line = true)
{
$color = substr($status_text, 0, 2) == 'OK' ? 'green' : 'red';
echo $this->colorText($status_text, $color, false);
if ( $new_line ) {
echo PHP_EOL;
}
}
}
\ No newline at end of file
Index: branches/5.2.x/core/units/helpers/priority_helper.php
===================================================================
--- branches/5.2.x/core/units/helpers/priority_helper.php (revision 15129)
+++ branches/5.2.x/core/units/helpers/priority_helper.php (revision 15130)
@@ -1,245 +1,245 @@
<?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 kPriorityHelper extends kHelper {
/**
* Prepares options for priority dropdown
*
* @param kEvent $event
* @param bool $is_new for newly created items add new priority to the end
* @param string $constrain constrain for priority selection (if any)
* @param string $joins left joins, used by constrain (if any)
*
*/
- function preparePriorities(&$event, $is_new = false, $constrain = '', $joins = '')
+ function preparePriorities($event, $is_new = false, $constrain = '', $joins = '')
{
$object =& $event->getObject();
/* @var $object kDBItem */
$field_options = $object->GetFieldOptions('Priority');
$table_name = $this->Application->getUnitOption($event->Prefix, 'TableName');
$sql = 'SELECT COUNT(*)
FROM ' . $table_name . ' item_table
' . $joins;
if ( $constrain ) {
$sql .= ' WHERE ' . $this->normalizeConstrain($constrain);
}
if ( !$object->isField('OldPriority') ) {
// make sure, then OldPriority field is defined
$virtual_fields = $object->getVirtualFields();
$virtual_fields['OldPriority'] = Array ('type' => 'int', 'default' => 0);
$object->setVirtualFields($virtual_fields);
}
$items_count = $this->Conn->GetOne($sql);
$current_priority = $object instanceof kDBList ? 0 : $object->GetDBField('Priority');
if ( $is_new || $current_priority == -($items_count + 1) ) {
$items_count++;
}
if ( $is_new ) {
// add new item to the end of list
$object->SetDBField('Priority', -$items_count);
$object->SetDBField('OldPriority', -$items_count);
}
else {
// storing priority right after load for comparing when updating
$object->SetDBField('OldPriority', $current_priority);
}
for ($i = 1; $i <= $items_count; $i++) {
$field_options['options'][-$i] = $i;
}
$object->SetFieldOptions('Priority', $field_options);
}
/**
* Updates priorities for changed items
*
* @param kEvent $event
* @param Array $changes = Array (ID => Array ('constrain' => ..., 'new' => ..., 'old' => ...), ...)
* @param Array $new_ids = Array (temp_id => live_id)
* @param string $constrain
* @param string $joins
* @return Array
*/
- function updatePriorities(&$event, $changes, $new_ids, $constrain = '', $joins = '')
+ function updatePriorities($event, $changes, $new_ids, $constrain = '', $joins = '')
{
// TODO: no need pass external $constrain, since the one from $pair is used
if ( !$changes ) {
// no changes to process
return Array ();
}
list ($id, $pair) = each($changes);
if ( !$id && !isset($pair['constrain']) ) {
// adding new item without constrain -> priority stays the same
return Array ($id);
}
$id_field = $this->Application->getUnitOption($event->Prefix, 'IDField');
$table_name = $this->Application->getUnitOption($event->Prefix, 'TableName');
if ( $this->Application->IsTempMode($event->Prefix, $event->Special) ) {
$table_name = $this->Application->GetTempName($table_name, 'prefix:' . $event->Prefix);
}
$ids = Array ();
$not_processed = array_keys($changes);
foreach ($changes as $id => $pair) {
array_push($ids, $id);
$constrain = isset($pair['constrain']) ? $this->normalizeConstrain($pair['constrain']) . ' AND ' : '';
if ( $pair['old'] == 'new' ) {
// replace 0 with newly created item id (from $new_ids mapping)
$not_processed[array_search($id, $not_processed)] = $new_ids[$id];
$id = $new_ids[$id];
$sql = 'SELECT MIN(item_table.Priority)
FROM ' . $table_name . ' item_table
' . $joins . '
WHERE ' . $constrain . ' item_table.' . $id_field . ' NOT IN (' . implode(',', $not_processed) . ')';
$min_priority = (int)$this->Conn->GetOne($sql) - 1;
if ( $pair['new'] < $min_priority ) {
$pair['new'] = $min_priority;
}
$pair['old'] = $min_priority;
}
if ( $pair['new'] < $pair['old'] ) {
$set = ' SET item_table.Priority = item_table.Priority + 1';
$where = ' WHERE ' . $constrain . '
item_table.Priority >= ' . $pair['new'] . '
AND
item_table.Priority < ' . $pair['old'] . '
AND
' . $id_field . ' NOT IN (' . implode(',', $not_processed) . ')';
}
elseif ( $pair['new'] > $pair['old'] ) {
$set = ' SET item_table.Priority = item_table.Priority - 1';
$where = ' WHERE ' . $constrain . '
item_table.Priority > ' . $pair['old'] . '
AND
item_table.Priority <= ' . $pair['new'] . '
AND
' . $id_field . ' NOT IN (' . implode(',', $not_processed) . ')';
}
else {
$set = ' SET item_table.Priority = ' . $pair['new'];
$where = ' WHERE ' . $id_field . ' = ' . $id;
}
$sql = 'SELECT item_table.' . $id_field . '
FROM ' . $table_name . ' item_table
' . $joins . '
' . $where;
$ids = array_merge($ids, $this->Conn->GetCol($sql));
$q = 'UPDATE ' . $table_name . ' item_table
' . $joins . '
' . $set . $where;
$this->Conn->Query($q);
unset($not_processed[array_search($id, $not_processed)]);
}
return $ids;
}
/**
* Recalculates priorities
*
* @param kEvent $event
* @param string $constrain
* @param string $joins
* @return Array
*/
- function recalculatePriorities(&$event, $constrain = '', $joins = '')
+ function recalculatePriorities($event, $constrain = '', $joins = '')
{
$id_field = $this->Application->getUnitOption($event->Prefix, 'IDField');
$table_name = $this->Application->getUnitOption($event->Prefix, 'TableName');
$constrain = $this->normalizeConstrain($constrain);
if ( $this->Application->IsTempMode($event->Prefix, $event->Special) ) {
$table_name = $this->Application->GetTempName($table_name, 'prefix:' . $event->Prefix);
}
$sql = 'SELECT ' . $id_field . '
FROM ' . $table_name . ' item_table ' .
$joins . ' ' .
($constrain ? ' WHERE ' . $constrain : '') . '
ORDER BY item_table.Priority DESC';
$items = $this->Conn->GetCol($sql);
foreach ($items as $item_number => $item_id) {
$sql = 'UPDATE ' . $table_name . '
SET Priority = ' . -($item_number + 1) . '
WHERE ' . $id_field . ' = ' . $item_id;
$this->Conn->Query($sql);
}
return $items;
}
/**
* Adds current table name into constrain if doesn't have it already (to prevent ambiguous columns during joins)
*
* @param string $constrain
* @return string
*/
function normalizeConstrain($constrain)
{
if ( strpos($constrain, '.') === false ) {
return 'item_table.' . $constrain;
}
return $constrain;
}
/**
* Performs fake kDBItem::Update call, so any OnBefore/OnAfter events would be notified of priority change
*
* @param string $prefix
* @param Array $ids
*/
function massUpdateChanged($prefix, $ids)
{
$ids = array_unique($ids);
$dummy =& $this->Application->recallObject($prefix . '.-dummy', null, Array ('skip_autoload' => true));
/* @var $dummy kDBItem */
$sql = $dummy->GetSelectSQL() . '
WHERE ' . $dummy->TableName . '.' . $dummy->IDField . ' IN (' . implode(',', $ids) . ')';
$records = $this->Conn->Query($sql);
foreach ($records as $record) {
$dummy->LoadFromHash($record);
$dummy->Update();
}
}
}
\ No newline at end of file
Index: branches/5.2.x/core/units/helpers/country_states_helper.php
===================================================================
--- branches/5.2.x/core/units/helpers/country_states_helper.php (revision 15129)
+++ branches/5.2.x/core/units/helpers/country_states_helper.php (revision 15130)
@@ -1,223 +1,223 @@
<?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 kCountryStatesHelper extends kHelper
{
/**
* Returns countries, that have states
*
* @return Array
*/
function getCountriesWithStates()
{
static $cache = null;
if (!isset($cache)) {
$table_name = $this->Application->getUnitOption('country-state', 'TableName');
$sql = 'SELECT DISTINCT cname.IsoCode, cid.StateCountryId
FROM ' . $table_name . ' cid
JOIN ' . $table_name . ' cname ON cname.CountryStateId = cid.StateCountryId
WHERE cid.StateCountryId IS NOT NULL';
$cache = $this->Conn->GetCol($sql, 'StateCountryId');
}
return $cache;
}
/**
* Checks, that country with given 3symbol ISO code has states
*
* @param string $country_code
* @return bool
*/
function CountryHasStates($country_code)
{
return $country_code ? in_array($country_code, $this->getCountriesWithStates()) : false;
}
/**
* Prepares states dropdown based on country selected
*
* @param kEvent $event
* @param string $state_field
* @param string $country_field
*/
- function PopulateStates(&$event, $state_field, $country_field)
+ function PopulateStates($event, $state_field, $country_field)
{
static $cache = Array ();
$object =& $event->getObject();
/* @var $object kDBItem */
$country_iso = $object->GetDBField($country_field);
if (!$country_iso) {
return ;
}
if (!array_key_exists($country_iso, $cache)) {
$states = $this->getStates($country_iso);
if ( !$states ) {
return;
}
$cache[$country_iso] = $states;
}
$field_options = $object->GetFieldOptions($state_field);
$field_options['options'] = $cache[$country_iso];
$field_options['options'][''] = '';
$object->SetFieldOptions($state_field, $field_options);
}
/**
* Returns list of given country states
*
* @param string $country_iso
* @return Array
*/
public function getStates($country_iso)
{
$country_id = $this->getCountryStateId($country_iso, DESTINATION_TYPE_COUNTRY);
if ( !$country_id ) {
return Array ();
}
// don't use GetVar('m_lang') since it's always equals to default language on editing form in admin
$current_language = $this->Application->Phrases->LanguageId;
$primary_language = $this->Application->GetDefaultLanguageId();
$sql = 'SELECT IF(l' . $current_language . '_Name = "", l' . $primary_language . '_Name, l' . $current_language . '_Name) AS Name, IsoCode
FROM ' . $this->Application->getUnitOption('country-state', 'TableName') . '
WHERE (Type = ' . DESTINATION_TYPE_STATE . ') AND (StateCountryId = ' . $country_id . ')
ORDER BY Name ASC';
return $this->Conn->GetCol($sql, 'IsoCode');
}
/**
* Returns valid state ISO code for state name and country code passed
*
* @param string $state_name
* @param string $country_iso
* @return string
*/
function getStateIso($state_name, $country_iso)
{
if (!$this->CountryHasStates($country_iso)) {
return $state_name;
}
$table_name = $this->Application->getUnitOption('country-state', 'TableName');
$country_id = $this->getCountryStateId($country_iso, DESTINATION_TYPE_COUNTRY);
// don't use GetVar('m_lang') since it's always equals to default language on editing form in admin
$current_language = $this->Application->Phrases->LanguageId;
$primary_language = $this->Application->GetDefaultLanguageId();
$sql = 'SELECT IsoCode
FROM ' . $table_name . '
WHERE (Type = ' . DESTINATION_TYPE_STATE . ') AND (StateCountryId = %1$s) AND
(
(IsoCode = %2$s) OR (UPPER(l%3$s_Name) = %2$s) OR (UPPER(l%4$s_Name) = %2$s)
)';
$state_name = trim( mb_strtoupper($state_name) );
$sql = sprintf($sql, $country_id, $this->Conn->qstr($state_name), $current_language, $primary_language);
return $this->Conn->GetOne($sql);
}
/**
* Checks, that entered state matches entered country
*
* @param kEvent $event
* @param string $state_field
* @param string $country_field
* @param bool $auto_required
* @return void
*/
- function CheckStateField(&$event, $state_field, $country_field, $auto_required = true)
+ function CheckStateField($event, $state_field, $country_field, $auto_required = true)
{
$object =& $event->getObject();
/* @var $object kDBItem */
$country_iso = $object->GetDBField($country_field);
if ( $auto_required ) {
$object->setRequired($state_field, $this->CountryHasStates($country_iso));
}
$state = $object->GetDBField($state_field);
if ( $country_iso && $state ) {
$state_iso = $this->getStateIso($state, $country_iso);
if ( $state_iso !== false ) {
// replace state name with it's ISO code
$object->SetDBField($state_field, $state_iso);
}
else {
// state not found by name -> report error
$object->SetError($state_field, 'invalid_state', 'la_invalid_state');
}
}
}
/**
* Returns country/state id based on given iso code and it's type
*
* @param string $iso_code
* @param int $type
* @return int
*/
function getCountryStateId($iso_code, $type)
{
$sql = 'SELECT ' . $this->Application->getUnitOption('country-state', 'IDField') . '
FROM ' . $this->Application->getUnitOption('country-state', 'TableName') . '
WHERE (Type = ' . $type . ') AND (IsoCode = ' . $this->Conn->qstr($iso_code) . ')';
return (int)$this->Conn->GetOne($sql);
}
/**
* Returns 3 symbols ISO code from 2 symbols ISO code or otherwise, when $from_short parameter is used
*
* @param string $iso_code
* @param bool $from_short
* @return string
*/
function getCountryIso($iso_code, $from_short = false)
{
if ($from_short) {
$sql = 'SELECT IsoCode
FROM ' . TABLE_PREFIX . 'CountryStates
WHERE ShortIsoCode = ' . $this->Conn->qstr($iso_code) . ' AND `Type` = ' . DESTINATION_TYPE_COUNTRY;
}
else {
$sql = 'SELECT ShortIsoCode
FROM ' . TABLE_PREFIX . 'CountryStates
WHERE IsoCode = ' . $this->Conn->qstr($iso_code) . ' AND `Type` = ' . DESTINATION_TYPE_COUNTRY;
}
return $this->Conn->GetOne($sql);
}
}
\ No newline at end of file
Index: branches/5.2.x/core/units/helpers/cat_dbitem_export_helper.php
===================================================================
--- branches/5.2.x/core/units/helpers/cat_dbitem_export_helper.php (revision 15129)
+++ branches/5.2.x/core/units/helpers/cat_dbitem_export_helper.php (revision 15130)
@@ -1,1569 +1,1569 @@
<?php
/**
* @version $Id$
* @package In-Portal
* @copyright Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
* @license GNU/GPL
* In-Portal is Open Source software.
* This means that this software may have been modified pursuant
* the GNU General Public License, and as distributed it includes
* or is derivative of works licensed under the GNU General Public License
* or other free or open source software licenses.
* See http://www.in-portal.org/license for copyright notices and details.
*/
defined('FULL_PATH') or die('restricted access!');
define('EXPORT_STEP', 100); // export by 200 items (e.g. links)
define('IMPORT_STEP', 20); // export by 200 items (e.g. links)
define('IMPORT_CHUNK', 10240); // 10240); //30720); //50120); // 5 KB
define('IMPORT_TEMP', 1);
define('IMPORT_LIVE', 2);
class kCatDBItemExportHelper extends kHelper {
var $false = false;
var $cache = Array();
/**
* Allows to find out what items are new in cache
*
* @var Array
*/
var $cacheStatus = Array();
var $cacheTable = '';
var $exportFields = Array();
/**
* Export options
*
* @var Array
*/
var $exportOptions = Array();
/**
* Item beeing currenly exported
*
* @var kCatDBItem
*/
var $curItem = null;
/**
* Dummy category object
*
* @var CategoriesItem
*/
var $dummyCategory = null;
/**
* Pointer to opened file
*
* @var resource
*/
var $filePointer = null;
/**
* Custom fields definition of current item
*
* @var Array
*/
var $customFields = Array();
public function __construct()
{
parent::__construct();
$this->cacheTable = TABLE_PREFIX.'ImportCache';
}
/**
* Returns value from cache if found or false otherwise
*
* @param string $type
* @param int $key
* @return mixed
*/
function getFromCache($type, $key)
{
return getArrayValue($this->cache, $type, $key);
}
/**
* Adds value to be cached
*
* @param string $type
* @param int $key
* @param mixed $value
* @param bool $is_new
*/
function addToCache($type, $key, $value, $is_new = true)
{
/*if ( !isset($this->cache[$type]) ) {
$this->cache[$type] = Array ();
}*/
$this->cache[$type][$key] = $value;
if ( $is_new ) {
$this->cacheStatus[$type][$key] = true;
}
}
function storeCache($cache_types)
{
$cache_types = explode(',', $cache_types);
$values_sql = '';
foreach ($cache_types as $cache_type) {
$sql_mask = '('.$this->Conn->qstr($cache_type).',%s,%s),';
$cache = getArrayValue($this->cacheStatus, $cache_type);
if (!$cache) $cache = Array();
foreach ($cache as $var_name => $cache_status) {
$var_value = $this->cache[$cache_type][$var_name];
$values_sql .= sprintf($sql_mask, $this->Conn->qstr($var_name), $this->Conn->qstr($var_value) );
}
}
$values_sql = substr($values_sql, 0, -1);
if ($values_sql) {
$sql = 'INSERT INTO '.$this->cacheTable.'(`CacheName`,`VarName`,`VarValue`) VALUES '.$values_sql;
$this->Conn->Query($sql);
}
}
function loadCache()
{
$sql = 'SELECT * FROM '.$this->cacheTable;
$records = $this->Conn->Query($sql);
$this->cache = Array();
foreach ($records as $record) {
$this->addToCache($record['CacheName'], $record['VarName'], $record['VarValue'], false);
}
}
/**
* Fill required fields with dummy values
*
* @param kEvent|bool $event
* @param kCatDBItem|bool $object
* @param bool $set_status
*/
- function fillRequiredFields(&$event, &$object, $set_status = false)
+ function fillRequiredFields($event, &$object, $set_status = false)
{
if ( $object == $this->false ) {
$object =& $event->getObject();
/* @var $object kCatDBItem */
}
$has_empty = false;
$fields = $object->getFields();
if ( $object->isField('CreatedById') ) {
// CSV file was created without required CreatedById column
if ( $object->isRequired('CreatedById') ) {
$object->setRequired('CreatedById', false);
}
if ( !is_numeric( $object->GetDBField('CreatedById') ) ) {
$object->SetDBField('CreatedById', $this->Application->RecallVar('user_id'));
}
}
foreach ($fields as $field_name => $field_options) {
if ( $object->isVirtualField($field_name) || !$object->isRequired($field_name) ) {
continue;
}
if ( $object->GetDBField($field_name) ) {
continue;
}
$formatter_class = getArrayValue($field_options, 'formatter');
if ( $formatter_class ) {
// not tested
$formatter =& $this->Application->recallObject($formatter_class);
/* @var $formatter kFormatter */
$sample_value = $formatter->GetSample($field_name, $field_options, $object);
}
$has_empty = true;
$object->SetField($field_name, isset($sample_value) && $sample_value ? $sample_value : 'no value');
}
$object->UpdateFormattersSubFields();
if ( $set_status && $has_empty ) {
$object->SetDBField('Status', 0);
}
}
/**
* Verifies that all user entered export params are correct
*
* @param kEvent $event
* @return bool
* @access protected
*/
- protected function verifyOptions(&$event)
+ protected function verifyOptions($event)
{
if ($this->Application->RecallVar($event->getPrefixSpecial().'_ForceNotValid'))
{
$this->Application->StoreVar($event->getPrefixSpecial().'_ForceNotValid', 0);
return false;
}
$this->fillRequiredFields($event, $this->false);
$object =& $event->getObject();
/* @var $object kCatDBItem */
$cross_unique_fields = Array('FieldsSeparatedBy', 'FieldsEnclosedBy');
if (($object->GetDBField('CategoryFormat') == 1) || ($event->Special == 'import')) // in one field
{
$object->setRequired('CategorySeparator');
$cross_unique_fields[] = 'CategorySeparator';
}
$ret = $object->Validate();
// check if cross unique fields has no same values
foreach ($cross_unique_fields as $field_index => $field_name)
{
if ($object->GetErrorPseudo($field_name) == 'required') {
continue;
}
$check_fields = $cross_unique_fields;
unset($check_fields[$field_index]);
foreach ($check_fields as $check_field)
{
if ($object->GetDBField($field_name) == $object->GetDBField($check_field))
{
$object->SetError($check_field, 'unique');
}
}
}
if ($event->Special == 'import')
{
$this->exportOptions = $this->loadOptions($event);
$automatic_fields = ($object->GetDBField('FieldTitles') == 1);
$object->setRequired('ExportColumns', !$automatic_fields);
$category_prefix = '__CATEGORY__';
if ( $automatic_fields && ($this->exportOptions['SkipFirstRow']) ) {
$this->openFile($event);
$this->exportOptions['ExportColumns'] = $this->readRecord();
if (!$this->exportOptions['ExportColumns']) {
$this->exportOptions['ExportColumns'] = Array ();
}
$this->closeFile();
// remove additional (non-parseble columns)
foreach ($this->exportOptions['ExportColumns'] as $field_index => $field_name) {
if (!$this->validateField($field_name, $object)) {
unset($this->exportOptions['ExportColumns'][$field_index]);
}
}
$category_prefix = '';
}
// 1. check, that we have column definitions
if (!$this->exportOptions['ExportColumns']) {
$object->setError('ExportColumns', 'required');
$ret = false;
}
else {
// 1.1. check that all required fields are present in imported file
$missing_columns = Array();
$fields = $object->getFields();
foreach ($fields as $field_name => $field_options) {
if ($object->skipField($field_name)) continue;
if ( $object->isRequired($field_name) && !in_array($field_name, $this->exportOptions['ExportColumns']) ) {
$missing_columns[] = $field_name;
$object->setError('ExportColumns', 'required_fields_missing', 'la_error_RequiredColumnsMissing');
$ret = false;
}
}
if (!$ret && $this->Application->isDebugMode()) {
$this->Application->Debugger->appendHTML('Missing required for import/export:');
$this->Application->Debugger->dumpVars($missing_columns);
}
}
// 2. check, that we have only mixed category field or only separated category fields
$category_found['mixed'] = false;
$category_found['separated'] = false;
foreach ($this->exportOptions['ExportColumns'] as $import_field) {
if (preg_match('/^'.$category_prefix.'Category(Path|[0-9]+)/', $import_field, $rets)) {
$category_found[$rets[1] == 'Path' ? 'mixed' : 'separated'] = true;
}
}
if ($category_found['mixed'] && $category_found['separated']) {
$object->SetError('ExportColumns', 'unique_category', 'la_error_unique_category_field');
$ret = false;
}
// 3. check, that duplicates check fields are selected & present in imported fields
if ($this->exportOptions['ReplaceDuplicates']) {
if ($this->exportOptions['CheckDuplicatesMethod'] == 1) {
$check_fields = Array($object->IDField);
}
else {
$check_fields = $this->exportOptions['DuplicateCheckFields'] ? explode('|', substr($this->exportOptions['DuplicateCheckFields'], 1, -1)) : Array();
$object =& $event->getObject();
$fields = $object->getFields();
$language_id = $this->Application->GetDefaultLanguageId();
foreach ($check_fields as $index => $check_field) {
foreach ($fields as $field_name => $field_options) {
if ($field_name == 'l'.$language_id.'_'.$check_field) {
$check_fields[$index] = 'l'.$language_id.'_'.$check_field;
break;
}
}
}
}
$this->exportOptions['DuplicateCheckFields'] = $check_fields;
if (!$check_fields) {
$object->setError('CheckDuplicatesMethod', 'required');
$ret = false;
}
else {
foreach ($check_fields as $check_field) {
$check_field = preg_replace('/^cust_(.*)/', 'Custom_\\1', $check_field);
if (!in_array($check_field, $this->exportOptions['ExportColumns'])) {
$object->setError('ExportColumns', 'required');
$ret = false;
break;
}
}
}
}
$this->saveOptions($event);
}
return $ret;
}
/**
* Returns filename to read import data from
*
* @return string
*/
function getImportFilename()
{
if ($this->exportOptions['ImportSource'] == 1)
{
$ret = $this->exportOptions['ImportFilename']; // ['name']; commented by Kostja
}
else {
$ret = $this->exportOptions['ImportLocalFilename'];
}
return EXPORT_PATH.'/'.$ret;
}
/**
* Returns filename to write export data to
*
* @return string
*/
function getExportFilename()
{
$extension = $this->getFileExtension();
$filename = preg_replace('/(.*)\.' . $extension . '$/', '\1', $this->exportOptions['ExportFilename']) . '.' . $extension;
return EXPORT_PATH . DIRECTORY_SEPARATOR . $filename;
}
/**
* Opens file required for export/import operations
*
* @param kEvent $event
*/
- function openFile(&$event)
+ function openFile($event)
{
$file_helper =& $this->Application->recallObject('FileHelper');
/* @var $file_helper FileHelper */
$file_helper->CheckFolder(EXPORT_PATH);
if ($event->Special == 'export') {
$write_mode = ($this->exportOptions['start_from'] == 0) ? 'w' : 'a';
$this->filePointer = fopen($this->getExportFilename(), $write_mode);
}
else {
$this->filePointer = fopen($this->getImportFilename(), 'r');
}
// skip UTF-8 BOM Modifier
$first_chars = fread($this->filePointer, 3);
if (bin2hex($first_chars) != 'efbbbf') {
fseek($this->filePointer, 0);
}
}
/**
* Closes opened file
*
*/
function closeFile()
{
fclose($this->filePointer);
}
function getCustomSQL()
{
$ml_formatter =& $this->Application->recallObject('kMultiLanguage');
/* @var $ml_formatter kMultiLanguage */
$custom_sql = '';
foreach ($this->customFields as $custom_id => $custom_name) {
$custom_sql .= 'custom_data.' . $ml_formatter->LangFieldName('cust_' . $custom_id) . ' AS cust_' . $custom_name . ', ';
}
return substr($custom_sql, 0, -2);
}
function getPlainExportSQL($count_only = false)
{
if ( $count_only && isset($this->exportOptions['ForceCountSQL']) ) {
$sql = $this->exportOptions['ForceCountSQL'];
}
elseif ( !$count_only && isset($this->exportOptions['ForceSelectSQL']) ) {
$sql = $this->exportOptions['ForceSelectSQL'];
}
else {
$items_list =& $this->Application->recallObject($this->curItem->Prefix . '.export-items-list', $this->curItem->Prefix . '_List');
/* @var $items_list kDBList */
$items_list->SetPerPage(-1);
if ( $this->exportOptions['export_ids'] != '' ) {
$items_list->addFilter('export_ids', $items_list->TableName . '.' . $items_list->IDField . ' IN (' . implode(',', $this->exportOptions['export_ids']) . ')');
}
if ( $count_only ) {
$sql = $items_list->getCountSQL($items_list->GetSelectSQL(true, false));
}
else {
$sql = $items_list->GetSelectSQL();
}
}
if ( !$count_only ) {
$sql .= ' LIMIT ' . $this->exportOptions['start_from'] . ',' . EXPORT_STEP;
}
/*else {
$sql = preg_replace("/^\s*SELECT(.*?\s)FROM(?!_)/is", "SELECT COUNT(*) AS count FROM ", $sql);
}*/
return $sql;
}
function getExportSQL($count_only = false)
{
if ( !$this->Application->getUnitOption($this->curItem->Prefix, 'CatalogItem') ) {
return $this->GetPlainExportSQL($count_only); // in case this is not a CategoryItem
}
if ( $this->exportOptions['export_ids'] === false ) {
// get links from current category & all it's subcategories
$join_clauses = Array ();
$custom_sql = $this->getCustomSQL();
if ( $custom_sql ) {
$custom_table = $this->Application->getUnitOption($this->curItem->Prefix . '-cdata', 'TableName');
$join_clauses[$custom_table . ' custom_data'] = 'custom_data.ResourceId = item_table.ResourceId';
}
$join_clauses[TABLE_PREFIX . 'CategoryItems ci'] = 'ci.ItemResourceId = item_table.ResourceId';
$join_clauses[TABLE_PREFIX . 'Categories c'] = 'c.CategoryId = ci.CategoryId';
$sql = 'SELECT item_table.*, ci.CategoryId' . ($custom_sql ? ', ' . $custom_sql : '') . '
FROM ' . $this->curItem->TableName . ' item_table';
foreach ($join_clauses as $table_name => $join_expression) {
$sql .= ' LEFT JOIN ' . $table_name . ' ON ' . $join_expression;
}
$sql .= ' WHERE ';
if ( $this->exportOptions['export_cats_ids'][0] == 0 ) {
$sql .= '1';
}
else {
foreach ($this->exportOptions['export_cats_ids'] as $category_id) {
$sql .= '(c.ParentPath LIKE "%|' . $category_id . '|%") OR ';
}
$sql = substr($sql, 0, -4);
}
$sql .= ' ORDER BY ci.PrimaryCat DESC'; // NEW
}
else {
// get only selected links
$sql = 'SELECT item_table.*, ' . $this->exportOptions['export_cats_ids'][0] . ' AS CategoryId
FROM ' . $this->curItem->TableName . ' item_table
WHERE ' . $this->curItem->IDField . ' IN (' . implode(',', $this->exportOptions['export_ids']) . ')';
}
if ( !$count_only ) {
$sql .= ' LIMIT ' . $this->exportOptions['start_from'] . ',' . EXPORT_STEP;
}
else {
$sql = preg_replace("/^\s*SELECT(.*?\s)FROM(?!_)/is", "SELECT COUNT(*) AS count FROM ", $sql);
}
return $sql;
}
/**
* Enter description here...
*
* @param kEvent $event
*/
- function performExport(&$event)
+ function performExport($event)
{
$this->exportOptions = $this->loadOptions($event);
$this->exportFields = $this->exportOptions['ExportColumns'];
$this->curItem =& $event->getObject( Array('skip_autoload' => true) );
$this->customFields = $this->Application->getUnitOption($event->Prefix, 'CustomFields');
$this->openFile($event);
if ($this->exportOptions['start_from'] == 0) // first export step
{
if (!getArrayValue($this->exportOptions, 'IsBaseCategory')) {
$this->exportOptions['IsBaseCategory'] = 0;
}
if ($this->exportOptions['IsBaseCategory'] ) {
$sql = 'SELECT ParentPath
FROM '.TABLE_PREFIX.'Categories
WHERE CategoryId = ' . (int)$this->Application->GetVar('m_cat_id');
$parent_path = $this->Conn->GetOne($sql);
$parent_path = explode('|', substr($parent_path, 1, -1));
if ($parent_path && $parent_path[0] == $this->Application->getBaseCategory()) {
array_shift($parent_path);
}
$this->exportOptions['BaseLevel'] = count($parent_path); // level to cut from other categories
}
// 1. export field titles if required
if ($this->exportOptions['IncludeFieldTitles'])
{
$data_array = Array();
foreach ($this->exportFields as $export_field)
{
$data_array = array_merge($data_array, $this->getFieldCaption($export_field));
}
$this->writeRecord($data_array);
}
$this->exportOptions['total_records'] = $this->Conn->GetOne( $this->getExportSQL(true) );
}
// 2. export data
$records = $this->Conn->Query( $this->getExportSQL() );
$records_exported = 0;
foreach ($records as $record_info) {
$this->curItem->LoadFromHash($record_info);
$data_array = Array();
foreach ($this->exportFields as $export_field)
{
$data_array = array_merge($data_array, $this->getFieldValue($export_field) );
}
$this->writeRecord($data_array);
$records_exported++;
}
$this->closeFile();
$this->exportOptions['start_from'] += $records_exported;
$this->saveOptions($event);
return $this->exportOptions;
}
function getItemFields()
{
// just in case dummy user selected automtic mode & moved columns too :(
$src_options = $this->curItem->GetFieldOption('ExportColumns', 'options');
$dst_options = $this->curItem->GetFieldOption('AvailableColumns', 'options');
return array_merge($dst_options, $src_options);
}
/**
* Checks if field really belongs to importable field list
*
* @param string $field_name
* @param kCatDBItem $object
* @return bool
*/
function validateField($field_name, &$object)
{
// 1. convert custom field
$field_name = preg_replace('/^Custom_(.*)/', '__CUSTOM__\\1', $field_name);
// 2. convert category field (mixed version & separated version)
$field_name = preg_replace('/^Category(Path|[0-9]+)/', '__CATEGORY__Category\\1', $field_name);
$valid_fields = $object->getPossibleExportColumns();
return isset($valid_fields[$field_name]) || isset($valid_fields['__VIRTUAL__'.$field_name]);
}
/**
* Enter description here...
*
* @param kEvent $event
*/
- function performImport(&$event)
+ function performImport($event)
{
if (!$this->exportOptions) {
// load import options in case if not previously loaded in verification function
$this->exportOptions = $this->loadOptions($event);
}
$backup_category_id = $this->Application->GetVar('m_cat_id');
$this->Application->SetVar('m_cat_id', (int)$this->Application->RecallVar('ImportCategory') );
$this->openFile($event);
$bytes_imported = 0;
if ($this->exportOptions['start_from'] == 0) // first export step
{
// 1st time run
if ($this->exportOptions['SkipFirstRow']) {
$this->readRecord();
$this->exportOptions['start_from'] = ftell($this->filePointer);
$bytes_imported = ftell($this->filePointer);
}
$current_category_id = $this->Application->GetVar('m_cat_id');
if ($current_category_id > 0) {
$sql = 'SELECT ParentPath FROM '.TABLE_PREFIX.'Categories WHERE CategoryId = '.$current_category_id;
$this->exportOptions['ImportCategoryPath'] = $this->Conn->GetOne($sql);
}
else {
$this->exportOptions['ImportCategoryPath'] = '';
}
$this->exportOptions['total_records'] = filesize($this->getImportFilename());
}
else {
$this->loadCache();
}
$this->exportFields = $this->exportOptions['ExportColumns'];
$this->addToCache('category_parent_path', $this->Application->GetVar('m_cat_id'), $this->exportOptions['ImportCategoryPath']);
// 2. import data
$this->dummyCategory =& $this->Application->recallObject('c.-tmpitem', 'c', Array('skip_autoload' => true));
fseek($this->filePointer, $this->exportOptions['start_from']);
$items_processed = 0;
while (($bytes_imported < IMPORT_CHUNK && $items_processed < IMPORT_STEP) && !feof($this->filePointer)) {
$data = $this->readRecord();
if ($data) {
if ($this->exportOptions['ReplaceDuplicates']) {
// set fields used as keys for replace duplicates code
$this->resetImportObject($event, IMPORT_TEMP, $data);
}
$this->processCurrentItem($event, $data);
}
$bytes_imported = ftell($this->filePointer) - $this->exportOptions['start_from'];
$items_processed++;
}
$this->closeFile();
$this->Application->SetVar('m_cat_id', $backup_category_id);
$this->exportOptions['start_from'] += $bytes_imported;
$this->storeCache('new_ids');
$this->saveOptions($event);
if ($this->exportOptions['start_from'] == $this->exportOptions['total_records']) {
$this->Conn->Query('TRUNCATE TABLE '.$this->cacheTable);
}
return $this->exportOptions;
}
function setCurrentID()
{
$this->curItem->setID( $this->curItem->GetDBField($this->curItem->IDField) );
}
/**
* Sets value of import/export object
* @param int $field_index
* @param mixed $value
* @return void
* @access protected
*/
protected function setFieldValue($field_index, $value)
{
if ( empty($value) ) {
$value = null;
}
$field_name = getArrayValue($this->exportFields, $field_index);
if ( $field_name == 'ResourceId' ) {
return ;
}
if ( substr($field_name, 0, 7) == 'Custom_' ) {
$field_name = 'cust_' . substr($field_name, 7);
$this->curItem->SetField($field_name, $value);
}
elseif ( $field_name == 'CategoryPath' || $field_name == '__CATEGORY__CategoryPath' ) {
$this->curItem->CategoryPath = $value ? explode($this->exportOptions['CategorySeparator'], $value) : Array ();
}
elseif ( substr($field_name, 0, 8) == 'Category' ) {
$this->curItem->CategoryPath[(int)substr($field_name, 8) - 1] = $value;
}
elseif ( substr($field_name, 0, 20) == '__CATEGORY__Category' ) {
$this->curItem->CategoryPath[(int)substr($field_name, 20) - 1] = $value;
}
elseif ( substr($field_name, 0, 11) == '__VIRTUAL__' ) {
$field_name = substr($field_name, 11);
$this->curItem->SetField($field_name, $value);
}
else {
$this->curItem->SetField($field_name, $value);
}
if ( $this->curItem->GetErrorPseudo($field_name) ) {
$this->curItem->SetDBField($field_name, null);
$this->curItem->RemoveError($field_name);
}
}
/**
* Resets import object
*
* @param kEvent $event
* @param int $object_type
* @param Array $record_data
* @return void
*/
- function resetImportObject(&$event, $object_type, $record_data = null)
+ function resetImportObject($event, $object_type, $record_data = null)
{
switch ($object_type) {
case IMPORT_TEMP:
$this->curItem =& $event->getObject( Array('skip_autoload' => true) );
break;
case IMPORT_LIVE:
$this->curItem =& $this->Application->recallObject($event->Prefix.'.-tmpitem'.$event->Special, $event->Prefix, Array('skip_autoload' => true));
break;
}
$this->curItem->Clear();
$this->curItem->SetDBField('CategoryId', NULL); // since default value is import root category
$this->customFields = $this->Application->getUnitOption($event->Prefix, 'CustomFields');
if (isset($record_data)) {
$this->setImportData($record_data);
}
}
function setImportData($record_data)
{
foreach ($record_data as $field_index => $field_value) {
$this->setFieldValue($field_index, $field_value);
}
$this->setCurrentID();
}
function getItemCategory()
{
static $lang_prefix = null;
$backup_category_id = $this->Application->GetVar('m_cat_id');
$category_id = $this->getFromCache('category_names', implode(':', $this->curItem->CategoryPath));
if ($category_id) {
$this->Application->SetVar('m_cat_id', $category_id);
return $category_id;
}
if (is_null($lang_prefix)) {
$lang_prefix = 'l'.$this->Application->GetVar('m_lang').'_';
}
foreach ($this->curItem->CategoryPath as $category_index => $category_name) {
if (!$category_name) continue;
$category_key = crc32( implode(':', array_slice($this->curItem->CategoryPath, 0, $category_index + 1) ) );
$category_id = $this->getFromCache('category_names', $category_key);
if ($category_id === false) {
// get parent category path to search only in it
$current_category_id = $this->Application->GetVar('m_cat_id');
// $parent_path = $this->getParentPath($current_category_id);
// get category id from database by name
$sql = 'SELECT CategoryId
FROM '.TABLE_PREFIX.'Categories
WHERE ('.$lang_prefix.'Name = '.$this->Conn->qstr($category_name).') AND (ParentId = '.(int)$current_category_id.')';
$category_id = $this->Conn->GetOne($sql);
if ( $category_id === false ) {
// category not in db -> create
$category_fields = Array (
$lang_prefix.'Name' => $category_name, $lang_prefix.'Description' => $category_name,
'Status' => STATUS_ACTIVE, 'ParentId' => $current_category_id, 'AutomaticFilename' => 1
);
$this->dummyCategory->Clear();
$this->dummyCategory->SetDBFieldsFromHash($category_fields);
if ( $this->dummyCategory->Create() ) {
$category_id = $this->dummyCategory->GetID();
$this->addToCache('category_parent_path', $category_id, $this->dummyCategory->GetDBField('ParentPath'));
$this->addToCache('category_names', $category_key, $category_id);
}
}
else {
$this->addToCache('category_names', $category_key, $category_id);
}
}
if ($category_id) {
$this->Application->SetVar('m_cat_id', $category_id);
}
}
if (!$this->curItem->CategoryPath) {
$category_id = $backup_category_id;
}
return $category_id;
}
/**
* Enter description here...
*
* @param kEvent $event
* @param Array $record_data
* @return bool
*/
- function processCurrentItem(&$event, $record_data)
+ function processCurrentItem($event, $record_data)
{
$save_method = 'Create';
$load_keys = Array();
// create/update categories
$backup_category_id = $this->Application->GetVar('m_cat_id');
// perform replace duplicates code
if ($this->exportOptions['ReplaceDuplicates']) {
// get replace keys first, then reset current item to empty one
$category_id = $this->getItemCategory();
if ($this->exportOptions['CheckDuplicatesMethod'] == 1) {
if ($this->curItem->GetID()) {
$load_keys = Array($this->curItem->IDField => $this->curItem->GetID());
}
}
else {
$key_fields = $this->exportOptions['DuplicateCheckFields'];
foreach ($key_fields as $key_field) {
$load_keys[$key_field] = $this->curItem->GetDBField($key_field);
}
}
$this->resetImportObject($event, IMPORT_LIVE);
if (count($load_keys)) {
$where_clause = '';
$language_id = (int)$this->Application->GetVar('m_lang');
if (!$language_id) {
$language_id = 1;
}
foreach ($load_keys as $field_name => $field_value) {
if (preg_match('/^cust_(.*)/', $field_name, $regs)) {
$custom_id = array_search($regs[1], $this->customFields);
$field_name = 'l'.$language_id.'_cust_'.$custom_id;
$where_clause .= '(custom_data.`'.$field_name.'` = '.$this->Conn->qstr($field_value).') AND ';
}
else {
$where_clause .= '(item_table.`'.$field_name.'` = '.$this->Conn->qstr($field_value).') AND ';
}
}
$where_clause = substr($where_clause, 0, -5);
$item_id = $this->getFromCache('new_ids', crc32($where_clause));
if (!$item_id) {
if ($this->exportOptions['CheckDuplicatesMethod'] == 2) {
// by other fields
$parent_path = $this->getParentPath($category_id);
$where_clause = '(c.ParentPath LIKE "'.$parent_path.'%") AND '.$where_clause;
}
$cdata_table = $this->Application->getUnitOption($event->Prefix.'-cdata', 'TableName');
$sql = 'SELECT '.$this->curItem->IDField.'
FROM '.$this->curItem->TableName.' item_table
LEFT JOIN '.$cdata_table.' custom_data ON custom_data.ResourceId = item_table.ResourceId
LEFT JOIN '.TABLE_PREFIX.'CategoryItems ci ON ci.ItemResourceId = item_table.ResourceId
LEFT JOIN '.TABLE_PREFIX.'Categories c ON c.CategoryId = ci.CategoryId
WHERE '.$where_clause;
$item_id = $this->Conn->GetOne($sql);
}
$save_method = $item_id && $this->curItem->Load($item_id) ? 'Update' : 'Create';
if ($save_method == 'Update') {
// replace id from csv file with found id (only when ID is found in cvs file)
if (in_array($this->curItem->IDField, $this->exportFields)) {
$record_data[ array_search($this->curItem->IDField, $this->exportFields) ] = $item_id;
}
}
}
$this->setImportData($record_data);
}
else {
$this->resetImportObject($event, IMPORT_LIVE, $record_data);
$category_id = $this->getItemCategory();
}
// create main record
if ($save_method == 'Create') {
$this->fillRequiredFields($this->false, $this->curItem, true);
}
// $sql_start = microtime(true);
if (!$this->curItem->$save_method()) {
$this->Application->SetVar('m_cat_id', $backup_category_id);
return false;
}
// $sql_end = microtime(true);
// $this->saveLog('SQL ['.$save_method.'] Time: '.($sql_end - $sql_start).'s');
if ($load_keys && ($save_method == 'Create') && $this->exportOptions['ReplaceDuplicates']) {
// map new id to old id
$this->addToCache('new_ids', crc32($where_clause), $this->curItem->GetID() );
}
// assign item to categories
$this->curItem->assignToCategory($category_id, false);
$this->Application->SetVar('m_cat_id', $backup_category_id);
return true;
}
/*function saveLog($msg)
{
static $first_time = true;
$fp = fopen((defined('RESTRICTED') ? RESTRICTED : FULL_PATH) . '/sqls.log', $first_time ? 'w' : 'a');
fwrite($fp, $msg."\n");
fclose($fp);
$first_time = false;
}*/
/**
* Returns category parent path, if possible, then from cache
*
* @param int $category_id
* @return string
*/
function getParentPath($category_id)
{
$parent_path = $this->getFromCache('category_parent_path', $category_id);
if ($parent_path === false) {
$sql = 'SELECT ParentPath
FROM '.TABLE_PREFIX.'Categories
WHERE CategoryId = '.$category_id;
$parent_path = $this->Conn->GetOne($sql);
$this->addToCache('category_parent_path', $category_id, $parent_path);
}
return $parent_path;
}
function getFileExtension()
{
return $this->exportOptions['ExportFormat'] == 1 ? 'csv' : 'xml';
}
function getLineSeparator($option = 'LineEndings')
{
return $this->exportOptions[$option] == 1 ? "\r\n" : "\n";
}
/**
* Returns field caption for any exported field
*
* @param string $field
* @return string
*/
function getFieldCaption($field)
{
if (substr($field, 0, 10) == '__CUSTOM__')
{
$ret = 'Custom_'.substr($field, 10, strlen($field) );
}
elseif (substr($field, 0, 12) == '__CATEGORY__')
{
return $this->getCategoryTitle();
}
elseif (substr($field, 0, 11) == '__VIRTUAL__') {
$ret = substr($field, 11);
}
else
{
$ret = $field;
}
return Array($ret);
}
/**
* Returns requested field value (including custom fields and category fields)
*
* @param string $field
* @return string
*/
function getFieldValue($field)
{
if (substr($field, 0, 10) == '__CUSTOM__') {
$field = 'cust_'.substr($field, 10, strlen($field));
$ret = $this->curItem->GetField($field);
}
elseif (substr($field, 0, 12) == '__CATEGORY__') {
return $this->getCategoryPath();
}
elseif (substr($field, 0, 11) == '__VIRTUAL__') {
$field = substr($field, 11);
$ret = $this->curItem->GetField($field);
}
else
{
$ret = $this->curItem->GetField($field);
}
$ret = str_replace("\r\n", $this->getLineSeparator('LineEndingsInside'), $ret);
return Array($ret);
}
/**
* Returns category field(-s) caption based on export mode
*
* @return string
*/
function getCategoryTitle()
{
// category path in separated fields
$category_count = $this->getMaxCategoryLevel();
if ($this->exportOptions['CategoryFormat'] == 1)
{
// category path in one field
return $category_count ? Array('CategoryPath') : Array();
}
else
{
$i = 0;
$ret = Array();
while ($i < $category_count) {
$ret[] = 'Category'.($i + 1);
$i++;
}
return $ret;
}
}
/**
* Returns category path in required format for current link
*
* @return string
*/
function getCategoryPath()
{
$category_id = $this->curItem->GetDBField('CategoryId');
$category_path = $this->getFromCache('category_path', $category_id);
if ( !$category_path ) {
$ml_formatter =& $this->Application->recallObject('kMultiLanguage');
/* @var $ml_formatter kMultiLanguage */
$sql = 'SELECT ' . $ml_formatter->LangFieldName('CachedNavbar') . '
FROM ' . TABLE_PREFIX . 'Categories
WHERE CategoryId = ' . $category_id;
$category_path = $this->Conn->GetOne($sql);
$category_path = $category_path ? explode('&|&', $category_path) : Array ();
if ( $category_path && strtolower($category_path[0]) == 'content' ) {
array_shift($category_path);
}
if ( $this->exportOptions['IsBaseCategory'] ) {
$i = $this->exportOptions['BaseLevel'];
while ( $i > 0 ) {
array_shift($category_path);
$i--;
}
}
$category_count = $this->getMaxCategoryLevel();
if ( $this->exportOptions['CategoryFormat'] == 1 ) {
// category path in single field
$category_path = $category_count ? Array (implode($this->exportOptions['CategorySeparator'], $category_path)) : Array ();
}
else {
// category path in separated fields
$levels_used = count($category_path);
if ( $levels_used < $category_count ) {
$i = 0;
while ( $i < $category_count - $levels_used ) {
$category_path[] = '';
$i++;
}
}
}
$this->addToCache('category_path', $category_id, $category_path);
}
return $category_path;
}
/**
* Get maximal category deep level from links beeing exported
*
* @return int
*/
function getMaxCategoryLevel()
{
static $max_level = -1;
if ($max_level != -1)
{
return $max_level;
}
$sql = 'SELECT IF(c.CategoryId IS NULL, 0, MAX( LENGTH(c.ParentPath) - LENGTH( REPLACE(c.ParentPath, "|", "") ) - 1 ))
FROM '.$this->curItem->TableName.' item_table
LEFT JOIN '.TABLE_PREFIX.'CategoryItems ci ON item_table.ResourceId = ci.ItemResourceId
LEFT JOIN '.TABLE_PREFIX.'Categories c ON c.CategoryId = ci.CategoryId
WHERE (ci.PrimaryCat = 1) AND ';
$where_clause = '';
if ($this->exportOptions['export_ids'] === false) {
// get links from current category & all it's subcategories
if ($this->exportOptions['export_cats_ids'][0] == 0) {
$where_clause = 1;
}
else {
foreach ($this->exportOptions['export_cats_ids'] as $category_id) {
$where_clause .= '(c.ParentPath LIKE "%|'.$category_id.'|%") OR ';
}
$where_clause = substr($where_clause, 0, -4);
}
}
else {
// get only selected links
$where_clause = $this->curItem->IDField.' IN ('.implode(',', $this->exportOptions['export_ids']).')';
}
$max_level = $this->Conn->GetOne($sql.'('.$where_clause.')');
if ($this->exportOptions['IsBaseCategory'] ) {
$max_level -= $this->exportOptions['BaseLevel'];
}
return $max_level;
}
/**
* Saves one record to export file
*
* @param Array $fields_hash
*/
function writeRecord($fields_hash)
{
kUtil::fputcsv($this->filePointer, $fields_hash, $this->exportOptions['FieldsSeparatedBy'], $this->exportOptions['FieldsEnclosedBy'], $this->getLineSeparator() );
}
function readRecord()
{
return fgetcsv($this->filePointer, 10000, $this->exportOptions['FieldsSeparatedBy'], $this->exportOptions['FieldsEnclosedBy']);
}
/**
* Saves import/export options
*
* @param kEvent $event
* @param Array $options
* @return void
*/
- function saveOptions(&$event, $options = null)
+ function saveOptions($event, $options = null)
{
if ( !isset($options) ) {
$options = $this->exportOptions;
}
$this->Application->StoreVar($event->getPrefixSpecial() . '_options', serialize($options));
}
/**
* Loads import/export options
*
* @param kEvent $event
* @return Array
*/
- function loadOptions(&$event)
+ function loadOptions($event)
{
return unserialize( $this->Application->RecallVar($event->getPrefixSpecial() . '_options') );
}
/**
* Sets correct available & export fields
*
* @param kEvent $event
*/
- function prepareExportColumns(&$event)
+ function prepareExportColumns($event)
{
$object =& $event->getObject( Array('skip_autoload' => true) );
/* @var $object kCatDBItem */
if ( !$object->isField('ExportColumns') ) {
// import/export prefix was used (see kDBEventHandler::prepareObject) but object don't plan to be imported/exported
return ;
}
$available_columns = Array();
if ($this->Application->getUnitOption($event->Prefix, 'CatalogItem')) {
// category field (mixed)
$available_columns['__CATEGORY__CategoryPath'] = 'CategoryPath';
if ($event->Special == 'import') {
// category field (separated fields)
$max_level = $this->Application->ConfigValue('MaxImportCategoryLevels');
$i = 0;
while ($i < $max_level) {
$available_columns['__CATEGORY__Category'.($i + 1)] = 'Category'.($i + 1);
$i++;
}
}
}
// db fields
$fields = $object->getFields();
foreach ($fields as $field_name => $field_options) {
if ( !$object->skipField($field_name) ) {
$available_columns[$field_name] = $field_name.( $object->isRequired($field_name) ? '*' : '');
}
}
$handler =& $this->Application->recallObject($event->Prefix.'_EventHandler');
/* @var $handler kDBEventHandler */
$available_columns = array_merge($available_columns, $handler->getCustomExportColumns($event));
// custom fields
$custom_fields = $object->getCustomFields();
foreach ($custom_fields as $custom_id => $custom_name)
{
$available_columns['__CUSTOM__'.$custom_name] = $custom_name;
}
// columns already in use
$items_info = $this->Application->GetVar( $event->getPrefixSpecial(true) );
if ($items_info)
{
list($item_id, $field_values) = each($items_info);
$export_keys = $field_values['ExportColumns'];
$export_keys = $export_keys ? explode('|', substr($export_keys, 1, -1) ) : Array();
}
else {
$export_keys = Array();
}
$export_columns = Array();
foreach ($export_keys as $field_key)
{
$field_name = $this->getExportField($field_key);
$export_columns[$field_key] = $field_name;
unset($available_columns[$field_key]);
}
$options = $object->GetFieldOptions('ExportColumns');
$options['options'] = $export_columns;
$object->SetFieldOptions('ExportColumns', $options);
$options = $object->GetFieldOptions('AvailableColumns');
$options['options'] = $available_columns;
$object->SetFieldOptions('AvailableColumns', $options);
$this->updateImportFiles($event);
$this->PrepareExportPresets($event);
}
/**
* Prepares export presets
*
* @param kEvent $event
* @return void
*/
- function PrepareExportPresets(&$event)
+ function PrepareExportPresets($event)
{
$object =& $event->getObject(Array ('skip_autoload' => true));
/* @var $object kDBItem */
$options = $object->GetFieldOptions('ExportPresets');
$export_settings = $this->Application->RecallPersistentVar('export_settings');
if ( !$export_settings ) {
return;
}
$export_settings = unserialize($export_settings);
if ( !isset($export_settings[$event->Prefix]) ) {
return;
}
$export_presets = array ('' => '');
foreach ($export_settings[$event->Prefix] as $key => $val) {
$export_presets[implode('|', $val['ExportColumns'])] = $key;
}
$options['options'] = $export_presets;
$object->SetFieldOptions('ExportPresets', $options);
}
function getExportField($field_key)
{
$prepends = Array('__CUSTOM__', '__CATEGORY__');
foreach ($prepends as $prepend)
{
if (substr($field_key, 0, strlen($prepend) ) == $prepend)
{
$field_key = substr($field_key, strlen($prepend), strlen($field_key) );
break;
}
}
return $field_key;
}
/**
* Updates uploaded files list
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function updateImportFiles(&$event)
+ protected function updateImportFiles($event)
{
if ( $event->Special != 'import' ) {
return ;
}
$file_helper =& $this->Application->recallObject('FileHelper');
/* @var $file_helper FileHelper */
$import_filenames = Array ();
$file_helper->CheckFolder(EXPORT_PATH);
$iterator = new DirectoryIterator(EXPORT_PATH);
/* @var $file_info DirectoryIterator */
foreach ($iterator as $file_info) {
$file = $file_info->getFilename();
if ( $file_info->isDir() || $file == 'dummy' || $file_info->getSize() == 0 ) {
continue;
}
$import_filenames[$file] = $file . ' (' . kUtil::formatSize( $file_info->getSize() ) . ')';
}
$object =& $event->getObject();
/* @var $object kDBItem */
$object->SetFieldOption('ImportLocalFilename', 'options', $import_filenames);
}
/**
* Returns module folder
*
* @param kEvent $event
* @return string
*/
- function getModuleName(&$event)
+ function getModuleName($event)
{
$module_path = $this->Application->getUnitOption($event->Prefix, 'ModuleFolder') . '/';
$module_name = $this->Application->findModule('Path', $module_path, 'Name');
return mb_strtolower($module_name);
}
/**
* Export form validation & processing
*
* @param kEvent $event
*/
- function OnExportBegin(&$event)
+ function OnExportBegin($event)
{
$items_info = $this->Application->GetVar($event->getPrefixSpecial(true));
if ( !$items_info ) {
$items_info = unserialize($this->Application->RecallVar($event->getPrefixSpecial() . '_ItemsInfo'));
$this->Application->SetVar($event->getPrefixSpecial(true), $items_info);
}
list($item_id, $field_values) = each($items_info);
$object =& $event->getObject(Array ('skip_autoload' => true));
/* @var $object kDBItem */
$object->SetFieldsFromHash($field_values, $this->getRequestProtectedFields($field_values));
$field_values['ImportFilename'] = $object->GetDBField('ImportFilename'); //if upload formatter has renamed the file during moving !!!
$object->setID($item_id);
$this->setRequiredFields($event);
// save export/import options
if ( $event->Special == 'export' ) {
$export_ids = $this->Application->RecallVar($event->Prefix . '_export_ids');
$export_cats_ids = $this->Application->RecallVar($event->Prefix . '_export_cats_ids');
// used for multistep export
$field_values['export_ids'] = $export_ids ? explode(',', $export_ids) : false;
$field_values['export_cats_ids'] = $export_cats_ids ? explode(',', $export_cats_ids) : Array ($this->Application->GetVar('m_cat_id'));
}
$field_values['ExportColumns'] = $field_values['ExportColumns'] ? explode('|', substr($field_values['ExportColumns'], 1, -1) ) : Array();
$field_values['start_from'] = 0;
$nevent = new kEvent($event->Prefix . ':OnBeforeExportBegin');
$nevent->setEventParam('options', $field_values);
$this->Application->HandleEvent($nevent);
$field_values = $nevent->getEventParam('options');
$this->saveOptions($event, $field_values);
if ( $this->verifyOptions($event) ) {
if ( $this->_getExportSavePreset($object) ) {
$name = $object->GetDBField('ExportPresetName');
$export_settings = $this->Application->RecallPersistentVar('export_settings');
$export_settings = $export_settings ? unserialize($export_settings) : array ();
$export_settings[$event->Prefix][$name] = $field_values;
$this->Application->StorePersistentVar('export_settings', serialize($export_settings));
}
$progress_t = $this->Application->RecallVar('export_progress_t');
if ( $progress_t ) {
$this->Application->RemoveVar('export_progress_t');
}
else {
$progress_t = $this->getModuleName($event) . '/' . $event->Special . '_progress';
}
$event->redirect = $progress_t;
if ( $event->Special == 'import' ) {
$import_category = (int)$this->Application->RecallVar('ImportCategory');
// in future could use module root category if import category will be unavailable :)
$event->SetRedirectParam('m_cat_id', $import_category); // for template permission checking
$this->Application->StoreVar('m_cat_id', $import_category); // for event permission checking
}
}
else {
// make uploaded file local & change source selection
$filename = getArrayValue($field_values, 'ImportFilename');
if ( $filename ) {
$this->updateImportFiles($event);
$object->SetDBField('ImportSource', 2);
$field_values['ImportSource'] = 2;
$object->SetDBField('ImportLocalFilename', $filename);
$field_values['ImportLocalFilename'] = $filename;
$this->saveOptions($event, $field_values);
}
$event->status = kEvent::erFAIL;
$event->redirect = false;
}
}
/**
* Returns export save preset name, when used at all
*
* @param kDBItem $object
* @return string
*/
function _getExportSavePreset(&$object)
{
if ( !$object->isField('ExportSavePreset') ) {
return '';
}
return $object->GetDBField('ExportSavePreset');
}
/**
* set required fields based on import or export params
*
* @param kEvent $event
*/
- function setRequiredFields(&$event)
+ function setRequiredFields($event)
{
$required_fields['common'] = Array('FieldsSeparatedBy', 'LineEndings', 'CategoryFormat');
$required_fields['export'] = Array('ExportFormat', 'ExportFilename','ExportColumns');
$object =& $event->getObject();
/* @var $object kDBItem */
if ($this->_getExportSavePreset($object)) {
$required_fields['export'][] = 'ExportPresetName';
}
$required_fields['import'] = Array('FieldTitles', 'ImportSource', 'CheckDuplicatesMethod'); // ImportFilename, ImportLocalFilename
if ($event->Special == 'import')
{
$import_source = Array(1 => 'ImportFilename', 2 => 'ImportLocalFilename');
$used_field = $import_source[ $object->GetDBField('ImportSource') ];
$required_fields[$event->Special][] = $used_field;
$object->SetFieldOption($used_field, 'error_field', 'ImportSource');
if ($object->GetDBField('FieldTitles') == 2) $required_fields[$event->Special][] = 'ExportColumns'; // manual field titles
}
$required_fields = array_merge($required_fields['common'], $required_fields[$event->Special]);
$object->setRequired($required_fields);
}
}
\ No newline at end of file
Index: branches/5.2.x/core/units/helpers/brackets_helper.php
===================================================================
--- branches/5.2.x/core/units/helpers/brackets_helper.php (revision 15129)
+++ branches/5.2.x/core/units/helpers/brackets_helper.php (revision 15130)
@@ -1,476 +1,476 @@
<?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 kBracketsHelper extends kHelper {
/**
* Field name holding minimal amount
*
* @var string
*/
var $min_field = '';
/**
* Field name holding maximal amount
*
* @var string
*/
var $max_field = '';
/**
* Default values to be set to automtically created price brackets
*
* @var Array
*/
var $default_values = Array();
var $defaultStartValue = 1;
/**
* Decimal separator
*
* @var string
*/
var $_decimalSeparator = '';
/**
* Thousands separator
*
* @var string
*/
var $_thousandsSeparator = '';
/**
* Current language
*
* @var LanguagesItem
*/
var $_language = null;
public function __construct()
{
parent::__construct();
$this->_language =& $this->Application->recallObject('lang.current');
/* @var $lang kDBItem */
$this->_decimalSeparator = $this->_language->GetDBField('DecimalPoint');
$this->_thousandsSeparator = $this->_language->GetDBField('ThousandSep');
}
function InitHelper($min_field, $max_field, $default_values, $default_start_value = null)
{
$this->min_field = $min_field;
$this->max_field = $max_field;
$this->default_values = $default_values;
if (isset($default_start_value)) {
$this->defaultStartValue = $default_start_value;
}
}
/**
* Converts number to operatable form
*
* @param string $value
* @return float
*/
function _parseNumber($value)
{
$value = str_replace($this->_thousandsSeparator, '', $value);
$value = str_replace($this->_decimalSeparator, '.', $value);
return $value;
}
/**
* Returns brackets from form with all numbers parsed
*
* @param kEvent $event
* @return Array
*/
- function getBrackets(&$event)
+ function getBrackets($event)
{
$items_info = $this->Application->GetVar( $event->getPrefixSpecial(true) );
return $this->parseBrackets($items_info);
}
function parseBrackets($brackets)
{
if (!$brackets) {
return $brackets;
}
foreach ($brackets as $id => $field_values) {
if (strlen($brackets[$id][$this->min_field])) {
$brackets[$id][$this->min_field] = (float)$this->_parseNumber($brackets[$id][$this->min_field]);
}
if (strlen($brackets[$id][$this->max_field])) {
$brackets[$id][$this->max_field] = (float)$this->_parseNumber($brackets[$id][$this->max_field]);
}
}
return $brackets;
}
/**
* Formats given brackets and sets them back to request
*
* @param kEvent $event
* @param Array $brackets
*/
- function setBrackets(&$event, $brackets)
+ function setBrackets($event, $brackets)
{
$brackets = $this->formatBrackets($brackets);
$this->Application->SetVar($event->getPrefixSpecial(true), $brackets);
}
function formatBrackets($brackets)
{
if (!$brackets) {
return $brackets;
}
foreach ($brackets as $id => $field_values) {
if (strlen($brackets[$id][$this->min_field])) {
$brackets[$id][$this->min_field] = $this->_language->formatNumber($brackets[$id][$this->min_field]);
}
if (strlen($brackets[$id][$this->max_field])) {
$brackets[$id][$this->max_field] = $this->_language->formatNumber($brackets[$id][$this->max_field]);
}
}
return $brackets;
}
/**
* Adds 5 more empty brackets to brackets
*
* @param kEvent $event
*/
- function OnMoreBrackets(&$event)
+ function OnMoreBrackets($event)
{
$field_values = $this->getBrackets($event);
$object =& $event->getObject();
foreach($field_values as $id => $record)
{
if($record[$this->max_field] == '&#8734;') $field_values[$id][$this->max_field] = -1;
}
$new_id = (int)$this->Conn->GetOne('SELECT MIN('.$object->IDField.') FROM '.$object->TableName);
if($new_id > 0) $new_id = 0;
do
{
$new_id--;
}while( $this->arraySearch($field_values, $object->IDField, $new_id) );
$last_max_qty = $this->Conn->GetOne('SELECT MAX('.$this->max_field.') FROM '.$object->TableName);
$min_qty = $this->Conn->GetOne('SELECT MIN('.$this->max_field.') FROM '.$object->TableName);
if($min_qty == -1) $last_max_qty = -1;
if(!$last_max_qty) $last_max_qty = $this->defaultStartValue;
for($i = $new_id; $i > $new_id - 5; $i--)
{
$field_values[$i][$object->IDField] = $i;
$field_values[$i][$this->min_field] = ($i == $new_id-4 && $last_max_qty != -1) ? $last_max_qty : '';
$field_values[$i][$this->max_field] = ($i == $new_id-4 && $last_max_qty != -1) ? -1 : '';
$field_values[$i] = array_merge($field_values[$i], $this->default_values);
}
$event->CallSubEvent('OnPreSaveBrackets');
$this->setBrackets($event, $field_values);
}
/**
* Adds infinity bracket
*
* @param kEvent $event
*/
- function OnInfinity(&$event)
+ function OnInfinity($event)
{
$object =& $event->getObject();
$infinite_exists = $this->Conn->GetOne('SELECT COUNT(*) FROM '.$object->TableName.' WHERE '.$this->max_field.' = -1');
$field_values = $this->getBrackets($event);
/*if(is_array($field_values))
{
foreach($field_values as $values)
{
$infinite_exists = $infinite_exists || ($values[$this->max_field] == -1);
}
}*/
if ($infinite_exists == 0) {
reset($field_values);
$last_bracket = end($field_values);
$new_id = (int)$this->Conn->GetOne('SELECT MIN('.$object->IDField.') FROM '.$object->TableName);
$brackets_exist = (int)$this->Conn->GetOne('SELECT COUNT(*) FROM '.$object->TableName);
if($new_id > 0) $new_id = 0;
do
{
$new_id--;
}while( $this->arraySearch($field_values, $object->IDField, $new_id) );
$infinite_bracket[$object->IDField] = $new_id;
$infinite_bracket[$this->min_field] = ($brackets_exist > 0) ? $last_bracket[$this->max_field] : $this->defaultStartValue;
$infinite_bracket[$this->max_field] = '-1';
$infinite_bracket = array_merge($infinite_bracket, $this->default_values);
$field_values[$new_id] = $infinite_bracket;
reset($field_values);
$this->setBrackets($event, $field_values);
}
}
/**
* Saves brackets to database
*
* @param kEvent $event
*/
- function OnPreSaveBrackets(&$event)
+ function OnPreSaveBrackets($event)
{
$items_info = $this->getBrackets($event);
if ($items_info) {
$object =& $event->getObject();
/* @var $object kDBItem */
$linked_info = $object->getLinkedInfo();
$stored_ids = $this->Conn->GetCol('SELECT '.$object->IDField.' FROM '.$object->TableName.' WHERE '.$linked_info['ForeignKey'].' = '.$linked_info['ParentId']);
uasort($items_info, Array(&$this, 'compareBrackets') );
foreach ($items_info as $item_id => $values) {
if (in_array($item_id, $stored_ids)) { //if it's already exist
$object->Load($item_id);
$object->SetFieldsFromHash($values/*, $this->getRequestProtectedFields($values)*/);
if (!$object->Validate()) {
unset($stored_ids[array_search($item_id, $stored_ids)]);
$event->redirect = false;
continue;
}
if( $object->Update($item_id) )
{
$event->status = kEvent::erSUCCESS;
}
else
{
$event->status = kEvent::erFAIL;
$event->redirect = false;
break;
}
unset( $stored_ids[ array_search($item_id, $stored_ids) ] );
}
else {
$object->Clear();
$object->SetFieldsFromHash($values/*, $this->getRequestProtectedFields($values)*/);
$object->SetDBField($linked_info['ForeignKey'], $linked_info['ParentId']);
if ($object->Create()) {
$event->status = kEvent::erSUCCESS;
}
}
}
// delete
foreach ($stored_ids as $stored_id)
{
$this->Conn->Query('DELETE FROM '.$object->TableName.' WHERE '.$object->IDField.' = '.$stored_id);
}
}
}
/**
* Sorts brackets and returns sorted array
*
* @param kEvent $event
* @return Array
*/
- function arrangeBrackets(&$event)
+ function arrangeBrackets($event)
{
$object =& $event->getObject();
/* @var $object kDBItem */
$temp = $this->getBrackets($event);
foreach ($temp as $id => $record) {
if ( $record[$this->max_field] == '&#8734;' ) {
$temp[$id][$this->max_field] = -1;
}
}
$temp_orig = $temp;
reset($temp);
if( is_array($temp) )
{
// array to store max values (2nd column)
$end_values = Array();
// get minimal value of Min
$first_elem = current($temp);
$start = $first_elem[$this->min_field];
if (!strlen($start)) {
$start = $this->defaultStartValue;
}
foreach($temp as $id => $record)
{
if(
// MAX is less than start
($record[$this->max_field] <= $start && $record[$this->max_field] != -1) ||
// Max is empty
!strlen($record[$this->max_field]) ||
// Max already defined in $end_values
(array_search($record[$this->max_field], $end_values) !== false)
) { // then delete from brackets list
unset($temp[$id]);
}
else { // this is when ok - add to end_values list
$end_values[] = $record[$this->max_field];
}
}
// sort brackets by 2nd column (Max values)
uasort($temp, Array (&$this, 'compareBrackets'));
reset($temp);
$first_item = each($temp);
$first_item_key = $first_item['key'];
$linked_info = $object->getLinkedInfo();
$sql = 'SELECT %s FROM %s WHERE %s = %s';
$ids = $this->Conn->GetCol( sprintf($sql, $object->IDField, $object->TableName, $linked_info['ForeignKey'], $linked_info['ParentId']) );
if ( is_array($ids) ) {
usort($ids, Array (&$this, 'sortBracketIDs'));
}
// $min_id = min( min($ids) - 1, -1 );
foreach ($temp as $key => $record) {
$temp[$key][$this->min_field] = $start;
$start = $temp[$key][$this->max_field];
}
}
$this->setBrackets($event, $temp);
return $temp;
}
function compareBrackets($bracket1, $bracket2) // ap_bracket_comp
{
$bracket1_min = $bracket1[$this->min_field];
$bracket1_max = $bracket1[$this->max_field];
$bracket2_min = $bracket2[$this->min_field];
$bracket2_max = $bracket2[$this->max_field];
// limits
if( ($bracket1_min != '') && ($bracket1_max == '') && ($bracket2_min != '') && ($bracket2_max != '') ) return 1;
if( ($bracket1_min != '') && ($bracket1_max == '') && ($bracket2_min == '') && ($bracket2_max == '') ) return -1;
if( ($bracket1_max == '') && ($bracket2_max != '') ) return 1;
if( ($bracket1_max != '') && ($bracket2_max == '') ) return -1;
if( ( ($bracket1_max > $bracket2_max) && ($bracket2_max != -1) ) || ( ($bracket1_max == -1) && ($bracket2_max != -1) ) )
{
return 1;
}
elseif( ($bracket1_max < $bracket2_max) || ( ($bracket2_max == -1) && ($bracket1_max != -1) ) )
{
return -1;
}
else
{
return 0;
}
}
function sortBracketIDs($first_id, $second_id) // pr_bracket_id_sort
{
$first_abs = abs($first_id);
$second_abs = abs($second_id);
$first_sign = ($first_id == 0) ? 0 : $first_id / $first_abs;
$second_sign = ($second_id == 0) ? 0 : $second_id / $second_abs;
if($first_sign != $second_sign)
{
if($first_id > $second_id)
{
$bigger =& $first_abs;
$smaller =& $second_abs;
}
else
{
$bigger =& $second_abs;
$smaller =& $first_abs;
}
$smaller = $bigger + $smaller;
}
return ($first_abs > $second_abs) ? 1 : ($first_abs < $second_abs ? -1 : 0);
}
/**
* Searches through submitted grid data to find record with specific value in specific field
*
* @param Array $records // grid data from REQUEST
* @param string $field
* @param string $value
* @return bool
*/
function arraySearch($records, $field, $value) // check_array
{
foreach ($records as $record)
{
if ($record[$field] == $value)
{
return true;
}
}
return false;
}
/**
* Replace infinity mark with -1 before saving to db
*
* @param kEvent $event
*/
- function replaceInfinity(&$event)
+ function replaceInfinity($event)
{
$object =& $event->getObject();
/* @var $object kDBItem */
if ( $object->GetDBField($this->max_field) == '&#8734;' ) {
$object->SetDBField($this->max_field, -1);
}
}
}
\ No newline at end of file
Index: branches/5.2.x/core/units/helpers/minifiers/minifiers_config.php
===================================================================
--- branches/5.2.x/core/units/helpers/minifiers/minifiers_config.php (revision 15129)
+++ branches/5.2.x/core/units/helpers/minifiers/minifiers_config.php (revision 15130)
@@ -1,26 +1,26 @@
<?php
/**
* @version $Id$
* @package In-Portal
* @copyright Copyright (C) 1997 - 2010 Intechnic. All rights reserved.
* @license GNU/GPL
* In-Portal is Open Source software.
* This means that this software may have been modified pursuant
* the GNU General Public License, and as distributed it includes
* or is derivative of works licensed under the GNU General Public License
* or other free or open source software licenses.
* See http://www.in-portal.org/license for copyright notices and details.
*/
defined('FULL_PATH') or die('restricted access!');
$config = Array (
'Prefix' => 'minify-helpers',
'EventHandlerClass' => Array ('class' => 'kEventHandler', 'file' => '', 'build_event' => 'OnBuild'),
'RegisterClasses' => Array (
- Array ('pseudo' => 'CssMinifyHelper', 'class' => 'CssMinifyHelper', 'file' => 'css_minify_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'),
- Array ('pseudo' => 'JsMinifyHelper', 'class' => 'JsMinifyHelper', 'file' => 'js_minify_helper.php', 'build_event' => '', 'require_classes' => Array ('kHelper')),
- Array ('pseudo' => 'MinifyHelper', 'class' => 'MinifyHelper', 'file' => 'minify_helper.php', 'build_event' => '', 'require_classes' => Array ('kHelper')),
+ Array ('pseudo' => 'CssMinifyHelper', 'class' => 'CssMinifyHelper', 'file' => 'css_minify_helper.php', 'build_event' => ''),
+ Array ('pseudo' => 'JsMinifyHelper', 'class' => 'JsMinifyHelper', 'file' => 'js_minify_helper.php', 'build_event' => ''),
+ Array ('pseudo' => 'MinifyHelper', 'class' => 'MinifyHelper', 'file' => 'minify_helper.php', 'build_event' => ''),
),
);
\ No newline at end of file
Index: branches/5.2.x/core/units/helpers/captcha_helper.php
===================================================================
--- branches/5.2.x/core/units/helpers/captcha_helper.php (revision 15129)
+++ branches/5.2.x/core/units/helpers/captcha_helper.php (revision 15130)
@@ -1,185 +1,185 @@
<?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 kCaptchaHelper extends kHelper {
var $width;
var $height;
function GenerateCaptchaCode($len = 5)
{
$chars = '1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
$s = '';
for ($i = 0; $i < $len; $i++) {
$s .= $chars[ rand(0, strlen($chars)-1) ];
}
return $s;
}
function graphics($w, $h)
{
$this->width = $w;
$this->height = $h;
}
function GenerateCaptchaImage($rand, $width, $height, $filter_blur = false)
{
global $site_font_path;
global $site_font_validation;
$image = imagecreate($width, $height);
$bgColor = imagecolorallocate ($image, 255, 255, 255);
$textColor = imagecolorallocate ($image, 0, 0, 0);
// add random noise
for ($i = 0; $i < 20; $i++) {
$rx1 = rand(0, $width);
$rx2 = rand(0, $width);
$ry1 = rand(0, $height);
$ry2 = rand(0, $height);
$rcVal = rand(0, 255);
$rc1 = imagecolorallocate($image, rand(0, 255), rand(0, 255), rand(100, 255));
imageline($image, $rx1, $ry1, $rx2, $ry2, $rc1);
}
// write the random number
$dimensions = imagettfbbox($height*0.75, 0, KERNEL_PATH.'/fonts/monofont.ttf', $rand );
imagettftext($image, $height*0.75, 0, floor(($width - $dimensions[4])/2), floor(($height - $dimensions[5])/2), $textColor, KERNEL_PATH.'/fonts/monofont.ttf', $rand);
// $font = imageloadfont(KERNEL_PATH.'/fonts/monofont.ttf');
// imagestring($image, $font, 3, 0, $rand, $textColor);
if ($filter_blur) $this->blur($image, 3);
// send several headers to make sure the image is not cached
// date in the past
header("Expires: Mon, 23 Jul 1993 05:00:00 GMT");
// always modified
header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
// HTTP/1.1
header("Cache-Control: no-store, no-cache, must-revalidate");
header("Cache-Control: post-check=0, pre-check=0", false);
// HTTP/1.0
header("Pragma: no-cache");
// send the content type header so the image is displayed properly
header('Content-type: image/jpeg');
imagejpeg($image);
imagedestroy($image);
}
function blur(&$gdimg, $radius = 5.0)
{
// Taken from Torstein Hønsi's phpUnsharpMask (see phpthumb.unsharp.php)
$radius = round(max(0, min($radius, 50)) * 2);
if (!$radius) {
return false;
}
$w = ImageSX($gdimg);
$h = ImageSY($gdimg);
$imgBlur = ImageCreateTrueColor($w, $h);
if ($imgBlur) {
// Gaussian blur matrix:
// 1 2 1
// 2 4 2
// 1 2 1
// Move copies of the image around one pixel at the time and merge them with weight
// according to the matrix. The same matrix is simply repeated for higher radii.
for ($i = 0; $i < $radius; $i++) {
ImageCopy ($imgBlur, $gdimg, 0, 0, 1, 1, $w - 1, $h - 1); // up left
ImageCopyMerge($imgBlur, $gdimg, 1, 1, 0, 0, $w, $h, 50.00000); // down right
ImageCopyMerge($imgBlur, $gdimg, 0, 1, 1, 0, $w - 1, $h, 33.33333); // down left
ImageCopyMerge($imgBlur, $gdimg, 1, 0, 0, 1, $w, $h - 1, 25.00000); // up right
ImageCopyMerge($imgBlur, $gdimg, 0, 0, 1, 0, $w - 1, $h, 33.33333); // left
ImageCopyMerge($imgBlur, $gdimg, 1, 0, 0, 0, $w, $h, 25.00000); // right
ImageCopyMerge($imgBlur, $gdimg, 0, 0, 0, 1, $w, $h - 1, 20.00000); // up
ImageCopyMerge($imgBlur, $gdimg, 0, 1, 0, 0, $w, $h, 16.666667); // down
ImageCopyMerge($imgBlur, $gdimg, 0, 0, 0, 0, $w, $h, 50.000000); // center
ImageCopy ($gdimg, $imgBlur, 0, 0, 0, 0, $w, $h);
}
return true;
}
return false;
}
/**
* Generates captcha code for showing on form
*
* @param string $variable_name
*/
function prepareCode($variable_name)
{
if ($this->Application->isAdmin || $this->Application->RecallVar($variable_name)) {
// when code found don't generate it 2nd time
return $this->Application->RecallVar($variable_name);
}
$code = $this->GenerateCaptchaCode();
$this->Application->StoreVar($variable_name, $code);
return $code;
}
/**
* Validates captcha code on form
*
* @param kEvent $event
* @param bool $check_request
* @return bool
*/
- function validateCode(&$event, $check_request = true)
+ function validateCode($event, $check_request = true)
{
if ($this->Application->isAdmin) {
// no captcha codes in admin
return true;
}
if ($check_request) {
// perform validation only when field is found on form
list ($id, $field_values) = each($this->Application->GetVar($event->getPrefixSpecial()));
if (!array_key_exists('Captcha', $field_values)) {
// when captcha code not submitted
return true;
}
}
$object =& $event->getObject();
/* @var $object kDBItem */
$valid_code = $this->Application->RecallVar($event->getPrefixSpecial() . '_captcha_code');
if (!$object->GetDBField('Captcha') || ($object->GetDBField('Captcha') != $valid_code)) {
// empty code OR codes doesn't match
$object->SetError('Captcha', 'captcha_error', 'lu_captcha_error');
$this->Application->StoreVar($event->getPrefixSpecial() . '_captcha_code', $this->GenerateCaptchaCode());
return false;
}
return true;
}
}
\ No newline at end of file
Index: branches/5.2.x/core/units/helpers/permissions_helper.php
===================================================================
--- branches/5.2.x/core/units/helpers/permissions_helper.php (revision 15129)
+++ branches/5.2.x/core/units/helpers/permissions_helper.php (revision 15130)
@@ -1,834 +1,834 @@
<?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 kPermissionsHelper extends kHelper {
/**
* Current set of permissions for group being edited
*
* @var Array
*/
var $Permissions = Array();
function LoadPermissions($group_id, $cat_id, $type = 1, $prefix = '')
{
$perm_table = $this->Application->getUnitOption('perm', 'TableName');
$perm_table = $this->Application->GetTempName($perm_table, 'prefix:'.$prefix);
$sql = 'SELECT *
FROM '.$perm_table.'
WHERE (GroupId = '.$group_id.') AND (CatId = '.$cat_id.') AND (Type = '.$type.')';
$permissions = $this->Conn->Query($sql, 'Permission');
$this->Permissions = Array();
foreach ($permissions as $perm_name => $perm_options) {
$perm_record['value'] = $perm_options['PermissionValue'];
$perm_record['id'] = $perm_options['PermissionId'];
$this->Permissions[$perm_name] = $perm_record;
}
}
function getPermissionValue($perm_name)
{
return isset($this->Permissions[$perm_name]) ? $this->Permissions[$perm_name]['value'] : 0;
}
function getPermissionID($perm_name)
{
return isset($this->Permissions[$perm_name]) ? $this->Permissions[$perm_name]['id'] : 0;
}
/**
* This is old permission like ADMIN or LOGIN
*
* @param string $section_name
* @param string $perm_name
* @return bool
*/
function isOldPermission($section_name, $perm_name)
{
return $section_name == 'in-portal:root' && $perm_name != 'view';
}
/**
* Returns permission names to check based on event name and item prefix (main item or subitem)
*
* @param kEvent $event
* @param Array $perm_mapping
* @return Array
*/
- function getPermissionByEvent(&$event, $perm_mapping)
+ function getPermissionByEvent($event, $perm_mapping)
{
$top_prefix = $event->getEventParam('top_prefix');
$prefix_type = ($top_prefix == $event->Prefix) ? 'self' : 'subitem';
$perm_mapping = getArrayValue($perm_mapping, $event->Name);
if (!$perm_mapping[$prefix_type]) {
throw new Exception('Permission mappings not defined for event <strong>' . $top_prefix . ' <- ' . $event->Prefix . ':' . $event->Name . '</strong>');
}
if ($perm_mapping[$prefix_type] === true) {
// event is defined in mapping but is not checked by permissions
return true;
}
return explode('|', $perm_mapping[$prefix_type]);
}
/**
* Common event permission checking method
*
* @param kEvent $event
* @param Array $perm_mapping
* @return bool
*/
- function CheckEventPermission(&$event, $perm_mapping)
+ function CheckEventPermission($event, $perm_mapping)
{
$section = $event->getSection();
if (preg_match('/^CATEGORY:(.*)/', $section)) {
return $this->CheckEventCategoryPermission($event, $perm_mapping);
}
$top_prefix = $event->getEventParam('top_prefix');
$check_perms = $this->getPermissionByEvent($event, $perm_mapping);
if ($check_perms === true) {
// event is defined in mapping but is not checked by permissions
return true;
}
$perm_status = false;
foreach ($check_perms as $perm_name) {
// check if at least one of required permissions is set
if ($perm_name == 'debug' && $this->Application->isDebugMode(false)) {
// universal "debug" permission
return true;
}
$perm_name = $section.'.'.$perm_name;
$perm_status = $this->CheckPermission($perm_name, 1);
if (($perm_name == $section.'.add') && $perm_status && ($top_prefix == $event->Prefix)) {
// main item, add permission allowed, but ID is > 0, then deny permission
// how to get id here
}
if ($perm_status) {
return $perm_status;
}
}
return $this->finalizePermissionCheck($event, $perm_status);
}
/**
* Returns owner + primary category for each item (used for permission checking)
*
* @param string $prefix
* @param string $ids
* @param bool $temp_mode
* @return Array
* @author Alex
*/
function GetCategoryItemData($prefix, $ids, $temp_mode = false)
{
if (is_array($ids)) {
$ids = implode(',', $ids);
}
$id_field = $this->Application->getUnitOption($prefix, 'IDField');
$table_name = $this->Application->getUnitOption($prefix, 'TableName');
$ci_table = $this->Application->getUnitOption('ci', 'TableName');
if ($temp_mode) {
$table_name = $this->Application->GetTempName($table_name, 'prefix:' . $prefix);
$ci_table = $this->Application->GetTempName($ci_table, 'prefix:' . $prefix);
}
$owner_field = $this->Application->getUnitOption($prefix, 'OwnerField');
if (!$owner_field) {
$owner_field = 'CreatedById';
}
$sql = 'SELECT item_table.'.$id_field.', item_table.'.$owner_field.' AS CreatedById, ci.CategoryId
FROM '.$table_name.' item_table
LEFT JOIN '.$ci_table.' ci ON ci.ItemResourceId = item_table.ResourceId
WHERE item_table.'.$id_field.' IN ('.$ids.') AND (ci.PrimaryCat = 1)';
return $this->Conn->Query($sql, $id_field);
}
/**
* Check category-based permissions for category items
*
* @param kEvent $event
* @param Array $event_perm_mapping
* @return bool
*/
- function _frontCheckEventCategoryPermission(&$event, $event_perm_mapping)
+ function _frontCheckEventCategoryPermission($event, $event_perm_mapping)
{
// mapping between specific permissions and common permissions
static $perm_mapping = Array(
'add' => 'ADD', 'add.pending' => 'ADD.PENDING', 'edit' => 'MODIFY',
'edit.pending' => 'MODIFY.PENDING', 'delete' => 'DELETE', 'view' => 'VIEW',
'debug' => 'DEBUG'
);
$top_prefix = $event->getEventParam('top_prefix');
$event_handler =& $this->Application->recallObject($event->Prefix . '_EventHandler');
/* @var $event_handler kCatDBEventHandler */
$raise_warnings = $event->getEventParam('raise_warnings');
$event->setEventParam('raise_warnings', 0);
if ( $event->Prefix != $top_prefix ) {
$top_event = new kEvent($top_prefix . ':' . $event->Name);
$id = $event_handler->getPassedID($top_event);
}
else {
$id = $event_handler->getPassedID($event);
}
$event->setEventParam('raise_warnings', $raise_warnings);
$owner_id = USER_ROOT; // owner is root if not detected
if ( !$id ) {
// item being created -> check by current (before editing started, saved in OnPreCreate event) category permissions
// note: category in session is placed on catalog data import start
$category_id = $this->Application->isAdmin ? $this->Application->RecallVar('m_cat_id') : $this->Application->GetVar('m_cat_id');
}
elseif ( $top_prefix == 'c' || $top_prefix == 'st' ) {
$category_id = $id;
}
else {
// item being edited -> check by it's primary category permissions
$items_info = $this->GetCategoryItemData($top_prefix, $id);
if ( $items_info ) {
$category_id = $items_info[$id]['CategoryId'];
$owner_id = $items_info[$id]['CreatedById'];
}
else {
// item wasn't found in database
$category_id = $this->Application->GetVar('m_cat_id');
}
}
// specific permission check for pending & owner permissions: begin
$uploader_events = Array ('OnUploadFile', 'OnDeleteFile', 'OnViewFile');
if ( in_array($event->Name, $uploader_events) ) {
// don't recall target object during uploader-related, because OnItemLoad will use incorrect
// $user_id in Firefox (during Flash problems session will be used from Internet Exploere)
$new_item = false;
}
else {
$new_item = $this->Application->isAdminUser && $event_handler->isNewItemCreate($event) ? true : false;
$check_status = $this->checkCombinedPermissions($event, $owner_id, (int)$category_id, $new_item);
}
if ( isset($check_status) ) {
return $this->finalizePermissionCheck($event, $check_status);
}
// specific permission check for pending & owner permissions: end
$perm_status = false;
$check_perms = $this->getPermissionByEvent($event, $event_perm_mapping);
if ( $check_perms === true ) {
// event is defined in mapping but is not checked by permissions
return true;
}
$item_prefix = $this->Application->getUnitOption($top_prefix, 'PermItemPrefix');
foreach ($check_perms as $perm_name) {
// check if at least one of required permissions is set
if ( !isset($perm_mapping[$perm_name]) ) {
// not mapped permission (e.g. advanced:approve) -> skip
continue;
}
if ( $perm_name == 'debug' && $this->Application->isDebugMode(false) ) {
// universal "debug" permission
return true;
}
$perm_name = $item_prefix . '.' . $perm_mapping[$perm_name];
$perm_status = $this->CheckPermission($perm_name, 0, (int)$category_id);
if ( $perm_status ) {
return $perm_status;
}
}
return $this->finalizePermissionCheck($event, $perm_status);
}
/**
* Finalizes permission checking (with additional debug output, when in debug mode)
*
* @param kEvent $event
* @param bool $perm_status
* @return bool
*/
- function finalizePermissionCheck(&$event, $perm_status)
+ function finalizePermissionCheck($event, $perm_status)
{
if (!$perm_status) {
if (MOD_REWRITE) {
// $event->SetRedirectParam('m_cat_id', 0); // category means nothing on admin login screen
$event->SetRedirectParam('next_template', urlencode('external:' . $_SERVER['REQUEST_URI']));
}
else {
$event->SetRedirectParam('next_template', $this->Application->GetVar('t'));
}
if ($this->Application->isDebugMode()) {
// for debugging purposes
$event->SetRedirectParam('section', $event->getSection());
$event->SetRedirectParam('main_prefix', $event->getEventParam('top_prefix'));
$event->SetRedirectParam('event_name', $event->Name);
}
$event->status = kEvent::erPERM_FAIL;
}
return $perm_status;
}
/**
* Allows to check combined permissions (*.owner, *.pending) for add/modify/delete operations from admin & front-end
*
* @param kEvent $event
* @param int $owner_id
* @param int $category_id
* @param bool $new_item
* @return mixed
*/
- function checkCombinedPermissions(&$event, $owner_id, $category_id, $new_item = false)
+ function checkCombinedPermissions($event, $owner_id, $category_id, $new_item = false)
{
$ret = null; // true/false when used, null when not used
$top_prefix = $event->getEventParam('top_prefix');
// check admin permission
if (substr($event->Name, 0, 9) == 'OnPreSave') {
if ($new_item) {
$ret = $this->AddCheckPermission($category_id, $top_prefix);
}
else {
// add & modify because $new_item is false, when item is aready created & then saved in temp table (even with 0 id)
$ret = $this->AddCheckPermission($category_id, $top_prefix) ||
$this->ModifyCheckPermission($owner_id, $category_id, $top_prefix);
}
}
// check front-end permissions
switch ($event->Name) {
case 'OnCreate':
$ret = $this->AddCheckPermission($category_id, $top_prefix);
break;
case 'OnUpdate':
$ret = $this->ModifyCheckPermission($owner_id, $category_id, $top_prefix);
break;
case 'OnDelete':
case 'OnMassDelete':
$ret = $this->DeleteCheckPermission($owner_id, $category_id, $top_prefix);
break;
}
if ($ret === 0) {
// permission check failed (user has no permission)
$event->status = kEvent::erPERM_FAIL;
}
return $ret;
}
/**
* Simplified permission check for category items, when adding/editing them from advanced view.
*
* @param kEvent $event
* @param Array $event_perm_mapping
* @return mixed
*/
- function CheckEventCategoryPermission(&$event, $event_perm_mapping)
+ function CheckEventCategoryPermission($event, $event_perm_mapping)
{
if (!$this->Application->isAdmin) {
// check front-end permission by old scheme
return $this->_frontCheckEventCategoryPermission($event, $event_perm_mapping);
}
if (substr($event->Name, 0, 9) == 'OnPreSave') {
// check separately, because permission mapping is not defined for OnPreSave* events
$check_perms = Array ('add', 'edit');
}
else {
$check_perms = $this->getPermissionByEvent($event, $event_perm_mapping);
}
if ($check_perms === true) {
// event is defined in mapping but is not checked by permissions
return true;
}
// 1. most of events does require admin login only
$perm_status = $this->Application->isAdminUser;
// 2. in case, when event require more, then "view" right, then restrict it to temporary tables only
if (!in_array('view', $check_perms)) {
$perm_status = $perm_status && $this->Application->IsTempMode($event->Prefix, $event->Special);
}
return $this->finalizePermissionCheck($event, $perm_status);
}
function TagPermissionCheck($params, $is_owner = false)
{
$perm_prefix = getArrayValue($params, 'perm_prefix');
$perm_event = getArrayValue($params, 'perm_event');
$permission_groups = getArrayValue($params, 'permissions');
$check_admin = isset($params['admin']) && $params['admin'];
if ($permission_groups && !$perm_event) {
// check permissions by permission names in current category
$permission_groups = explode('|', $permission_groups);
$group_has_permission = false;
$perm_category = isset($params['cat_id']) ? $params['cat_id'] : $this->Application->GetVar('m_cat_id');
if ($perm_prefix) {
// use primary category of item with id from {perm_prefix}_id as base for permission checking
$perm_category = $this->getPrimaryCategory($perm_prefix);
}
$is_system = isset($params['system']) && $params['system'] ? 1 : 0;
foreach ($permission_groups as $permission_group) {
$has_permission = true;
$permissions = explode(',', $permission_group);
if ( $check_admin ) {
foreach ($permissions as $permission) {
$owner_checked = (strpos($permission, '.OWNER.') !== false) ? $is_owner : true;
$has_permission = $has_permission && $this->CheckAdminPermission($permission, $is_system, $perm_category) && $owner_checked;
}
}
else {
foreach ($permissions as $permission) {
$owner_checked = (strpos($permission, '.OWNER.') !== false) ? $is_owner : true;
$has_permission = $has_permission && $this->CheckPermission($permission, $is_system, $perm_category) && $owner_checked;
}
}
$group_has_permission = $group_has_permission || $has_permission;
if ($group_has_permission) {
return true;
}
}
return false;
}
elseif ($perm_event) {
// check permission by event name
list ($prefix, ) = explode(':', $perm_event);
$event_handler =& $this->Application->recallObject($prefix . '_EventHandler');
/* @var $event_handler kEventHandler */
return $event_handler->CheckPermission( new kEvent($perm_event) );
}
return true;
}
/**
* Returns item's primary category (get item_id from request)
*
* @param string $prefix
* @return int
*/
function getPrimaryCategory($prefix)
{
$id_field = $this->Application->getUnitOption($prefix, 'IDField');
$table_name = $this->Application->getUnitOption($prefix, 'TableName');
$id = $this->Application->GetVar($prefix.'_id');
if (!$id) {
return $this->Application->GetVar('m_cat_id');
}
$sql = 'SELECT ResourceId
FROM '.$table_name.'
WHERE '.$id_field.' = '.(int)$id;
$resource_id = $this->Conn->GetOne($sql);
$sql = 'SELECT CategoryId
FROM '.$this->Application->getUnitOption('ci', 'TableName').'
WHERE ItemResourceId = '.$resource_id.' AND PrimaryCat = 1';
return $this->Conn->GetOne($sql);
}
/**
* Returns no permission template to redirect to
*
* @param Array $params
* @return Array
*/
function getPermissionTemplate($params)
{
$t = $this->Application->GetVar('t');
$next_t = getArrayValue($params, 'next_template');
if ( $next_t ) {
$t = $next_t;
}
$redirect_params = $this->Application->HttpQuery->getRedirectParams(true);
if (array_key_exists('pass_category', $params)) {
$redirect_params['pass_category'] = $params['pass_cateogry'];
}
if (MOD_REWRITE) {
// TODO: $next_t variable is ignored !!! (is anyone using m_RequireLogin tag with "next_template" parameter?)
$redirect_params = Array (
'm_cat_id' => 0, // category means nothing on admin login screen
'next_template' => urlencode('external:' . $_SERVER['REQUEST_URI']),
);
}
else {
$redirect_params['next_template'] = $t;
}
if ($this->Application->isAdmin) {
$redirect_params['m_wid'] = ''; // remove wid, otherwise parent window may add wid to its name breaking all the frameset (for <a> targets)
$redirect_params['pass'] = 'm'; // don't pass any other (except "m") prefixes to admin login template
}
if (!$this->Application->LoggedIn()) {
$redirect_template = array_key_exists('login_template', $params) ? $params['login_template'] : '';
if (!$redirect_template && $this->Application->isAdmin) {
$redirect_template = 'login';
}
}
else {
if (array_key_exists('no_permissions_template', $params)) {
$redirect_template = $params['no_permissions_template'];
}
else {
$redirect_template = $this->Application->isAdmin ? 'no_permission' : $this->Application->ConfigValue('NoPermissionTemplate');
}
if ($this->Application->isDebugMode()) {
$redirect_params['from_template'] = 1;
$redirect_params['perms'] = $params[ isset($params['permissions']) ? 'permissions' : 'perm_event' ];
}
}
if (isset($params['index_file']) && $params['index_file']) {
$redirect_params['index_file'] = $params['index_file'];
}
return Array ($redirect_template, $redirect_params);
}
/**
* Check current user permissions based on it's group permissions in specified category (for non-system permissions) or just checks if system permission is set
*
* @param string $name permission name
* @param int $cat_id category id, current used if not specified
* @param int $type permission type {1 - system, 0 - per category}
* @return int
*/
function CheckPermission($name, $type = 1, $cat_id = null)
{
$user_id = $this->Application->RecallVar('user_id');
return $this->CheckUserPermission($user_id, $name, $type, $cat_id);
}
/**
* Check current admin permissions (when called from Front-End) based on it's group permissions in specified category (for non-system permissions) or just checks if system permission is set
*
* @param string $name permission name
* @param int $cat_id category id, current used if not specified
* @param int $type permission type {1 - system, 0 - per category}
* @return int
*/
function CheckAdminPermission($name, $type = 1, $cat_id = null)
{
if ( $this->Application->isAdmin ) {
return $this->CheckPermission($name, $type, $cat_id);
}
$user_id = $this->Application->RecallVar('admin_user_id');
return $this->CheckUserPermission($user_id, $name, $type, $cat_id);
}
function CheckUserPermission($user_id, $name, $type = 1, $cat_id = null)
{
$user_id = (int)$user_id;
if ( $user_id == USER_ROOT ) {
// "root" is allowed anywhere
return substr($name, -5) == '.deny' || $name == 'SYSTEM_ACCESS.READONLY' ? 0 : 1;
}
if ( !isset($cat_id) ) {
$cat_id = $this->Application->GetVar('m_cat_id');
}
if ( $type == 1 ) {
// "system" permission are always checked per "Home" category (ID = 0)
$cat_id = 0;
}
elseif ( "$cat_id" === "0" ) {
$cat_id = $this->Application->getBaseCategory();
}
// perm cache is build only based on records in db, that's why if permission is not explicitly denied, then
// that (perm cache creator) code thinks that it is allowed & adds corresponding record and code below will
// return incorrect results
if ( $user_id == $this->Application->RecallVar('user_id') ) {
$groups = $this->Application->RecallVar('UserGroups');
}
else {
// checking not current user
$groups = $this->Application->RecallVar('UserGroups:' . $user_id);
if ( $groups === false ) {
// die('me');
$sql = 'SELECT GroupId
FROM '.TABLE_PREFIX.'UserGroupRelations
WHERE (PortalUserId = '.$user_id.') AND ( (MembershipExpires IS NULL) OR ( MembershipExpires >= UNIX_TIMESTAMP() ) )';
$groups = $this->Conn->GetCol($sql);
array_push($groups, $this->Application->ConfigValue('User_LoggedInGroup') );
$groups = implode(',', $groups);
$this->Application->StoreVar('UserGroups:' . $user_id, $groups);
}
}
$groups = explode(',', $groups);
$cache_key = $name . '|' . $type . '|' . $cat_id . '|' . implode(',', $groups);
$perm_value = $this->Application->getCache('permissions[%' . ($type == 1 ? 'G' : 'C') . 'PermSerial%]:' . $cache_key);
if ( $perm_value !== false ) {
return $perm_value;
}
if ( preg_match('/(.*)\.VIEW$/', $name) && ($type == 0) ) {
// cached view permission of category: begin
if ( strpos($cat_id, '|') !== false ) {
$category_path = explode('|', substr($cat_id, 1, -1));
$cat_id = end($category_path);
}
$sql = 'SELECT PermissionConfigId
FROM ' . TABLE_PREFIX . 'CategoryPermissionsConfig
WHERE PermissionName = ' . $this->Conn->qstr($name);
$perm_id = $this->Conn->GetOne($sql);
$sql = 'SELECT PermId
FROM ' . TABLE_PREFIX . 'CategoryPermissionsCache
WHERE (PermId = ' . $perm_id . ') AND (CategoryId = ' . (int)$cat_id . ')';
$view_filters = Array ();
foreach ($groups as $group) {
$view_filters[] = 'FIND_IN_SET(' . $group . ', ACL)';
}
$sql .= ' AND (' . implode(' OR ', $view_filters) . ')';
$perm_value = $this->Conn->GetOne($sql) ? 1 : 0;
$this->Application->setCache('permissions[%CPermSerial%]:' . $cache_key, $perm_value);
return $perm_value;
// cached view permission of category: end
}
if ( is_numeric($cat_id) && $cat_id == 0 ) {
$cat_hierarchy = Array (0);
}
else {
if ( strpos($cat_id, '|') !== false ) {
$cat_hierarchy = $cat_id;
}
else {
$sql = 'SELECT ParentPath
FROM ' . $this->Application->getUnitOption('c', 'TableName') . '
WHERE CategoryId = ' . $cat_id;
$cat_hierarchy = $this->Conn->GetOne($sql);
if ( $cat_hierarchy === false ) {
// category was deleted, but reference to it stays in other tables -> data integrity is broken
$cat_hierarchy = '|' . $this->Application->getBaseCategory() . '|';
}
}
$cat_hierarchy = explode('|', substr($cat_hierarchy, 1, -1));
$cat_hierarchy = array_reverse($cat_hierarchy);
array_push($cat_hierarchy, 0);
}
$perm_value = 0;
$groups = implode(',', $groups);
foreach ($cat_hierarchy as $category_id) {
$sql = 'SELECT SUM(PermissionValue)
FROM ' . TABLE_PREFIX . 'Permissions
WHERE Permission = "' . $name . '" AND CatId = ' . $category_id . ' AND GroupId IN (' . $groups . ') AND Type = ' . $type;
$res = $this->Conn->GetOne($sql);
if ( $res !== false && !is_null($res) ) {
$perm_value = $res ? 1 : 0;
break;
}
}
$this->Application->setCache('permissions[%' . ($type == 1 ? 'G' : 'C') . 'PermSerial%]:' . $cache_key, $perm_value);
return $perm_value;
}
/**
* Returns categories, where given permission is set to "1"
*
* @param string $permission_name
* @return Array
*/
function getPermissionCategories($permission_name)
{
$groups = $this->Application->RecallVar('UserGroups');
// get categories, where given permission is explicitely defined
$sql = 'SELECT SUM(PermissionValue), CatId
FROM ' . TABLE_PREFIX . 'Permissions
WHERE Permission = "' . $permission_name . '" AND GroupId IN (' . $groups . ') AND Type = 0
GROUP BY CatId';
$permissions = $this->Conn->GetCol($sql, 'CatId');
// get all categories along with their parent path
$sql = 'SELECT ParentPath, CategoryId
FROM ' . TABLE_PREFIX . 'Categories';
$parent_paths = $this->Conn->GetCol($sql, 'CategoryId');
foreach ($parent_paths as $category_id => $parent_path) {
if (array_key_exists($category_id, $permissions)) {
// permission for given category is set explicitly
continue;
}
$perm_value = 0;
$parent_path = explode('|', substr($parent_path, 1, -1));
$parent_path = array_reverse($parent_path);
array_push($parent_path, 0);
foreach ($parent_path as $parent_category_id) {
if (array_key_exists($parent_category_id, $permissions)) {
$perm_value = $permissions[$parent_category_id] ? 1 : 0;
break;
}
}
$permissions[$category_id] = $perm_value;
}
// remove categories, where given permissions is denied
foreach ($permissions as $category_id => $perm_value) {
if (!$perm_value) {
unset($permissions[$category_id]);
}
}
return array_keys($permissions);
}
/**
* Allows to check MODIFY & OWNER.MODFY +/- PENDING permission combinations on item
*
* @param int $owner_id user_id, that is owner of the item
* @param int $category_id primary category of item
* @param string $prefix prefix of item
* @return int {0 - no MODIFY permission, 1 - has MODIFY permission, 2 - has MODIFY.PENDING permission}
*/
function ModifyCheckPermission($owner_id, $category_id, $prefix)
{
$perm_prefix = $this->Application->getUnitOption($prefix, 'PermItemPrefix');
$live_modify = $this->CheckPermission($perm_prefix.'.MODIFY', ptCATEGORY, $category_id);
if ($live_modify) {
return 1;
}
else if ($this->CheckPermission($perm_prefix.'.MODIFY.PENDING', ptCATEGORY, $category_id)) {
return 2;
}
if ($owner_id == $this->Application->RecallVar('user_id')) {
// user is item's OWNER -> check this permissions first
$live_modify = $this->CheckPermission($perm_prefix.'.OWNER.MODIFY', ptCATEGORY, $category_id);
if ($live_modify) {
return 1;
}
else if ($this->CheckPermission($perm_prefix.'.OWNER.MODIFY.PENDING', ptCATEGORY, $category_id)) {
return 2;
}
}
return 0;
}
/**
* Allows to check DELETE & OWNER.DELETE permission combinations on item
*
* @param int $owner_id user_id, that is owner of the item
* @param int $category_id primary category of item
* @param string $prefix prefix of item
* @return int {0 - no DELETE permission, 1 - has DELETE/OWNER.DELETE permission}
*/
function DeleteCheckPermission($owner_id, $category_id, $prefix)
{
$perm_prefix = $this->Application->getUnitOption($prefix, 'PermItemPrefix');
$live_delete = $this->CheckPermission($perm_prefix.'.DELETE', ptCATEGORY, $category_id);
if ($live_delete) {
return 1;
}
if ($owner_id == $this->Application->RecallVar('user_id')) {
// user is item's OWNER -> check this permissions first
$live_delete = $this->CheckPermission($perm_prefix.'.OWNER.DELETE', ptCATEGORY, $category_id);
if ($live_delete) {
return 1;
}
}
return 0;
}
/**
* Allows to check ADD +/- PENDING permission combinations on item
*
* @param int $category_id primary category of item
* @param string $prefix prefix of item
* @return int {0 - no ADD permission, 1 - has ADD permission, 2 - has ADD.PENDING permission}
*/
function AddCheckPermission($category_id, $prefix)
{
$perm_prefix = $this->Application->getUnitOption($prefix, 'PermItemPrefix');
$live_add = $this->CheckPermission($perm_prefix.'.ADD', ptCATEGORY, $category_id);
if ($live_add) {
return 1;
}
else if ($this->CheckPermission($perm_prefix.'.ADD.PENDING', ptCATEGORY, $category_id)) {
return 2;
}
return 0;
}
}
\ No newline at end of file
Index: branches/5.2.x/core/units/helpers/helpers_config.php
===================================================================
--- branches/5.2.x/core/units/helpers/helpers_config.php (revision 15129)
+++ branches/5.2.x/core/units/helpers/helpers_config.php (revision 15130)
@@ -1,75 +1,75 @@
<?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!');
$config = Array (
'Prefix' => 'helpers',
'EventHandlerClass' => Array ('class' => 'kEventHandler', 'file' => '', 'build_event' => 'OnBuild'),
'RegisterClasses' => Array (
- Array ('pseudo' => 'kMultiLanguageHelper', 'class' => 'kMultiLanguageHelper', 'file' => 'multilanguage_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'),
- Array ('pseudo' => 'SearchHelper', 'class' => 'kSearchHelper', 'file' => 'search_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'),
- Array ('pseudo' => 'SectionsHelper', 'class' => 'kSectionsHelper', 'file' => 'sections_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'),
- Array ('pseudo' => 'PermissionsHelper', 'class' => 'kPermissionsHelper', 'file' => 'permissions_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'),
- Array ('pseudo' => 'ModulesHelper', 'class' => 'kModulesHelper', 'file' => 'modules_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'),
- Array ('pseudo' => 'CategoryItemRewrite', 'class' => 'CategoryItemRewrite', 'file' => 'mod_rewrite_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'),
- Array ('pseudo' => 'RecursiveHelper', 'class' => 'kRecursiveHelper', 'file' => 'recursive_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'),
- Array ('pseudo' => 'FilenamesHelper', 'class' => 'kFilenamesHelper', 'file' => 'filenames_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'),
- Array ('pseudo' => 'ClipboardHelper', 'class' => 'kClipboardHelper', 'file' => 'clipboard_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'),
- Array ('pseudo' => 'ColumnPickerHelper', 'class' => 'kColumnPickerHelper', 'file' => 'col_picker_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'),
- Array ('pseudo' => 'ThemesHelper', 'class' => 'kThemesHelper', 'file' => 'themes_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'),
- Array ('pseudo' => 'CaptchaHelper', 'class' => 'kCaptchaHelper', 'file' => 'captcha_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'),
- Array ('pseudo' => 'PriorityHelper', 'class' => 'kPriorityHelper', 'file' => 'priority_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'),
- Array ('pseudo' => 'CurlHelper', 'class' => 'kCurlHelper', 'file' => 'curl_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'),
- Array ('pseudo' => 'CountHelper', 'class' => 'kCountHelper', 'file' => 'count_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'),
-
- Array ('pseudo' => 'ImageHelper', 'class' => 'ImageHelper', 'file' => 'image_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'),
- Array ('pseudo' => 'FileHelper', 'class' => 'FileHelper', 'file' => 'file_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'),
- Array ('pseudo' => 'CategoryHelper', 'class' => 'CategoryHelper', 'file' => 'category_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'),
- Array ('pseudo' => 'CSVHelper', 'class' => 'kCSVHelper', 'file' => 'csv_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'),
- Array ('pseudo' => 'ChartHelper', 'class' => 'kChartHelper', 'file' => 'chart_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'),
- Array ('pseudo' => 'RatingHelper', 'class' => 'RatingHelper', 'file' => 'rating_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'),
- Array ('pseudo' => 'FCKHelper', 'class' => 'fckFCKHelper', 'file' => 'fck_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'),
- Array ('pseudo' => 'SpamHelper', 'class' => 'SpamHelper', 'file' => 'spam_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'),
- Array ('pseudo' => 'TemplateHelper', 'class' => 'TemplateHelper', 'file' => 'template_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'),
- Array ('pseudo' => 'MailingListHelper', 'class' => 'MailingListHelper', 'file' => 'mailing_list_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'),
- Array ('pseudo' => 'JSONHelper', 'class' => 'JSONHelper', 'file' => 'json_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'),
- Array ('pseudo' => 'LanguageImportHelper', 'class' => 'LanguageImportHelper', 'file' => 'language_import_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'),
- Array ('pseudo' => 'SkinHelper', 'class' => 'SkinHelper', 'file' => 'skin_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'),
- Array ('pseudo' => 'SiteConfigHelper', 'class' => 'SiteConfigHelper', 'file' => 'site_config_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'),
- Array ('pseudo' => 'MenuHelper', 'class' => 'MenuHelper', 'file' => 'menu_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'),
-
- Array ('pseudo' => 'InpCustomFieldsHelper', 'class' => 'InpCustomFieldsHelper', 'file' => 'custom_fields_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'),
- Array ('pseudo' => 'CountryStatesHelper', 'class' => 'kCountryStatesHelper', 'file' => 'country_states_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'),
- Array ('pseudo' => 'BracketsHelper', 'class' => 'kBracketsHelper', 'file' => 'brackets_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'),
- Array ('pseudo' => 'kXMLHelper', 'class' => 'kXMLHelper', 'file' => 'xml_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'),
- Array ('pseudo' => 'CatItemExportHelper', 'class' => 'kCatDBItemExportHelper', 'file' => 'cat_dbitem_export_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'),
- Array ('pseudo' => 'EmailMessageHelper', 'class' => 'EmailMessageHelper', 'file' => 'email_message_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'),
- Array ('pseudo' => 'ListHelper', 'class' => 'ListHelper', 'file' => 'list_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'),
-
- Array ('pseudo' => 'FormSubmissionHelper', 'class' => 'FormSubmissionHelper', 'file' => 'form_submission_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'),
- Array ('pseudo' => 'MailboxHelper', 'class' => 'MailboxHelper', 'file' => 'mailbox_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'),
- Array ('pseudo' => 'POP3Helper', 'class' => 'POP3Helper', 'file' => 'pop3_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'),
- Array ('pseudo' => 'MimeDecodeHelper', 'class' => 'MimeDecodeHelper', 'file' => 'mime_decode_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'),
- Array ('pseudo' => 'UserHelper', 'class' => 'UserHelper', 'file' => 'user_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'),
- Array ('pseudo' => 'SiteHelper', 'class' => 'SiteHelper', 'file' => 'site_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'),
+ Array ('pseudo' => 'kMultiLanguageHelper', 'class' => 'kMultiLanguageHelper', 'file' => 'multilanguage_helper.php', 'build_event' => ''),
+ Array ('pseudo' => 'SearchHelper', 'class' => 'kSearchHelper', 'file' => 'search_helper.php', 'build_event' => ''),
+ Array ('pseudo' => 'SectionsHelper', 'class' => 'kSectionsHelper', 'file' => 'sections_helper.php', 'build_event' => ''),
+ Array ('pseudo' => 'PermissionsHelper', 'class' => 'kPermissionsHelper', 'file' => 'permissions_helper.php', 'build_event' => ''),
+ Array ('pseudo' => 'ModulesHelper', 'class' => 'kModulesHelper', 'file' => 'modules_helper.php', 'build_event' => ''),
+ Array ('pseudo' => 'CategoryItemRewrite', 'class' => 'CategoryItemRewrite', 'file' => 'mod_rewrite_helper.php', 'build_event' => ''),
+ Array ('pseudo' => 'RecursiveHelper', 'class' => 'kRecursiveHelper', 'file' => 'recursive_helper.php', 'build_event' => ''),
+ Array ('pseudo' => 'FilenamesHelper', 'class' => 'kFilenamesHelper', 'file' => 'filenames_helper.php', 'build_event' => ''),
+ Array ('pseudo' => 'ClipboardHelper', 'class' => 'kClipboardHelper', 'file' => 'clipboard_helper.php', 'build_event' => ''),
+ Array ('pseudo' => 'ColumnPickerHelper', 'class' => 'kColumnPickerHelper', 'file' => 'col_picker_helper.php', 'build_event' => ''),
+ Array ('pseudo' => 'ThemesHelper', 'class' => 'kThemesHelper', 'file' => 'themes_helper.php', 'build_event' => ''),
+ Array ('pseudo' => 'CaptchaHelper', 'class' => 'kCaptchaHelper', 'file' => 'captcha_helper.php', 'build_event' => ''),
+ Array ('pseudo' => 'PriorityHelper', 'class' => 'kPriorityHelper', 'file' => 'priority_helper.php', 'build_event' => ''),
+ Array ('pseudo' => 'CurlHelper', 'class' => 'kCurlHelper', 'file' => 'curl_helper.php', 'build_event' => ''),
+ Array ('pseudo' => 'CountHelper', 'class' => 'kCountHelper', 'file' => 'count_helper.php', 'build_event' => ''),
+
+ Array ('pseudo' => 'ImageHelper', 'class' => 'ImageHelper', 'file' => 'image_helper.php', 'build_event' => ''),
+ Array ('pseudo' => 'FileHelper', 'class' => 'FileHelper', 'file' => 'file_helper.php', 'build_event' => ''),
+ Array ('pseudo' => 'CategoryHelper', 'class' => 'CategoryHelper', 'file' => 'category_helper.php', 'build_event' => ''),
+ Array ('pseudo' => 'CSVHelper', 'class' => 'kCSVHelper', 'file' => 'csv_helper.php', 'build_event' => ''),
+ Array ('pseudo' => 'ChartHelper', 'class' => 'kChartHelper', 'file' => 'chart_helper.php', 'build_event' => ''),
+ Array ('pseudo' => 'RatingHelper', 'class' => 'RatingHelper', 'file' => 'rating_helper.php', 'build_event' => ''),
+ Array ('pseudo' => 'FCKHelper', 'class' => 'fckFCKHelper', 'file' => 'fck_helper.php', 'build_event' => ''),
+ Array ('pseudo' => 'SpamHelper', 'class' => 'SpamHelper', 'file' => 'spam_helper.php', 'build_event' => ''),
+ Array ('pseudo' => 'TemplateHelper', 'class' => 'TemplateHelper', 'file' => 'template_helper.php', 'build_event' => ''),
+ Array ('pseudo' => 'MailingListHelper', 'class' => 'MailingListHelper', 'file' => 'mailing_list_helper.php', 'build_event' => ''),
+ Array ('pseudo' => 'JSONHelper', 'class' => 'JSONHelper', 'file' => 'json_helper.php', 'build_event' => ''),
+ Array ('pseudo' => 'LanguageImportHelper', 'class' => 'LanguageImportHelper', 'file' => 'language_import_helper.php', 'build_event' => ''),
+ Array ('pseudo' => 'SkinHelper', 'class' => 'SkinHelper', 'file' => 'skin_helper.php', 'build_event' => ''),
+ Array ('pseudo' => 'SiteConfigHelper', 'class' => 'SiteConfigHelper', 'file' => 'site_config_helper.php', 'build_event' => ''),
+ Array ('pseudo' => 'MenuHelper', 'class' => 'MenuHelper', 'file' => 'menu_helper.php', 'build_event' => ''),
+
+ Array ('pseudo' => 'InpCustomFieldsHelper', 'class' => 'InpCustomFieldsHelper', 'file' => 'custom_fields_helper.php', 'build_event' => ''),
+ Array ('pseudo' => 'CountryStatesHelper', 'class' => 'kCountryStatesHelper', 'file' => 'country_states_helper.php', 'build_event' => ''),
+ Array ('pseudo' => 'BracketsHelper', 'class' => 'kBracketsHelper', 'file' => 'brackets_helper.php', 'build_event' => ''),
+ Array ('pseudo' => 'kXMLHelper', 'class' => 'kXMLHelper', 'file' => 'xml_helper.php', 'build_event' => ''),
+ Array ('pseudo' => 'CatItemExportHelper', 'class' => 'kCatDBItemExportHelper', 'file' => 'cat_dbitem_export_helper.php', 'build_event' => ''),
+ Array ('pseudo' => 'EmailMessageHelper', 'class' => 'EmailMessageHelper', 'file' => 'email_message_helper.php', 'build_event' => ''),
+ Array ('pseudo' => 'ListHelper', 'class' => 'ListHelper', 'file' => 'list_helper.php', 'build_event' => ''),
+
+ Array ('pseudo' => 'FormSubmissionHelper', 'class' => 'FormSubmissionHelper', 'file' => 'form_submission_helper.php', 'build_event' => ''),
+ Array ('pseudo' => 'MailboxHelper', 'class' => 'MailboxHelper', 'file' => 'mailbox_helper.php', 'build_event' => ''),
+ Array ('pseudo' => 'POP3Helper', 'class' => 'POP3Helper', 'file' => 'pop3_helper.php', 'build_event' => ''),
+ Array ('pseudo' => 'MimeDecodeHelper', 'class' => 'MimeDecodeHelper', 'file' => 'mime_decode_helper.php', 'build_event' => ''),
+ Array ('pseudo' => 'UserHelper', 'class' => 'UserHelper', 'file' => 'user_helper.php', 'build_event' => ''),
+ Array ('pseudo' => 'SiteHelper', 'class' => 'SiteHelper', 'file' => 'site_helper.php', 'build_event' => ''),
- Array ('pseudo' => 'DeploymentHelper', 'class' => 'DeploymentHelper', 'file' => 'deployment_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'),
- Array ('pseudo' => 'PageHelper', 'class' => 'PageHelper', 'file' => 'page_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'),
+ Array ('pseudo' => 'DeploymentHelper', 'class' => 'DeploymentHelper', 'file' => 'deployment_helper.php', 'build_event' => ''),
+ Array ('pseudo' => 'PageHelper', 'class' => 'PageHelper', 'file' => 'page_helper.php', 'build_event' => ''),
Array ('pseudo' => 'BackupHelper', 'class' => 'BackupHelper', 'file' => 'backup_helper.php', 'build_event' => ''),
- Array ('pseudo' => 'AjaxFormHelper', 'class' => 'AjaxFormHelper', 'file' => 'ajax_form_helper.php', 'build_event' => '', 'require_classes' => 'kHelper'),
+ Array ('pseudo' => 'AjaxFormHelper', 'class' => 'AjaxFormHelper', 'file' => 'ajax_form_helper.php', 'build_event' => ''),
),
);
\ 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 15129)
+++ branches/5.2.x/core/units/selectors/selectors_event_handler.php (revision 15130)
@@ -1,453 +1,453 @@
<?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 standard permission mapping
*
* @return void
* @access protected
* @see kEventHandler::$permMapping
*/
protected 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(kEvent &$event)
+ protected function OnBeforeClone(kEvent $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(kEvent &$event)
+ protected function SetCustomQuery(kEvent $event)
{
parent::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(kEvent &$event)
+ protected function OnBeforeItemUpdate(kEvent $event)
{
parent::OnBeforeItemUpdate($event);
$this->SerializeSelectorData($event);
}
/**
* Occurs before creating item
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnBeforeItemCreate(kEvent &$event)
+ protected function OnBeforeItemCreate(kEvent $event)
{
parent::OnBeforeItemCreate($event);
$this->SerializeSelectorData($event);
}
/**
* Occurs after updating item
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnAfterItemUpdate(kEvent &$event)
+ protected function OnAfterItemUpdate(kEvent $event)
{
parent::OnAfterItemUpdate($event);
$this->UnserializeSelectorData($event);
}
/**
* Occurs after creating item
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnAfterItemCreate(kEvent &$event)
+ protected function OnAfterItemCreate(kEvent $event)
{
parent::OnAfterItemCreate($event);
$this->UnserializeSelectorData($event);
}
/**
* Returns special of main item for linking with sub-item
*
* @param kEvent $event
* @return string
* @access protected
*/
- protected function getMainSpecial(kEvent &$event)
+ protected function getMainSpecial(kEvent $event)
{
return '';
}
/**
* Save css-style name & description before opening css editor
*
* @param kEvent $event
*/
- function OnOpenStyleEditor(&$event)
+ function OnOpenStyleEditor($event)
{
$this->SaveChanges($event);
$event->redirect = false;
}
/**
* Saves Changes to Item
*
* @param kEvent $event
*/
- function SaveChanges(&$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, $this->getRequestProtectedFields($field_values));
$object->Create();
$this->Application->SetVar($event->getPrefixSpecial() . '_id', $object->GetID());
}
else {
$object->Load($id);
$object->SetFieldsFromHash($field_values, $this->getRequestProtectedFields($field_values));
$object->Update();
}
}
}
/**
* Save style changes from style editor
*
* @param kEvent $event
*/
- function OnSaveStyle(&$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(kEvent &$event)
+ protected function OnAfterItemLoad(kEvent $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)
+ 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)
+ 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)
+ 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
* @param Array $selector_data
* @return Array
*/
- function RemoveParentProperties(&$event, $selector_data)
+ 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
* @param Array $selector_data
* @return Array
*/
- function AddParentProperties(&$event, $selector_data)
+ 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)
+ function OnResetToBase($event)
{
$object =& $event->getObject();
/* @var $object SelectorsItem */
$field_values = $this->getSubmittedFields($event);
$object->SetFieldsFromHash($field_values, $this->getRequestProtectedFields($field_values));
$object->ResetStyle();
$event->SetRedirectParam('pass', 'all,' . $event->getPrefixSpecial());
}
/**
* Resets selected styles properties to values of their base classes
*
* @param kEvent $event
*/
- function OnMassResetToBase(&$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/fck/fck_eh.php
===================================================================
--- branches/5.2.x/core/units/fck/fck_eh.php (revision 15129)
+++ branches/5.2.x/core/units/fck/fck_eh.php (revision 15130)
@@ -1,253 +1,253 @@
<?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 FckEventHandler extends kDBEventHandler {
/**
* Allows to override standard permission mapping
*
* @return void
* @access protected
* @see kEventHandler::$permMapping
*/
protected function mapPermissions()
{
parent::mapPermissions();
$permissions = Array (
'OnGetsEditorStyles' => 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(kEvent &$event)
+ public function CheckPermission(kEvent $event)
{
if ( $this->Application->isAdminUser || $event->Name == 'OnGetsEditorStyles' ) {
// this limits all event execution only to logged-in users in admin
return true;
}
return parent::CheckPermission($event);
}
function CreateXmlHeader()
{
ob_end_clean() ;
// Prevent the browser from caching the result.
// Date in the past
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT') ;
// always modified
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT') ;
// HTTP/1.1
header('Cache-Control: no-store, no-cache, must-revalidate') ;
header('Cache-Control: post-check=0, pre-check=0', false) ;
// HTTP/1.0
header('Pragma: no-cache') ;
// Set the response format.
header( 'Content-Type: text/xml; charset=utf-8' ) ;
// Create the XML document header.
}
- function OnLoadCmsTree(&$event)
+ function OnLoadCmsTree($event)
{
$event->status = kEvent::erSTOP;
$category_helper =& $this->Application->recallObject('CategoryHelper');
/* @var $category_helper CategoryHelper */
$pages = $category_helper->getStructureTreeAsOptions();
$sql = 'SELECT NamedParentPath, CategoryId
FROM ' . TABLE_PREFIX . 'Categories
WHERE CategoryId IN (' . implode(',', array_keys($pages)) . ')';
$templates = $this->Conn->GetCol($sql, 'CategoryId');
$templates[$this->Application->getBaseCategory()] .= '/Index'; // "Content" category will act as "Home Page"
$res = '<?xml version="1.0" encoding="utf-8" ?>' . "\n";
$res .= '<CmsPages>' . "\n";
foreach ($pages as $id => $title) {
$template = $templates[$id];
$page_path = preg_replace('/^Content\//i', '', strtolower($template).'.html');
$title = $title . ' (' . $page_path . ')';
$real_url = $this->Application->HREF($template, '_FRONT_END_', array('pass' => 'm'), 'index.php');
$res .= '<CmsPage real_url="' . $real_url . '" path="@@' . $id . '@@" title="' . htmlspecialchars($title, ENT_QUOTES) . '" st_id="' . $id . '" serverpath="" />' . "\n";
}
$res.= "</CmsPages>";
$this->CreateXmlHeader();
echo $res;
}
- function OnRenameFile(&$event)
+ function OnRenameFile($event)
{
$event->status = kEvent::erSTOP;
if ($this->Application->CheckPermission('SYSTEM_ACCESS.READONLY', 1)) {
return;
}
$old_name = $this->Application->GetVar('old_name');
$new_name = $this->Application->GetVar('new_name');
$folder = $this->Application->GetVar('folder');
$sServerDir = WRITEABLE . '/user_files/' . $folder . '/';
if (!file_exists($sServerDir.$old_name) || !is_file($sServerDir.$old_name)) {
echo 204;
return;
}
$fck_helper =& $this->Application->recallObject('FCKHelper');
/* @var $fck_helper fckFCKHelper*/
if ( !$fck_helper->IsAllowedExtension($folder, $new_name) ) {
echo 203;
return;
}
if ( !rename($sServerDir . $old_name, $sServerDir . $new_name) ) {
// echo $sServerDir.$old_name.' -> '.$sServerDir.$new_name;
echo 205;
return;
}
echo '0';
}
- function OnDeleteFiles(&$event)
+ function OnDeleteFiles($event)
{
$event->status = kEvent::erSTOP;
if ($this->Application->CheckPermission('SYSTEM_ACCESS.READONLY', 1)) {
return;
}
$files = trim($this->Application->GetVar('files'),'|');
// echo $files;
$a_files = explode('|', $files);
$folder = $this->Application->GetVar('folder');
$sServerDir = WRITEABLE . '/user_files/' . $folder . '/';
foreach ($a_files AS $file) {
@unlink($sServerDir.$file);
}
// print_r($a_files);
}
- function OnGetFoldersFilesList(&$event)
+ function OnGetFoldersFilesList($event)
{
$this->CreateXmlHeader();
$fck_helper =& $this->Application->recallObject('FCKHelper');
/* @var $fck_helper fckFCKHelper */
$ret = '<?xml version="1.0" encoding="utf-8" ?>'."\n" ;
$ret .= "<content>"."\n";
$ret .= $fck_helper->PrintFolders();
$ret .= $fck_helper->PrintFiles();
$ret .= "</content>"."\n";
echo $ret;
exit;
}
- function OnCreateFolder(&$event)
+ function OnCreateFolder($event)
{
$event->status = kEvent::erSTOP;
if ($this->Application->CheckPermission('SYSTEM_ACCESS.READONLY', 1)) {
return;
}
$new_folder = $this->Application->GetVar('new_folder');
$current_folder = $this->Application->GetVar('current_folder');
$folderPath = WRITEABLE . '/user_files' . '/' . $current_folder . "/" . $new_folder;
if ( file_exists( $folderPath ) && is_dir($folderPath)) {
echo "101";
}
if ( !file_exists( $folderPath ) )
{
// Turn off all error reporting.
error_reporting( 0 ) ;
// Enable error tracking to catch the error.
ini_set( 'track_errors', '1' ) ;
// To create the folder with 0777 permissions, we need to set umask to zero.
$oldumask = umask(0) ;
mkdir( $folderPath, 0777 ) ;
umask( $oldumask ) ;
$sErrorMsg = $php_errormsg ;
// Restore the configurations.
ini_restore( 'track_errors' ) ;
ini_restore( 'error_reporting' ) ;
if ($sErrorMsg)
echo $sErrorMsg ;
else
echo '0';
}
}
/**
* Uploads a file from FCK file browser
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnUploadFile(kEvent &$event)
+ protected function OnUploadFile(kEvent $event)
{
$event->status = kEvent::erSTOP;
if ( $this->Application->CheckPermission('SYSTEM_ACCESS.READONLY', 1) ) {
return;
}
$fck_helper =& $this->Application->recallObject('FCKHelper');
/* @var $fck_helper fckFCKHelper*/
$fck_helper->UploadFile();
}
/**
* Returns compressed CSS file
*
* @param kEvent $event
*/
- function OnGetsEditorStyles(&$event)
+ function OnGetsEditorStyles($event)
{
$minify_helper =& $this->Application->recallObject('MinifyHelper');
/* @var $minify_helper MinifyHelper */
$this->Application->InitParser();
$styles_css = $minify_helper->CompressScriptTag( Array ('files' => 'inc/style.css') );
$event->redirect = 'external:' . $styles_css;
}
}
\ No newline at end of file
Index: branches/5.2.x/core/units/custom_data/custom_data_event_handler.php
===================================================================
--- branches/5.2.x/core/units/custom_data/custom_data_event_handler.php (revision 15129)
+++ branches/5.2.x/core/units/custom_data/custom_data_event_handler.php (revision 15130)
@@ -1,242 +1,242 @@
<?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 CustomDataEventHandler extends kDBEventHandler {
/**
* [HOOK] Allows to apply custom fields functionality to specific config
* When main item is created, then cdata config is cloned
*
* @param kEvent $event
*/
- function OnDefineCustomFields(&$event)
+ function OnDefineCustomFields($event)
{
// 1. clone customdata table
$clones = $this->Application->getUnitOption('cdata', 'Clones');
$data_table = $this->Application->getUnitOption($event->MasterEvent->Prefix, 'CustomDataTableName');
if ( !$data_table ) {
$data_table = $this->Application->getUnitOption($event->MasterEvent->Prefix, 'TableName') . 'CustomData';
}
$clones[$event->MasterEvent->Prefix.'-cdata'] = Array (
'ParentPrefix' => $event->MasterEvent->Prefix,
'TableName' => $data_table,
);
$this->Application->setUnitOption('cdata', 'Clones', $clones);
// 2. add custom field information to main item
$this->createCustomFields($event->MasterEvent->Prefix);
}
/**
* Returns list of custom fields for a given $prefix
*
* @param $prefix
*
* @return Array|bool
* @access protected
*/
protected function scanCustomFields($prefix)
{
static $custom_fields = Array ();
if (defined('IS_INSTALL') && IS_INSTALL && !$this->Application->TableFound('CustomFields', true)) {
return false;
}
if (!$prefix) {
// prefix not specified
return false;
}
$item_type = $this->Application->getUnitOption($prefix, 'ItemType');
if (!$item_type) {
// no main config of such type
return false;
}
$no_caching = (defined('IS_INSTALL') && IS_INSTALL) || (defined('CUSTOM_FIELD_ADDED') && CUSTOM_FIELD_ADDED);
if (!$custom_fields || $no_caching) {
// query all custom fields at once -> saves 4 sqls queries
if ($no_caching) {
$all_custom_fields = $this->getCustomFields();
}
else {
$cache_key = 'all_custom_fields[%CfSerial%][%ModSerial%]';
$all_custom_fields = $this->Application->getCache($cache_key, false);
if ($all_custom_fields === false) {
$this->Conn->nextQueryCachable = true;
$all_custom_fields = $this->getCustomFields();
$this->Application->setCache($cache_key, $all_custom_fields);
}
}
foreach ($all_custom_fields as $custom_field_id => $custom_field_data) {
$cf_type = $custom_field_data['Type'];
if (!array_key_exists($cf_type, $custom_fields)) {
$custom_fields[$cf_type] = Array ();
}
$custom_fields[$cf_type][$custom_field_id] = $custom_field_data;
}
}
return array_key_exists($item_type, $custom_fields) ? $custom_fields[$item_type] : false;
}
/**
* Returns sorted list of all custom fields
*
* @return Array
*/
function getCustomFields()
{
$sql = 'SELECT *
FROM '.TABLE_PREFIX.'CustomFields';
$ret = $this->Conn->Query($sql, 'CustomFieldId');
ksort($ret);
return $ret;
}
/**
* Fills cloned cdata config with data from it's parent
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnAfterConfigRead(kEvent &$event)
+ protected function OnAfterConfigRead(kEvent $event)
{
parent::OnAfterConfigRead($event);
$main_prefix = $this->Application->getUnitOption($event->Prefix, 'ParentPrefix');
if ( !$main_prefix ) {
return ;
}
$custom_fields = $this->scanCustomFields($main_prefix);
if ( !$custom_fields ) {
return ;
}
// 2. create fields (for customdata item)
$fields = $this->Application->getUnitOption($event->Prefix, 'Fields', Array ());
$field_options = Array ('type' => 'string', 'formatter' => 'kMultiLanguage', 'db_type' => 'text', 'default' => '');
foreach ($custom_fields as $custom_id => $custom_params) {
if ( isset($fields['cust_' . $custom_id]) ) {
continue;
}
$fields['cust_' . $custom_id] = $field_options;
$fields['cust_' . $custom_id]['force_primary'] = !$custom_params['MultiLingual'];
}
$this->Application->setUnitOption($event->Prefix, 'Fields', $fields);
}
/**
* Creates "cust_<custom_name>" virtual fields for main item
*
* @param string $prefix
* @return void
* @access protected
*/
protected function createCustomFields($prefix)
{
$custom_fields = $this->scanCustomFields($prefix);
if ( !$custom_fields ) {
return;
}
$calculated_fields = Array ();
$virtual_fields = $this->Application->getUnitOption($prefix, 'VirtualFields', Array ());
$cf_helper =& $this->Application->recallObject('InpCustomFieldsHelper');
/* @var $cf_helper InpCustomFieldsHelper */
$is_install = defined('IS_INSTALL') && IS_INSTALL;
foreach ($custom_fields as $custom_id => $custom_params) {
$custom_name = $custom_params['FieldName'];
$field_options = Array ('type' => 'string', 'default' => $custom_params['DefaultValue']);
// raises warnings during 4.3.9 -> 5.0.0 upgrade, no fatal sqls though
if ( $custom_params['IsRequired'] ) {
$field_options['required'] = 1;
}
$calculated_fields['cust_' . $custom_name] = 'cust.l' . $this->Application->GetDefaultLanguageId() . '_cust_' . $custom_id;
switch ( $custom_params['ElementType'] ) {
case 'date':
unset($field_options['options']);
$field_options['formatter'] = 'kDateFormatter';
$field_options['input_time_format'] = '';
$field_options['time_format'] = '';
break;
case 'datetime':
unset($field_options['options']);
$field_options['formatter'] = 'kDateFormatter';
break;
case 'select':
case 'multiselect':
case 'radio':
if ( $custom_params['ValueList'] ) {
// $is_install check prevents 335 bad phrase sql errors on upgrade to 5.1.0
$field_options['options'] = $is_install ? Array () : $cf_helper->GetValuesHash($custom_params['ValueList']);
$field_options['formatter'] = 'kOptionsFormatter';
$field_options['multiple'] = $custom_params['ElementType'] == 'multiselect';
}
break;
default:
if ( $custom_params['MultiLingual'] ) {
$field_options['formatter'] = 'kMultiLanguage';
$calculated_fields['cust_' . $custom_name] = 'cust.l%2$s_cust_' . $custom_id;
}
break;
}
if ( !isset($virtual_fields['cust_' . $custom_name]) ) {
$virtual_fields['cust_' . $custom_name] = Array ();
}
$virtual_fields['cust_' . $custom_name] = kUtil::array_merge_recursive($field_options, $virtual_fields['cust_' . $custom_name]);
$custom_fields[$custom_id] = $custom_name;
}
$config_calculated_fields = $this->Application->getUnitOption($prefix, 'CalculatedFields', Array ());
foreach ($config_calculated_fields as $special => $special_fields) {
if ( $special == '-virtual' ) {
continue;
}
$config_calculated_fields[$special] = array_merge($config_calculated_fields[$special], $calculated_fields);
}
$this->Application->setUnitOption($prefix, 'CalculatedFields', $config_calculated_fields);
$this->Application->setUnitOption($prefix, 'CustomFields', $custom_fields);
$this->Application->setUnitOption($prefix, 'VirtualFields', $virtual_fields);
}
}
\ No newline at end of file
Index: branches/5.2.x/core/units/logs/session_logs/session_log_eh.php
===================================================================
--- branches/5.2.x/core/units/logs/session_logs/session_log_eh.php (revision 15129)
+++ branches/5.2.x/core/units/logs/session_logs/session_log_eh.php (revision 15130)
@@ -1,130 +1,130 @@
<?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 SessionLogEventHandler extends kDBEventHandler {
/**
* Opens log for new session
*
* @param kEvent $event
*/
- function OnStartSession(&$event)
+ function OnStartSession($event)
{
if (!$this->Application->ConfigValue('UseChangeLog')) {
// don't use session log when change log is disabled
return ;
}
$object =& $this->Application->recallObject($event->Prefix, null, Array ('skip_autoload' => 1));
/* @var $object kDBItem */
$fields_hash = Array (
'SessionStart' => adodb_mktime(),
'IP' => $_SERVER['REMOTE_ADDR'],
'PortalUserId' => $this->Application->RecallVar('user_id'),
'SessionId' => $this->Application->GetSID(),
'Status' => SESSION_LOG_ACTIVE,
);
$object->SetDBFieldsFromHash($fields_hash);
$object->UpdateFormattersSubFields();
if ($object->Create()) {
$this->Application->StoreVar('_SessionLogId_', $object->GetID());
}
}
/**
* Closes log for current session
*
* @param kEvent $event
*/
- function OnEndSession(&$event)
+ function OnEndSession($event)
{
$object =& $this->Application->recallObject($event->Prefix, null, Array ('skip_autoload' => 1));
/* @var $object kDBItem */
$object->Load($this->Application->RecallVar('_SessionLogId_'));
if (!$object->isLoaded()) {
return ;
}
$fields_hash = Array (
'SessionEnd' => adodb_mktime(),
'Status' => SESSION_LOG_LOGGED_OUT,
);
$object->SetDBFieldsFromHash($fields_hash);
$object->UpdateFormattersSubFields();
$object->Update();
}
/**
* Apply custom processing to item
*
* @param kEvent $event
* @param string $type
* @return void
* @access protected
*/
- protected function customProcessing(kEvent &$event, $type)
+ protected function customProcessing(kEvent $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 <> ' . SESSION_LOG_ACTIVE;
$allowed_ids = $this->Conn->GetCol($sql);
$event->setEventParam('ids', $allowed_ids);
}
}
}
/**
* Delete changes, related to deleted session
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnAfterItemDelete(kEvent &$event)
+ protected function OnAfterItemDelete(kEvent $event)
{
parent::OnAfterItemDelete($event);
$object =& $event->getObject();
/* @var $object kDBItem */
$sql = 'SELECT ' . $this->Application->getUnitOption('change-log', 'IDField') . '
FROM ' . $this->Application->getUnitOption('change-log', 'TableName') . '
WHERE SessionLogId = ' . $object->GetID();
$related_ids = $this->Conn->GetCol($sql);
if ( $related_ids ) {
$temp_handler =& $this->Application->recallObject('change-log_TempHandler', 'kTempTablesHandler');
/* @var $temp_handler kTempTablesHandler */
$temp_handler->DeleteItems('change-log', '', $related_ids);
}
}
}
\ No newline at end of file
Index: branches/5.2.x/core/units/logs/change_logs/change_logs_config.php
===================================================================
--- branches/5.2.x/core/units/logs/change_logs/change_logs_config.php (revision 15129)
+++ branches/5.2.x/core/units/logs/change_logs/change_logs_config.php (revision 15130)
@@ -1,160 +1,160 @@
<?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!');
$config = Array (
'Prefix' => 'change-log',
'ItemClass' => Array('class' => 'kDBItem', 'file' => '', 'build_event' => 'OnItemBuild'),
'ListClass' => Array('class' => 'kDBList', 'file' => '', 'build_event' => 'OnListBuild'),
'EventHandlerClass' => Array ('class' => 'ChangeLogEventHandler', 'file' => 'change_log_eh.php', 'build_event' => 'OnBuild'),
'TagProcessorClass' => Array ('class' => 'ChangeLogTagProcessor', 'file' => 'change_log_tp.php', 'build_event' => 'OnBuild'),
'RegisterClasses' => Array (
- Array ('pseudo' => 'kChangesFormatter', 'class' => 'kChangesFormatter', 'file' => 'changes_formatter.php', 'build_event' => '', 'require_classes' => 'kFormatter'),
+ Array ('pseudo' => 'kChangesFormatter', 'class' => 'kChangesFormatter', 'file' => 'changes_formatter.php', 'build_event' => ''),
),
'AutoLoad' => true,
'QueryString' => Array (
1 => 'id',
2 => 'Page',
3 => 'PerPage',
4 => 'event',
5 => 'mode',
),
'IDField' => 'ChangeLogId',
//'StatusField' => Array ('Status'),
'TableName' => TABLE_PREFIX.'ChangeLogs',
'TitlePresets' => Array (
'default' => Array (
'edit_status_labels' => Array ('change-log' => '!la_title_EditingChangeLog!'),
),
'change_log_list' => Array (
'prefixes' => Array('change-log_List'), 'format' => '!la_tab_ChangeLog!',
'toolbar_buttons' => Array ('edit', 'delete', 'view'),
),
'change_log_edit' => Array (
'prefixes' => Array('change-log'), 'format' => '#change-log_status# #change-log_titlefield#',
'toolbar_buttons' => Array ('select', 'cancel', 'reset_edit', 'prev', 'next'),
),
),
'PermSection' => Array ('main' => 'in-portal:change_logs'),
// don't forget to add corresponding permissions to install script
// INSERT INTO Permissions VALUES (0, 'in-portal:change_logs.view', 11, 1, 1, 0), (0, 'in-portal:change_logs.add', 11, 1, 1, 0), (0, 'in-portal:change_logs.edit', 11, 1, 1, 0), (0, 'in-portal:change_logs.delete', 11, 1, 1, 0);
'Sections' => Array (
'in-portal:change_logs' => Array (
'parent' => 'in-portal:reports',
'icon' => 'changes_log', // 'change_logs',
'label' => 'la_tab_ChangeLog',
'url' => Array('t' => 'logs/change_logs/change_log_list', 'pass' => 'm'),
'permissions' => Array('view', 'edit', 'delete'),
'priority' => 3,
// 'show_mode' => smSUPER_ADMIN,
'type' => stTREE,
),
),
'TitleField' => 'ChangeLogId',
'ListSQLs' => Array (
'' => ' SELECT %1$s.* %2$s
FROM %1$s
LEFT JOIN '.TABLE_PREFIX.'Users AS u ON u.PortalUserId = %1$s.PortalUserId',
),
'ListSortings' => Array (
'' => Array (
'Sorting' => Array ('OccuredOn' => 'desc'),
)
),
'CalculatedFields' => Array (
'' => Array (
'UserLogin' => 'IF(%1$s.PortalUserId = ' . USER_ROOT . ', \'root\', u.Username)',
'UserFirstName' => 'u.FirstName',
'UserLastName' => 'u.LastName',
'UserEmail' => 'u.Email',
),
),
'ForceDontLogChanges' => true,
'Fields' => Array (
'ChangeLogId' => Array ('type' => 'int', 'not_null' => 1, 'default' => 0),
'PortalUserId' => Array ('type' => 'int', 'not_null' => 1, 'default' => 0),
'SessionLogId' => Array ('type' => 'int', 'not_null' => 1, 'default' => 0),
'Action' => Array (
'type' => 'int', 'formatter' => 'kOptionsFormatter',
'options' => array (ChangeLog::CREATE => 'la_opt_ActionCreate', ChangeLog::UPDATE => 'la_opt_ActionUpdate', ChangeLog::DELETE => 'la_opt_ActionDelete'),
'use_phrases' => 1,
'not_null' => 1, 'default' => 0
),
'OccuredOn' => Array ('type' => 'int', 'formatter' => 'kDateFormatter', 'time_format' => 'H:i:s', 'default' => NULL),
'Prefix' => Array (
'type' => 'string', 'formatter' => 'kOptionsFormatter',
'options_sql' => 'SELECT DISTINCT %s FROM '.TABLE_PREFIX.'ChangeLogs ORDER BY Phrase',
'option_key_field' => 'Prefix',
'option_title_field' => 'CONCAT(\'la_prefix_\', Prefix) AS Phrase',
'use_phrases' => 1,
'max_len' => 255, 'not_null' => 1, 'default' => ''
),
'ItemId' => Array ('type' => 'int', 'not_null' => 1, 'default' => 0),
'Changes' => Array ('type' => 'string', 'formatter' => 'kChangesFormatter', 'default' => NULL),
'MasterPrefix' => Array (
'type' => 'string', 'formatter' => 'kOptionsFormatter',
'options_sql' => 'SELECT DISTINCT %s FROM '.TABLE_PREFIX.'ChangeLogs ORDER BY Phrase',
'option_key_field' => 'MasterPrefix',
'option_title_field' => 'CONCAT(\'la_prefix_\',MasterPrefix) AS Phrase',
'use_phrases' => 1,
'max_len' => 255, 'not_null' => 1, 'default' => ''
),
'MasterId' => Array ('type' => 'int', 'not_null' => 1, 'default' => 0),
),
'VirtualFields' => Array (
'UserLogin' => Array ('type' => 'string', 'default' => ''),
'UserFirstName' => Array ('type' => 'string', 'default' => ''),
'UserLastName' => Array ('type' => 'string', 'default' => ''),
'UserEmail' => Array ('type' => 'string', 'default' => ''),
),
'Grids' => Array (
'Default' => Array (
'Icons' => Array ('default' => 'icon16_item.png'),
'Fields' => Array (
'ChangeLogId' => Array ('title' => 'column:la_fld_Id', 'data_block' => 'grid_checkbox_td', 'filter_block' => 'grid_range_filter', 'width' => 70, ),
'PortalUserId' => Array ('title' => 'la_col_PortalUserId', 'filter_block' => 'grid_like_filter', 'width' => 70, ),
'UserLogin' => Array ('title' => 'column:la_fld_Username', 'filter_block' => 'grid_like_filter', 'width' => 100, ),
'UserFirstName' => Array ('title' => 'column:la_fld_FirstName', 'filter_block' => 'grid_like_filter', 'width' => 120, ),
'UserLastName' => Array ('title' => 'column:la_fld_LastName', 'filter_block' => 'grid_like_filter', 'width' => 120, ),
'UserEmail' => Array ('title' => 'column:la_fld_Email', 'filter_block' => 'grid_like_filter', 'width' => 120, ),
'SessionLogId' => Array ('filter_block' => 'grid_range_filter', 'width' => 120, ),
'Action' => Array ('filter_block' => 'grid_options_filter', 'width' => 120, ),
'OccuredOn' => Array ('filter_block' => 'grid_date_range_filter', 'width' => 150, ),
'MasterPrefix' => Array ('filter_block' => 'grid_options_filter', 'width' => 120, ),
'MasterId' => Array ('filter_block' => 'grid_range_filter', 'width' => 90, ),
'Prefix' => Array ('title' => 'column:la_fld_ItemPrefix', 'filter_block' => 'grid_options_filter', 'width' => 120, ),
'ItemId' => Array ('filter_block' => 'grid_range_filter', 'width' => 120, ),
'Changes' => Array ('data_block' => 'grid_changes_td', 'filter_block' => 'grid_like_filter', 'format' => 'auto_cut', 'width' => 225, ),
),
),
),
);
\ No newline at end of file
Index: branches/5.2.x/core/units/logs/change_logs/change_log_eh.php
===================================================================
--- branches/5.2.x/core/units/logs/change_logs/change_log_eh.php (revision 15129)
+++ branches/5.2.x/core/units/logs/change_logs/change_log_eh.php (revision 15130)
@@ -1,66 +1,66 @@
<?php
/**
* @version $Id$
* @package In-Portal
* @copyright Copyright (C) 1997 - 2011 Intechnic. All rights reserved.
* @license GNU/GPL
* In-Portal is Open Source software.
* This means that this software may have been modified pursuant
* the GNU General Public License, and as distributed it includes
* or is derivative of works licensed under the GNU General Public License
* or other free or open source software licenses.
* See http://www.in-portal.org/license for copyright notices and details.
*/
defined('FULL_PATH') or die('restricted access!');
class ChangeLogEventHandler extends kDBEventHandler {
/**
* Allows to override standard permission mapping
*
* @return void
* @access protected
* @see kEventHandler::$permMapping
*/
protected function mapPermissions()
{
parent::mapPermissions();
$permissions = Array (
'OnEnableLog' => Array ('self' => 'view'),
);
$this->permMapping = array_merge($this->permMapping, $permissions);
}
/**
* Updates affected record count in session, when change log record is deleted
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnAfterItemDelete(kEvent &$event)
+ protected function OnAfterItemDelete(kEvent $event)
{
parent::OnAfterItemDelete($event);
$object =& $event->getObject();
/* @var $object kDBItem */
$sql = 'UPDATE ' . $this->Application->getUnitOption('session-log', 'TableName') . '
SET AffectedItems = AffectedItems - 1
WHERE SessionLogId = ' . $object->GetDBField('SessionLogId');
$this->Conn->Query($sql);
}
/**
* Changes configuration value to enable log writing
*
* @param kEvent $event
*/
- function OnEnableLog(&$event)
+ function OnEnableLog($event)
{
$this->Application->SetConfigValue('UseChangeLog', 1);
}
}
\ No newline at end of file
Index: branches/5.2.x/core/units/scheduled_tasks/scheduled_task_eh.php
===================================================================
--- branches/5.2.x/core/units/scheduled_tasks/scheduled_task_eh.php (revision 15129)
+++ branches/5.2.x/core/units/scheduled_tasks/scheduled_task_eh.php (revision 15130)
@@ -1,178 +1,178 @@
<?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 ScheduledTaskEventHandler extends kDBEventHandler {
/**
* Allows to override standard permission mapping
*
* @return void
* @access protected
* @see kEventHandler::$permMapping
*/
protected function mapPermissions()
{
parent::mapPermissions();
$permissions = Array (
'OnMassCancel' => Array ('self' => 'add|edit'),
'OnRun' => Array ('self' => 'add|edit'),
);
$this->permMapping = array_merge($this->permMapping, $permissions);
}
/**
* [HOOK] Refreshes scheduled task list in database based on cached data from unit configs
*
* @param kEvent $event
*/
- function OnRefresh(&$event)
+ function OnRefresh($event)
{
$scheduled_tasks_from_cache = $this->Application->EventManager->getScheduledTasks(true);
$object =& $event->getObject( Array ('skip_autoload' => true) );
/* @var $object kDBItem */
$processed_ids = Array ();
$scheduled_tasks_from_db = $this->Conn->Query($object->GetSelectSQL(), 'Name');
foreach ($scheduled_tasks_from_cache as $scheduled_task_name => $scheduled_task_params) {
if ( !isset($scheduled_tasks_from_db[$scheduled_task_name]) ) {
$fields_hash = Array (
'Event' => $scheduled_task_params['Event'],
'Name' => $scheduled_task_name,
'Type' => ScheduledTask::TYPE_SYSTEM,
'Status' => isset($scheduled_task_params['Status']) ? $scheduled_task_params['Status'] : STATUS_ACTIVE,
'RunInterval' => $scheduled_task_params['RunInterval'],
);
$object->Clear();
$object->SetDBFieldsFromHash($fields_hash);
$object->Create();
}
else {
$object->LoadFromHash( $scheduled_tasks_from_db[$scheduled_task_name] );
}
$processed_ids[] = $object->GetID();
}
// delete all non-processed scheduled tasks (ones, that were deleted from unit configs)
$sql = 'SELECT ' . $object->IDField . '
FROM ' . $object->TableName . '
WHERE (Type = ' . ScheduledTask::TYPE_SYSTEM . ') AND (' . $object->IDField . ' NOT IN (' . implode(',', $processed_ids) . '))';
$delete_ids = $this->Conn->GetCol($sql);
if ($delete_ids) {
$temp_handler =& $this->Application->recallObject($event->getPrefixSpecial().'_TempHandler', 'kTempTablesHandler');
/* @var $temp_handler kTempTablesHandler */
$temp_handler->DeleteItems($event->Prefix, $event->Special, $delete_ids);
}
$this->Application->removeObject($event->getPrefixSpecial());
}
/**
* Don't allow to delete other user's messages
*
* @param kEvent $event
* @param string $type
* @return void
* @access protected
*/
- protected function customProcessing(kEvent &$event, $type)
+ protected function customProcessing(kEvent $event, $type)
{
if ( $event->Name == 'OnMassDelete' && $type == 'before' ) {
if ( $this->Application->isDebugMode() ) {
// allow to delete system scheduled tasks in debug mode
return;
}
$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 Type <> ' . ScheduledTask::TYPE_SYSTEM;
$event->setEventParam('ids', $this->Conn->GetCol($sql));
}
}
}
/**
* Cancels scheduled tasks, that are currently running
*
* @param kEvent $event
*/
- function OnMassCancel(&$event)
+ function OnMassCancel($event)
{
$ids = $this->StoreSelectedIDs($event);
if ($ids) {
$object =& $event->getObject( Array ('skip_autoload' => true) );
/* @var $object kDBItem */
foreach ($ids as $id) {
$object->Load($id);
if ($object->GetDBField('LastRunStatus') == ScheduledTask::LAST_RUN_RUNNING) {
// only changes status, doesn't affect currency running scheduled tasks
$object->SetDBField('LastRunStatus', ScheduledTask::LAST_RUN_FAILED);
$object->Update();
}
}
}
$this->clearSelectedIDs($event);
}
/**
* Runs selected scheduled tasks
*
* @param kEvent $event
*/
- function OnRun(&$event)
+ function OnRun($event)
{
$ids = $this->StoreSelectedIDs($event);
if ($ids) {
$object =& $event->getObject( Array ('skip_autoload' => true) );
/* @var $object kDBItem */
$where_clause = Array (
$object->TableName . '.' . $object->IDField . ' IN (' . implode(',', $ids) . ')',
$object->TableName . '.Status = ' . STATUS_ACTIVE,
$object->TableName . '.LastRunStatus <> ' . ScheduledTask::LAST_RUN_RUNNING,
);
$sql = $object->GetSelectSQL() . '
WHERE (' . implode(') AND (', $where_clause) . ')';
$scheduled_tasks = $this->Conn->Query($sql);
foreach ($scheduled_tasks as $scheduled_task_data) {
$scheduled_task_data['EventName'] = $scheduled_task_data['Event'];
$this->Application->EventManager->runScheduledTask($scheduled_task_data);
}
}
$this->clearSelectedIDs($event);
}
}
\ No newline at end of file
Index: branches/5.2.x/core/units/promo_block_groups/promo_block_group_eh.php
===================================================================
--- branches/5.2.x/core/units/promo_block_groups/promo_block_group_eh.php (revision 15129)
+++ branches/5.2.x/core/units/promo_block_groups/promo_block_group_eh.php (revision 15130)
@@ -1,134 +1,134 @@
<?php
/**
* @version $Id$
* @package In-Portal
* @copyright Copyright (C) 1997 - 2011 Intechnic. All rights reserved.
* @license GNU/GPL
* In-Portal is Open Source software.
* This means that this software may have been modified pursuant
* the GNU General Public License, and as distributed it includes
* or is derivative of works licensed under the GNU General Public License
* or other free or open source software licenses.
* See http://www.in-portal.org/license for copyright notices and details.
*/
defined('FULL_PATH') or die('restricted access!');
class PromoBlockGroupEventHandler extends kDBEventHandler {
/**
* Occurs before creating item
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnBeforeItemCreate(kEvent &$event)
+ protected function OnBeforeItemCreate(kEvent $event)
{
parent::OnBeforeItemCreate($event);
$this->beforeItemChange($event);
}
/**
* Occurs before updating item
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnBeforeItemUpdate(kEvent &$event)
+ protected function OnBeforeItemUpdate(kEvent $event)
{
parent::OnBeforeItemUpdate($event);
$this->beforeItemChange($event);
}
/**
* Occurs before updating item
*
* @param kEvent $event
* @return void
* @access private
*/
- private function beforeItemChange(&$event)
+ private function beforeItemChange($event)
{
$object =& $event->getObject();
/* @var $object kDBItem */
$object->setRequired('TransitionEffectCustom', $object->GetDBField('TransitionEffect') == '-1');
}
/**
* Occurs before deleting item, id of item being
* deleted is stored as 'id' event param
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnBeforeItemDelete(kEvent &$event)
+ protected function OnBeforeItemDelete(kEvent $event)
{
parent::OnBeforeItemDelete($event);
$object =& $event->getObject();
/* @var $object kDBItem */
$sql = 'SELECT BlockId
FROM ' . TABLE_PREFIX . 'PromoBlocks
WHERE PromoBlockGroupId = ' . $object->GetID();
$block_id = $this->Conn->GetOne($sql);
if ( $block_id ) {
$event->MasterEvent->SetRedirectParam('grid_error', 'la_error_PromoGroupNotEmpty');
$event->status = kEvent::erFAIL;
}
}
/**
* Deleting empty promo block group disconnects it from associated sections
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnAfterItemDelete(kEvent &$event)
+ protected function OnAfterItemDelete(kEvent $event)
{
parent::OnAfterItemDelete($event);
$sql = 'UPDATE ' . TABLE_PREFIX . 'Categories
SET PromoBlockGroupId = 0
WHERE PromoBlockGroupId = ' . $event->getEventParam('id');
$this->Conn->Query($sql);
}
/**
* Set tree update flag
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnSave(kEvent &$event)
+ protected function OnSave(kEvent $event)
{
parent::OnSave($event);
if ( $event->status == kEvent::erSUCCESS ) {
$event->SetRedirectParam('refresh_tree', 1);
}
}
/**
* Set tree update flag
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnMassDelete(kEvent &$event)
+ protected function OnMassDelete(kEvent $event)
{
parent::OnMassDelete($event);
if ( $event->status == kEvent::erSUCCESS ) {
$event->SetRedirectParam('refresh_tree', 1);
}
}
}
Index: branches/5.2.x/core/units/images/image_event_handler.php
===================================================================
--- branches/5.2.x/core/units/images/image_event_handler.php (revision 15129)
+++ branches/5.2.x/core/units/images/image_event_handler.php (revision 15130)
@@ -1,496 +1,496 @@
<?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 ImageEventHandler extends kDBEventHandler {
/**
* Allows to override standard permission mapping
*
* @return void
* @access protected
* @see kEventHandler::$permMapping
*/
protected function mapPermissions()
{
parent::mapPermissions();
$permissions = Array (
'OnCleanImages' => Array ('subitem' => true),
'OnCleanResizedImages' => Array ('subitem' => true),
);
$this->permMapping = array_merge($this->permMapping, $permissions);
}
/**
* Define alternative event processing method names
*
* @return void
* @see kEventHandler::$eventMethods
* @access protected
*/
protected function mapEvents()
{
parent::mapEvents(); // ensure auto-adding of approve/decline and so on events
$image_events = Array (
'OnAfterCopyToTemp'=>'ImageAction',
'OnBeforeDeleteFromLive'=>'ImageAction',
'OnBeforeCopyToLive'=>'ImageAction',
'OnBeforeItemDelete'=>'ImageAction',
'OnAfterClone'=>'ImageAction',
);
$this->eventMethods = array_merge($this->eventMethods, $image_events);
}
/**
* Returns special of main item for linking with sub-item
*
* @param kEvent $event
* @return string
* @access protected
*/
- protected function getMainSpecial(kEvent &$event)
+ protected function getMainSpecial(kEvent $event)
{
if ( $event->Special == 'list' && !$this->Application->isAdmin ) {
// ListImages aggregated tag uses this special
return '';
}
return parent::getMainSpecial($event);
}
/**
* Don't allow to delete primary category item image, when there are no more images
*
* @param kEvent $event
* @param string $type
* @return void
* @access protected
*/
- protected function customProcessing(kEvent &$event, $type)
+ protected function customProcessing(kEvent $event, $type)
{
$object =& $event->getObject();
/* @var $object kDBItem */
if ( $event->Name == 'OnMassDelete' && $type == 'before' ) {
$ids = $event->getEventParam('ids');
$parent_info = $object->getLinkedInfo($event->Special);
$sql = 'SELECT ImageId
FROM ' . $object->TableName . '
WHERE DefaultImg = 1 AND ' . $parent_info['ForeignKey'] . ' = ' . $parent_info['ParentId'];
$primary_file_id = $this->Conn->GetOne($sql);
if ( $primary_file_id ) {
$file_id_index = array_search($primary_file_id, $ids);
if ( $file_id_index ) {
// allow deleting of primary product file, when there is another file to make primary
$sql = 'SELECT COUNT(*)
FROM ' . $object->TableName . '
WHERE DefaultImg = 0 AND ' . $parent_info['ForeignKey'] . ' = ' . $parent_info['ParentId'];
$non_primary_file_count = $this->Conn->GetOne($sql);
if ( $non_primary_file_count ) {
unset($ids[$file_id_index]);
}
}
}
$event->setEventParam('ids', $ids);
}
switch ($type) {
case 'before' :
// empty unused fields
$object->SetDBField($object->GetDBField('LocalImage') ? 'Url' : 'LocalPath', '');
$object->SetDBField($object->GetDBField('LocalThumb') ? 'ThumbUrl' : 'ThumbPath', '');
if ( $object->GetDBField('SameImages') ) {
$object->SetDBField('LocalImage', 1);
$object->SetDBField('LocalPath', '');
$object->SetDBField('Url', '');
}
break;
case 'after':
// make sure, that there is only one primary image for the item
if ( $object->GetDBField('DefaultImg') ) {
$sql = 'UPDATE ' . $object->TableName . '
SET DefaultImg = 0
WHERE ResourceId = ' . $object->GetDBField('ResourceId') . ' AND ImageId <> ' . $object->GetID();
$this->Conn->Query($sql);
}
break;
}
}
/**
* Performs temp-table related action on current image record
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function ImageAction(&$event)
+ protected function ImageAction($event)
{
$id = $event->getEventParam('id');
$object =& $this->Application->recallObject($event->Prefix . '.-item', $event->Prefix, Array ('skip_autoload' => true));
/* @var $object kDBItem */
if ( in_array($event->Name, Array ('OnBeforeDeleteFromLive', 'OnAfterClone')) ) {
$object->SwitchToLive();
}
elseif ( $event->Name == 'OnBeforeItemDelete' ) {
// keep current table
}
else {
$object->SwitchToTemp();
}
$object->Load($id);
$file_helper =& $this->Application->recallObject('FileHelper');
/* @var $file_helper FileHelper */
$fields = Array ('LocalPath' => 'LocalImage', 'ThumbPath' => 'LocalThumb');
foreach ($fields as $a_field => $mode_field) {
$file = $object->GetDBField($a_field);
if ( !$file ) {
continue;
}
$source_file = FULL_PATH . $file;
switch ($event->Name) {
// Copy image files to pending dir and update corresponding fields in temp record
// Checking for existing files and renaming if necessary - two users may upload same pending files at the same time!
case 'OnAfterCopyToTemp':
$file = preg_replace('/^' . preg_quote(IMAGES_PATH, '/') . '/', IMAGES_PENDING_PATH, $file, 1);
$new_file = $file_helper->ensureUniqueFilename(FULL_PATH, $file);
$dst_file = FULL_PATH . $new_file;
copy($source_file, $dst_file);
$object->SetFieldOption($a_field, 'skip_empty', false);
$object->SetDBField($a_field, $new_file);
break;
// Copy image files to live dir (checking if file exists and renaming if necessary)
// and update corresponding fields in temp record (which gets copied to live automatically)
case 'OnBeforeCopyToLive':
if ( $object->GetDBField($mode_field) ) {
// if image is local -> rename file if it exists in live folder
$file = preg_replace('/^' . preg_quote(IMAGES_PENDING_PATH, '/') . '/', IMAGES_PATH, $file, 1);
$new_file = $file_helper->ensureUniqueFilename(FULL_PATH, $file);
$dst_file = FULL_PATH . $new_file;
rename($source_file, $dst_file);
}
else {
// if image is remote url - remove local file (if any), update local file field with empty value
if ( file_exists($source_file) ) {
@unlink($source_file);
}
$new_file = '';
}
$object->SetFieldOption($a_field, 'skip_empty', false);
$object->SetDBField($a_field, $new_file);
break;
case 'OnBeforeDeleteFromLive': // Delete image files from live folder before copying over from temp
case 'OnBeforeItemDelete': // Delete image files when deleting Image object
@unlink(FULL_PATH . $file);
break;
case 'OnAfterClone':
// Copy files when cloning objects, renaming it on the fly
$new_file = $file_helper->ensureUniqueFilename(FULL_PATH, $file);
$dst_file = FULL_PATH . $new_file;
copy($source_file, $dst_file);
$object->SetFieldOption($a_field, 'skip_empty', false);
$object->SetDBField($a_field, $new_file);
break;
}
}
if ( in_array($event->Name, Array ('OnAfterClone', 'OnBeforeCopyToLive', 'OnAfterCopyToTemp')) ) {
$object->Update(null, true);
}
}
/**
* Sets primary image of user/category/category item
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnSetPrimary(&$event)
+ protected function OnSetPrimary($event)
{
$object =& $event->getObject();
/* @var $object kDBItem */
$object->SetDBField('DefaultImg', 1);
$object->Update();
}
/**
* Occurs before updating item
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnBeforeItemUpdate(kEvent &$event)
+ protected function OnBeforeItemUpdate(kEvent $event)
{
parent::OnBeforeItemUpdate($event);
$this->processImageStatus($event);
}
/**
* Occurs after creating item
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnAfterItemCreate(kEvent &$event)
+ protected function OnAfterItemCreate(kEvent $event)
{
parent::OnAfterItemCreate($event);
$this->processImageStatus($event);
$object =& $event->getObject();
/* @var $object kDBItem */
$object->Update();
}
/**
* Occurs before item changed
*
* @param kEvent $event
*/
- function processImageStatus(&$event)
+ function processImageStatus($event)
{
$object =& $event->getObject();
/* @var $object kDBItem */
$id = $object->GetDBField('ResourceId');
$sql = 'SELECT ImageId
FROM ' . $object->TableName . '
WHERE ResourceId = ' . $id . ' AND DefaultImg = 1';
$primary_image_id = $this->Conn->GetOne($sql);
if ( !$primary_image_id ) {
$object->SetDBField('DefaultImg', 1);
}
if ( $object->GetDBField('DefaultImg') && $object->Validate() ) {
$sql = 'UPDATE ' . $object->TableName . '
SET DefaultImg = 0
WHERE ResourceId = ' . $id . ' AND ImageId <> ' . $object->GetDBField('ImageId');
$this->Conn->Query($sql);
$object->SetDBField('Enabled', 1);
}
}
/**
* Apply any custom changes to list's sql query
*
* @param kEvent $event
* @return void
* @access protected
* @see kDBEventHandler::OnListBuild()
*/
- protected function SetCustomQuery(kEvent &$event)
+ protected function SetCustomQuery(kEvent $event)
{
parent::SetCustomQuery($event);
$object =& $event->getObject();
/* @var $object kDBList */
if ( !$this->Application->isAdminUser ) {
$object->addFilter('active', '%1$s.Enabled = 1');
}
$product_id = $event->getEventParam('product_id');
if ( $product_id ) {
$object->removeFilter('parent_filter');
$sql = 'SELECT ResourceId
FROM ' . $this->Application->getUnitOption('p', 'TableName') . '
WHERE ProductId = ' . $product_id;
$resource_id = (int)$this->Conn->GetOne($sql);
$object->addFilter('product_images', '%1$s.ResourceId = ' . $resource_id);
}
$search_helper =& $this->Application->recallObject('SearchHelper');
/* @var $search_helper kSearchHelper */
$types = $event->getEventParam('types');
$except_types = $event->getEventParam('except');
$type_clauses = $this->getTypeClauses($event);
$search_helper->SetComplexFilter($event, $type_clauses, $types, $except_types);
}
/**
* Return type clauses for list bulding on front
*
* @param kEvent $event
* @return Array
*/
- function getTypeClauses(&$event)
+ function getTypeClauses($event)
{
$type_clauses = Array ();
$type_clauses['additional']['include'] = '%1$s.DefaultImg != 1';
$type_clauses['additional']['except'] = '%1$s.DefaultImg = 1';
$type_clauses['additional']['having_filter'] = false;
return $type_clauses;
}
/**
* [SCHEDULED TASK] Remove unused images from "/system/images" and "/system/images/pending" folders
*
* @param kEvent $event
*/
- function OnCleanImages(&$event)
+ function OnCleanImages($event)
{
// 1. get images, that are currently in use
$active_images = $this->_getActiveImages( $this->Application->getUnitOption('img', 'TableName') );
$active_images[] = 'noimage.gif';
// 2. get images on disk
$this->_deleteUnusedImages(FULL_PATH . IMAGES_PATH, $active_images);
// 3. get images in use from "images/pending" folder
$active_images = $this->_getPendingImages();
// 4. get image on disk
$this->_deleteUnusedImages(FULL_PATH . IMAGES_PENDING_PATH, $active_images);
}
/**
* Gets image filenames (no path) from given table
*
* @param string $image_table
* @return Array
*/
function _getActiveImages($image_table)
{
$sql = 'SELECT LocalPath, ThumbPath
FROM ' . $image_table . '
WHERE COALESCE(LocalPath, "") <> "" OR COALESCE(ThumbPath) <> ""';
$images = $this->Conn->Query($sql);
$active_images = Array ();
foreach ($images as $image) {
if ($image['LocalPath']) {
$active_images[] = basename($image['LocalPath']);
}
if ($image['ThumbPath']) {
$active_images[] = basename($image['ThumbPath']);
}
}
return $active_images;
}
/**
* Gets active images, that are currently beeing edited inside temporary tables
*
* @return Array
*/
function _getPendingImages()
{
$tables = $this->Conn->GetCol('SHOW TABLES');
$mask_edit_table = '/'.TABLE_PREFIX.'ses_(.*)_edit_' . TABLE_PREFIX . 'CatalogImages/';
$active_images = Array ();
foreach ($tables as $table) {
if (!preg_match($mask_edit_table, $table)) {
continue;
}
$active_images = array_unique( array_merge($active_images, $this->_getActiveImages($table)) );
}
return $active_images;
}
/**
* Deletes all files in given path, except of given $active_images
*
* @param string $path
* @param Array $active_images
*/
function _deleteUnusedImages($path, &$active_images)
{
$images = glob($path . '*.*');
if ($images) {
$images = array_map('basename', $images);
// delete images, that are on disk, but are not mentioned in CatalogImages table
$delete_images = array_diff($images, $active_images);
foreach ($delete_images as $delete_image) {
unlink($path . $delete_image);
}
}
}
/**
* [SCHEDULED TASK] Remove all images from "/system/images/resized" and "/system/images/pending/resized" folders
*
* @param kEvent $event
*/
- function OnCleanResizedImages(&$event)
+ function OnCleanResizedImages($event)
{
$images = glob(FULL_PATH . IMAGES_PATH . 'resized/*.*');
if ($images) {
foreach ($images as $image) {
unlink($image);
}
}
$images = glob(FULL_PATH . IMAGES_PENDING_PATH . 'resized/*.*');
if ($images) {
foreach ($images as $image) {
unlink($image);
}
}
}
}
\ No newline at end of file
Index: branches/5.2.x/core/units/configuration/configuration_event_handler.php
===================================================================
--- branches/5.2.x/core/units/configuration/configuration_event_handler.php (revision 15129)
+++ branches/5.2.x/core/units/configuration/configuration_event_handler.php (revision 15130)
@@ -1,376 +1,376 @@
<?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 ConfigurationEventHandler extends kDBEventHandler {
/**
* Allows to override standard permission mapping
*
* @return void
* @access protected
* @see kEventHandler::$permMapping
*/
protected function mapPermissions()
{
parent::mapPermissions();
$permissions = Array (
'OnGenerateMaintenancePage' => Array ('self' => 'add|edit'),
);
$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(kEvent &$event)
+ public function CheckPermission(kEvent $event)
{
$event->setEventParam('PermSection', $this->Application->GetVar('section'));
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(kEvent &$event)
+ protected function SetCustomQuery(kEvent $event)
{
parent::SetCustomQuery($event);
$object =& $event->getObject();
/* @var $object kDBList */
$module = $this->Application->GetVar('module');
$section = $this->Application->GetVar('section');
$object->addFilter('module_filter', '%1$s.ModuleOwner = ' . $this->Conn->qstr($module));
$object->addFilter('section_filter', '%1$s.Section = ' . $this->Conn->qstr($section));
if ( !$this->Application->ConfigValue('AllowAdminConsoleInterfaceChange') ) {
$object->addFilter('interface_change_filter', '%1$s.VariableName <> "AdminConsoleInterface"');
}
if ( defined('IS_INSTALL') && IS_INSTALL ) {
$object->addFilter('install_filter', '%1$s.Install = 1');
}
$object->addFilter('visible_filter', '%1$s.Heading <> ""');
}
/**
* Performs validation of configuration variable value
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnBeforeItemUpdate(kEvent &$event)
+ protected function OnBeforeItemUpdate(kEvent $event)
{
static $default_field_options = null;
parent::OnBeforeItemUpdate($event);
$object =& $event->getObject();
/* @var $object kDBItem */
// ability to validate each configuration variable separately
if ( !isset($default_field_options) ) {
$default_field_options = $object->GetFieldOptions('VariableValue');
}
$new_field_options = $default_field_options;
$validation = $object->GetDBField('Validation');
if ( $validation ) {
$new_field_options = array_merge($new_field_options, unserialize($validation));
}
$object->SetFieldOptions('VariableValue', $new_field_options);
// if password field is empty, then don't update
if ( $object->GetDBField('ElementType') == 'password' ) {
if ( trim($object->GetDBField('VariableValue')) == '' ) {
$field_options = $object->GetFieldOptions('VariableValue');
$field_options['skip_empty'] = 1;
$object->SetFieldOptions('VariableValue', $field_options);
}
else {
$password_formatter =& $this->Application->recallObject('kPasswordFormatter');
/* @var $password_formatter kPasswordFormatter */
$object->SetDBField('VariableValue', $password_formatter->EncryptPassword($object->GetDBField('VariableValue'), 'b38'));
}
}
$field_name = $object->GetDBField('VariableName');
$field_values = $this->Application->GetVar($event->getPrefixSpecial(true));
$state_country_hash = Array ('Comm_State' => 'Comm_Country', 'Comm_Shipping_State' => 'Comm_Shipping_Country');
if ( array_key_exists($field_name, $state_country_hash) ) {
// if this is state field
$sql = 'SELECT VariableId
FROM ' . $this->Application->getUnitOption('conf', 'TableName') . '
WHERE VariableName = "' . $state_country_hash[$field_name] . '"';
$country_variable_id = $this->Conn->GetOne($sql);
$check_state = $object->GetDBField('VariableValue');
$check_country = $field_values[$country_variable_id]['VariableValue'];
if ( !$check_country || !$check_state ) {
return;
}
$cs_helper =& $this->Application->recallObject('CountryStatesHelper');
/* @var $cs_helper kCountryStatesHelper */
$state_iso = $cs_helper->getStateIso($check_state, $check_country);
if ( $state_iso !== false ) {
$object->SetDBField('VariableValue', $state_iso);
}
else {
// selected state doesn't belong to selected country
$object->SetError('VariableValue', 'invalid_state', 'la_InvalidState');
}
}
$variable_name = $object->GetDBField('VariableName');
$new_value = $object->GetDBField('VariableValue');
if ( $variable_name == 'AdminConsoleInterface' ) {
$can_change = $this->Application->ConfigValue('AllowAdminConsoleInterfaceChange');
if ( ($new_value != $object->GetOriginalField('VariableValue')) && !$can_change ) {
$object->SetError('VariableValue', 'not_allowed', 'la_error_OperationNotAllowed');
}
}
elseif ( $variable_name == 'HardMaintenanceTemplate' ) {
$compile = $event->MasterEvent->getEventParam('compile_maintenance_template');
$compile = $compile || $new_value != $object->GetOriginalField('VariableValue');
if ( $compile && !$this->generateMaintenancePage($new_value) ) {
$object->SetError('VariableValue', 'template_file_missing', 'la_error_TemplateFileMissing');
}
}
elseif ( $variable_name == 'DefaultEmailRecipients' ) {
$email_event_data = $this->Application->GetVar('emailevents_' . $event->Prefix);
$object->SetDBField('VariableValue', $email_event_data[0]['Recipients']);
}
}
/**
* Occurs after updating item
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnAfterItemUpdate(kEvent &$event)
+ protected function OnAfterItemUpdate(kEvent $event)
{
static $skin_deleted = false;
parent::OnAfterItemUpdate($event);
$object =& $event->getObject();
/* @var $object kDBItem */
if ( $object->GetDBField('ElementType') == 'password' ) {
if ( trim($object->GetDBField('VariableValue')) == '' ) {
$field_options = $object->GetFieldOptions('VariableValue');
unset($field_options['skip_empty']);
$object->SetFieldOptions('VariableValue', $field_options);
}
}
// allows to check if variable's value was changed now
$variable_name = $object->GetDBField('VariableName');
$changed = $this->Application->GetVar($event->getPrefixSpecial() . '_changed', Array ());
if ( $object->GetDBField('VariableValue') != $object->GetOriginalField('VariableValue') ) {
$changed[] = $variable_name;
$this->Application->SetVar($event->getPrefixSpecial() . '_changed', $changed);
// update value in cache, so other code (during this script run) would use new value
$this->Application->SetConfigValue($variable_name, $object->GetDBField('VariableValue'), true);
}
if ( $variable_name == 'Require_AdminSSL' || $variable_name == 'AdminSSL_URL' ) {
// when administrative console is moved to SSL mode, then delete skin
if ( in_array($variable_name, $changed) && !$skin_deleted ) {
$skin_helper =& $this->Application->recallObject('SkinHelper');
/* @var $skin_helper SkinHelper */
$skin_file = $skin_helper->getSkinPath();
if ( file_exists($skin_file) ) {
unlink($skin_file);
}
$skin_deleted = true;
}
}
$this->Application->StoreVar('config_was_updated', 1);
}
/**
* Updates kDBItem
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnUpdate(kEvent &$event)
+ protected function OnUpdate(kEvent $event)
{
if ( $this->Application->CheckPermission('SYSTEM_ACCESS.READONLY', 1) ) {
$event->status = kEvent::erFAIL;
return;
}
$items_info = $this->Application->GetVar($event->getPrefixSpecial(true));
// 1. save user selected module root category
$new_category_id = getArrayValue($items_info, 'ModuleRootCategory', 'VariableValue');
if ( $new_category_id !== false ) {
unset($items_info['ModuleRootCategory']);
}
$object =& $event->getObject( Array('skip_autoload' => true) );
/* @var $object kDBItem */
if ( $items_info ) {
$has_error = false;
foreach ($items_info as $id => $field_values) {
$object->Clear(); // clear validation errors from previous variable
$object->Load($id);
$object->SetFieldsFromHash($field_values, $this->getRequestProtectedFields($field_values));
if ( !$object->Update($id) ) {
// don't stop when error found !
$has_error = true;
}
}
$event->status = $has_error ? kEvent::erFAIL : kEvent::erSUCCESS;
}
if ( $event->status == kEvent::erSUCCESS ) {
if ( $new_category_id !== false ) {
// root category was submitted
$module = $this->Application->GetVar('module');
$root_category_id = $this->Application->findModule('Name', $module, 'RootCat');
if ( $root_category_id != $new_category_id ) {
// root category differs from one in db
$fields_hash = Array ('RootCat' => $new_category_id);
$this->Conn->doUpdate($fields_hash, TABLE_PREFIX . 'Modules', 'Name = ' . $this->Conn->qstr($module));
}
}
// reset cache
$changed = $this->Application->GetVar($event->getPrefixSpecial() . '_changed', Array ());
$require_refresh = Array ('AdvancedUserManagement', 'Site_Name', 'AdminConsoleInterface', 'UsePopups');
$refresh_sections = array_intersect($require_refresh, $changed);
$require_full_refresh = Array ('Site_Name', 'AdminConsoleInterface');
if ( array_intersect($require_full_refresh, $changed) ) {
$event->SetRedirectParam('refresh_all', 1);
}
elseif ( $refresh_sections ) {
$event->SetRedirectParam('refresh_tree', 1);
}
if ( $refresh_sections ) {
// reset sections too, because of AdvancedUserManagement
$this->Application->DeleteSectionCache();
}
$this->Application->DeleteUnitCache($changed);
}
elseif ( $this->Application->GetVar('errors_' . $event->getPrefixSpecial()) ) {
// because we have list out there, and this is item
$this->Application->removeObject($event->getPrefixSpecial());
}
// keeps module and section in REQUEST to ensure, that last admin template will work
$event->SetRedirectParam('module', $this->Application->GetVar('module'));
$event->SetRedirectParam('section', $this->Application->GetVar('section'));
}
/**
* Process items from selector (selected_ids var, key - prefix, value - comma separated ids)
*
* @param kEvent $event
*/
- function OnProcessSelected(&$event)
+ function OnProcessSelected($event)
{
$selected_ids = $this->Application->GetVar('selected_ids');
$this->Application->StoreVar('ModuleRootCategory', $selected_ids['c']);
$event->SetRedirectParam('opener', 'u');
}
/**
* Generates maintenance page
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnGenerateMaintenancePage(kEvent &$event)
+ protected function OnGenerateMaintenancePage(kEvent $event)
{
$event->setEventParam('compile_maintenance_template', 1);
$event->CallSubEvent('OnUpdate');
}
/**
* Generates HTML version of hard maintenance template
*
* @param string $template
* @return bool
* @access protected
*/
protected function generateMaintenancePage($template = null)
{
if ( !isset($template) ) {
$template = $this->Application->ConfigValue('HardMaintenanceTemplate');
}
$curl_helper =& $this->Application->recallObject('CurlHelper');
/* @var $curl_helper kCurlHelper */
$html = $curl_helper->Send($this->Application->BaseURL() . '?t=' . $template);
if ( $curl_helper->isGoodResponseCode() ) {
file_put_contents(WRITEABLE . DIRECTORY_SEPARATOR . 'maintenance.html', $html);
return true;
}
return false;
}
}
\ No newline at end of file
Index: branches/5.2.x/core/units/filters/item_filter_eh.php
===================================================================
--- branches/5.2.x/core/units/filters/item_filter_eh.php (revision 15129)
+++ branches/5.2.x/core/units/filters/item_filter_eh.php (revision 15130)
@@ -1,159 +1,159 @@
<?php
/**
* @version $Id$
* @package In-Portal
* @copyright Copyright (C) 1997 - 2011 Intechnic. All rights reserved.
* @license GNU/GPL
* In-Portal is Open Source software.
* This means that this software may have been modified pursuant
* the GNU General Public License, and as distributed it includes
* or is derivative of works licensed under the GNU General Public License
* or other free or open source software licenses.
* See http://www.in-portal.org/license for copyright notices and details.
*/
defined('FULL_PATH') or die('restricted access!');
class ItemFilterEventHandler extends kDBEventHandler {
/**
* Allows to override standard permission mapping
*
* @return void
* @access protected
* @see kEventHandler::$permMapping
*/
protected function mapPermissions()
{
parent::mapPermissions();
$permissions = Array (
'OnItemBuild' => Array ('self' => true),
);
$this->permMapping = array_merge($this->permMapping, $permissions);
}
/**
* Apply any custom changes to list's sql query
*
* @param kEvent $event
* @return void
* @access protected
* @see kDBEventHandler::OnListBuild()
*/
- protected function SetCustomQuery(kEvent &$event)
+ protected function SetCustomQuery(kEvent $event)
{
parent::SetCustomQuery($event);
if ( !$this->Application->isAdmin ) {
$object =& $event->getObject();
/* @var $object kDBList */
$prefix_info = $this->Application->processPrefix($event->getEventParam('prefix'));
$object->addFilter('prefix_filter', '%1$s.ItemPrefix = ' . $this->Conn->qstr($prefix_info['prefix']));
$object->addFilter('status_filter', '%1$s.Enabled = 1');
if ( $event->Special == 'used' ) {
$filters = array_keys($this->Application->GetVar('filters', Array ()));
if ( $filters ) {
$filters = $this->Conn->qstrArray($filters);
$object->addFilter('field_filter', '%1$s.FilterField IN (' . implode(',', $filters) . ')');
}
else {
$object->addFilter('field_filter', 'FALSE');
}
}
$exclude_filters = $this->Application->GetVar('exclude_filters');
if ( $exclude_filters ) {
$exclude_filters = $this->Conn->qstrArray(explode(',', $exclude_filters));
$object->addFilter('field_filter', '%1$s.FilterField NOT IN (' . implode(',', $exclude_filters) . ')');
}
if ( $event->getEventParam('per_page') === false ) {
$event->setEventParam('per_page', -1);
}
}
}
/**
* Validates filter settings
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnBeforeItemValidate(kEvent &$event)
+ protected function OnBeforeItemValidate(kEvent $event)
{
parent::OnBeforeItemValidate($event);
$object =& $event->getObject();
/* @var $object kDBItem */
$prefix = $object->GetDBField('ItemPrefix');
if ( $prefix ) {
if ( !$this->Application->prefixRegistred($prefix) ) {
$object->SetError('ItemPrefix', 'not_registered');
}
$field = $object->GetDBField('FilterField');
if ( $field ) {
$fields = $this->Application->getUnitOption($prefix, 'Fields');
$virtual_fields = $this->Application->getUnitOption($prefix, 'VirtualFields');
if ( !isset($fields[$field]) && !isset($virtual_fields[$field]) ) {
$object->SetError('FilterField', 'non_existing', null, Array ($prefix));
}
}
}
$object->setRequired('RangeCount', $object->GetDBField('FilterType') == 'range');
}
/**
* Load item if id is available
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function LoadItem(kEvent &$event)
+ protected function LoadItem(kEvent $event)
{
static $cache = null;
if ( $this->Application->isAdmin ) {
parent::LoadItem($event);
return;
}
$object =& $event->getObject();
/* @var $object kDBItem */
if ( !isset($cache) ) {
$cache = $this->Conn->Query($object->GetSelectSQL(), 'FilterKey');
}
$filter_key = $event->getEventParam('prefix') . '_' . $event->getEventParam('field');
if ( isset($cache[$filter_key]) ) {
$object->LoadFromHash($cache[$filter_key]);
}
if ( $object->isLoaded() ) {
$actions =& $this->Application->recallObject('kActions');
/* @var $actions Params */
$actions->Set($event->getPrefixSpecial() . '_id', $object->GetID());
}
else {
$object->setID(false);
}
}
}
Index: branches/5.2.x/core/units/modules/modules_event_handler.php
===================================================================
--- branches/5.2.x/core/units/modules/modules_event_handler.php (revision 15129)
+++ branches/5.2.x/core/units/modules/modules_event_handler.php (revision 15130)
@@ -1,178 +1,178 @@
<?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 ModulesEventHandler extends kDBEventHandler {
/**
* Builds item (loads if needed)
*
* Pattern: Prototype Manager
*
* @param kEvent $event
* @access protected
*/
- protected function OnItemBuild(kEvent &$event)
+ protected function OnItemBuild(kEvent $event)
{
$this->Application->SetVar($event->getPrefixSpecial(true) . '_id', $event->Special);
parent::OnItemBuild($event);
}
/**
* Apply any custom changes to list's sql query
*
* @param kEvent $event
* @return void
* @access protected
* @see kDBEventHandler::OnListBuild()
*/
- protected function SetCustomQuery(kEvent &$event)
+ protected function SetCustomQuery(kEvent $event)
{
parent::SetCustomQuery($event);
$object =& $event->getObject();
/* @var $object kDBList */
if ( $event->Special ) {
$object->addFilter('current_module', '%1$s.Name = ' . $event->Special);
}
$object->addFilter('not_core', '%1$s.Name <> "Core"');
}
/**
* Define alternative event processing method names
*
* @return void
* @see kEventHandler::$eventMethods
* @access protected
*/
protected function mapEvents()
{
parent::mapEvents();
$this->eventMethods['OnMassApprove'] = 'moduleAction';
$this->eventMethods['OnMassDecline'] = 'moduleAction';
}
/**
* Disabled modules, but not In-Portal
*
* @param kEvent $event
*/
- function moduleAction(&$event)
+ function moduleAction($event)
{
if ($this->Application->CheckPermission('SYSTEM_ACCESS.READONLY', 1)) {
$event->status = kEvent::erFAIL;
return ;
}
$object =& $event->getObject( Array('skip_autoload' => true) );
/* @var $object kDBItem */
$ids = $this->StoreSelectedIDs($event);
if (!$ids) {
return ;
}
$updated = 0;
$status_field = $this->Application->getUnitOption($event->Prefix, 'StatusField');
$status_field = array_shift($status_field);
foreach ($ids as $id) {
$object->Load($id);
if (in_array($id, Array ('In-Portal', 'Core')) || !$object->isLoaded()) {
// don't allow any kind of manupulations with kernel
// approve/decline on not installed module
continue;
}
$enabled = $event->Name == 'OnMassApprove' ? 1 : 0;
$object->SetDBField($status_field, $enabled);
if (!$object->GetChangedFields()) {
// no changes -> skip
continue;
}
if ($object->Update()) {
$updated++;
$sql = 'UPDATE ' . TABLE_PREFIX . 'ImportScripts
SET Status = ' . $enabled . '
WHERE Module = "' . $object->GetDBField('Name') . '"';
$this->Conn->Query($sql);
}
else {
$event->status = kEvent::erFAIL;
$event->redirect = false;
break;
}
}
if ( $updated ) {
$event->status = kEvent::erSUCCESS;
$event->SetRedirectParam('opener', 's');
$this->Application->DeleteUnitCache();
$this->Application->DeleteSectionCache();
$event->SetRedirectParam('RefreshTree', 1);
}
}
/**
* Occurs after list is queried
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnAfterListQuery(kEvent &$event)
+ protected function OnAfterListQuery(kEvent $event)
{
parent::OnAfterListQuery($event);
$modules_helper =& $this->Application->recallObject('ModulesHelper');
/* @var $modules_helper kModulesHelper */
$new_modules = $modules_helper->getModules(kModulesHelper::NOT_INSTALLED);
if ( !$new_modules || $this->Application->RecallVar('user_id') != USER_ROOT ) {
return;
}
require_once FULL_PATH . '/core/install/install_toolkit.php';
$toolkit = new kInstallToolkit();
$object =& $event->getObject();
/* @var $object kDBList */
foreach ($new_modules as $module) {
$module_record = Array (
'Name' => $toolkit->getModuleName($module),
'Path' => 'modules/' . $module . '/',
'Version' => $toolkit->GetMaxModuleVersion('modules/' . $module . '/'),
'Loaded' => 0,
'BuildDate' => null,
);
$object->addRecord($module_record);
}
}
}
\ No newline at end of file
Index: branches/5.2.x/core/units/content/content_eh.php
===================================================================
--- branches/5.2.x/core/units/content/content_eh.php (revision 15129)
+++ branches/5.2.x/core/units/content/content_eh.php (revision 15130)
@@ -1,208 +1,208 @@
<?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 ContentEventHandler extends kDBEventHandler {
/**
* Checks user permission to execute given $event
*
* @param kEvent $event
* @return bool
* @access public
*/
- public function CheckPermission(kEvent &$event)
+ public function CheckPermission(kEvent $event)
{
$perm_helper =& $this->Application->recallObject('PermissionsHelper');
/* @var $perm_helper kPermissionsHelper */
$user_id = $this->Application->RecallVar('user_id');
// user can change top category
$top_category = $this->Application->getBaseCategory();
$perm_status = $perm_helper->CheckUserPermission($user_id, 'CATEGORY.MODIFY', 0, $top_category);
return $perm_helper->finalizePermissionCheck($event, $perm_status);
}
/**
* Saves changes to a content block (+ creates draft if missing)
*
* @param kEvent $event
*/
- function OnSaveContentBlock(&$event)
+ function OnSaveContentBlock($event)
{
if ($this->Application->CheckPermission('SYSTEM_ACCESS.READONLY', 1)) {
$event->status = kEvent::erFAIL;
return ;
}
if ( !$this->saveContentBlock($event, false) ) {
$event->status = kEvent::erFAIL;
}
$event->SetRedirectParam('opener', 'u');
}
/**
* Performs auto-save of current content block (will create draft too)
*
* @param kEvent $event
*/
- function OnAutoSave(&$event)
+ function OnAutoSave($event)
{
$event->status = kEvent::erSTOP;
if ( $this->Application->GetVar('ajax') != 'yes' ) {
return ;
}
echo $this->saveContentBlock($event, true);
}
/**
* Saves content block
*
* @param kEvent $event
* @param bool $is_draft
* @return string
*/
- function saveContentBlock(&$event, $is_draft)
+ function saveContentBlock($event, $is_draft)
{
$object =& $event->getObject( Array('skip_autoload' => true) );
/* @var $object kDBItem */
$items_info = $this->Application->GetVar( $event->getPrefixSpecial(true) );
if ( !$items_info ) {
return '';
}
list ($object, $revision) = $this->getContentBlockAndRevision($event);
/* @var $revision kDBItem */
list (, $field_values) = each($items_info);
$object->SetFieldsFromHash($field_values, $this->getRequestProtectedFields($field_values));
$updated = $object->Update();
if ( $updated ) {
$revision->SetDBField('AutoSavedOn_date', adodb_mktime());
$revision->SetDBField('AutoSavedOn_time', adodb_mktime());
$revision->Update();
}
if ( $is_draft ) {
if ( $updated ) {
$page_helper =& $this->Application->recallObject('PageHelper');
/* @var $page_helper PageHelper */
return $revision->GetField('AutoSavedOn') . ' (' . $page_helper->getAgoTime( $revision->GetDBField('AutoSavedOn') ) . ')';
}
}
else {
return $updated;
}
return '';
}
/**
* Returns last autosave time
*
* @param kEvent $event
*/
- function OnGetAutoSaveTime(&$event)
+ function OnGetAutoSaveTime($event)
{
$event->status = kEvent::erSTOP;
if ( $this->Application->GetVar('ajax') != 'yes' ) {
return ;
}
list ($object, $revision) = $this->getContentBlockAndRevision($event);
/* @var $revision kDBItem */
$page_helper =& $this->Application->recallObject('PageHelper');
/* @var $page_helper PageHelper */
$time = $revision->GetField('AutoSavedOn');
if ( $time ) {
echo $time . ' (' . $page_helper->getAgoTime( $revision->GetDBField('AutoSavedOn') ) . ')';
}
}
/**
* Loads content block from given revision
*
* @param kDBItem $object
* @param kDBItem $revision
*/
function loadFromRevision(&$object, &$revision)
{
$load_keys = Array (
'PageId' => $object->GetDBField('PageId'),
'ContentNum' => $object->GetDBField('ContentNum'),
'RevisionId' => $revision->GetID(),
);
$object->Load($load_keys);
}
- function getContentBlockAndRevision(&$event)
+ function getContentBlockAndRevision($event)
{
$object =& $event->getObject( Array('skip_autoload' => true) );
/* @var $object kDBItem */
$items_info = $this->Application->GetVar( $event->getPrefixSpecial(true) );
if ( !$items_info ) {
return ;
}
list ($id, $field_values) = each($items_info);
$object->Load($id);
$revision =& $this->Application->recallObject('page-revision', null, Array ('skip_autoload' => true));
/* @var $revision kDBItem */
$revision->Load( $object->GetDBField('RevisionId') );
if ( $this->Application->ConfigValue('EnablePageContentRevisionControl') && !$revision->GetDBField('IsDraft') ) {
// editing live revision of a page's content block -> get draft for current user and page
$load_keys = Array (
'PageId' => $revision->GetDBField('PageId'),
'IsDraft' => 1,
'CreatedById' => $this->Application->RecallVar('user_id'),
);
$revision->Load($load_keys);
if ( $revision->isLoaded() ) {
// draft found -> use draft's content block version
$this->loadFromRevision($object, $revision);
}
else {
// draft not found -> create new
$revision->SetDBFieldsFromHash($load_keys);
$revision->SetDBField('FromRevisionId', $object->GetDBField('RevisionId'));
if ( $revision->Create() ) {
$this->loadFromRevision($object, $revision);
}
}
}
return Array (&$object, &$revision);
}
}
\ No newline at end of file
Index: branches/5.2.x/core/units/permission_types/permission_type_eh.php
===================================================================
--- branches/5.2.x/core/units/permission_types/permission_type_eh.php (revision 15129)
+++ branches/5.2.x/core/units/permission_types/permission_type_eh.php (revision 15130)
@@ -1,42 +1,42 @@
<?php
/**
* @version $Id$
* @package In-Portal
* @copyright Copyright (C) 1997 - 2011 Intechnic. All rights reserved.
* @license GNU/GPL
* In-Portal is Open Source software.
* This means that this software may have been modified pursuant
* the GNU General Public License, and as distributed it includes
* or is derivative of works licensed under the GNU General Public License
* or other free or open source software licenses.
* See http://www.in-portal.org/license for copyright notices and details.
*/
defined('FULL_PATH') or die('restricted access!');
class PermissionTypeEventHandler extends kDBEventHandler {
/**
* Cant delete system permissions
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnBeforeItemDelete(kEvent &$event)
+ protected function OnBeforeItemDelete(kEvent $event)
{
parent::OnBeforeItemDelete($event);
$object =& $event->getObject();
/* @var $object kDBItem */
if ( $object->GetDBField('IsSystem') ) {
// prevents deletion of this permission
$event->status = kEvent::erFAIL;
// informs main event, that redirect shouldn't be made
$event->MasterEvent->status = kEvent::erFAIL;
$this->Application->SetVar('cant_delete_system_permission', 1);
}
}
}
Index: branches/5.2.x/core/units/user_groups/user_groups_eh.php
===================================================================
--- branches/5.2.x/core/units/user_groups/user_groups_eh.php (revision 15129)
+++ branches/5.2.x/core/units/user_groups/user_groups_eh.php (revision 15130)
@@ -1,154 +1,154 @@
<?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 UserGroupsEventHandler extends kDBEventHandler {
/**
* Adds user as member for selected groups
*
* @param kEvent $event
*/
- function OnProcessSelected(&$event)
+ function OnProcessSelected($event)
{
if ($event->Prefix == 'u-ug') {
$new_groups = $this->Application->GetVar('g');
if (!$new_groups) {
return ;
}
$new_groups = array_keys($new_groups);
// don't insert duplicate group membership record
$user_id = $this->Application->GetVar('u_id');
$table_name = $this->Application->GetTempName(TABLE_PREFIX.'UserGroupRelations', 'prefix:u');
$sql = 'SELECT GroupId
FROM '.$table_name.'
WHERE PortalUserId = '.(int)$user_id;
$old_groups = $this->Conn->GetCol($sql);
$new_groups = array_diff($new_groups, $old_groups);
if ($new_groups) {
foreach ($new_groups as $new_group) {
$fields_hash = Array (
'GroupId' => $new_group,
'PortalUserId' => $user_id,
);
$this->Conn->doInsert($fields_hash, $table_name);
}
}
}
elseif ($event->Prefix == 'g-ug') {
$new_users = $this->Application->GetVar('u');
if (!$new_users) {
return ;
}
$new_users = array_keys($new_users);
// don't insert duplicate group membership record
$group_id = $this->Application->GetVar('g_id');
$table_name = $this->Application->GetTempName(TABLE_PREFIX.'UserGroupRelations', 'prefix:g');
$sql = 'SELECT PortalUserId
FROM ' . $table_name . '
WHERE GroupId = ' . (int)$group_id;
$old_users = $this->Conn->GetCol($sql);
$new_users = array_diff($new_users, $old_users);
if ($new_users) {
foreach ($new_users as $new_user) {
$fields_hash = Array (
'GroupId' => $group_id,
'PortalUserId' => $new_user,
);
$this->Conn->doInsert($fields_hash, $table_name);
}
}
}
$this->Application->StoreVar($this->Application->GetTopmostPrefix($event->Prefix).'_modified', '1', true); // true for optional
$event->SetRedirectParam('opener', 'u');
}
/**
* Sets primary group for user (in editing only)
*
* @param kEvent $event
*/
- function OnSetPrimary(&$event)
+ function OnSetPrimary($event)
{
$ids = $this->StoreSelectedIDs($event);
if ($ids) {
$user =& $this->Application->recallObject('u');
/* @var $user kDBItem */
$user->SetDBField('PrimaryGroupId', array_shift($ids));
$user->Update();
}
$this->clearSelectedIDs($event);
}
/**
* Don't allow primary group record deleting
*
* @param kEvent $event
* @param string $type
* @return void
* @access protected
*/
- protected function customProcessing(kEvent &$event, $type)
+ protected function customProcessing(kEvent $event, $type)
{
if ( $event->Name == 'OnMassDelete' && $type == 'before' ) {
$ids = $event->getEventParam('ids');
if ( $ids ) {
$object =& $event->getObject(Array ('skip_autoload' => true));
if ( $event->Prefix == 'u-ug' ) {
// allow deleting non-primary group of current user ($ids - groups)
$sql = 'SELECT PrimaryGroupId
FROM ' . $this->Application->GetTempName(TABLE_PREFIX . 'Users', 'prefix:u') . '
WHERE PortalUserId = ' . (int)$this->Application->GetVar('u_id');
$primary_group_id = (int)$this->Conn->GetOne($sql);
$index = array_search($primary_group_id, $ids);
if ( $index !== false ) {
unset($ids[$index]);
$event->setEventParam('ids', $ids);
}
}
elseif ( $event->Prefix == 'g-ug' ) {
// allow deleting users from group record, then it's not their primary group ($ids - users)
$group_id = (int)$this->Application->GetVar('g_id');
$sql = 'SELECT PortalUserId
FROM ' . TABLE_PREFIX . 'Users
WHERE PortalUserId IN (' . implode(',', $ids) . ') AND PrimaryGroupId = ' . $group_id;
$exclude_users = $this->Conn->GetCol($sql);
$event->setEventParam('ids', array_diff($ids, $exclude_users));
}
}
}
}
}
\ No newline at end of file
Index: branches/5.2.x/core/units/category_items/category_items_event_handler.php
===================================================================
--- branches/5.2.x/core/units/category_items/category_items_event_handler.php (revision 15129)
+++ branches/5.2.x/core/units/category_items/category_items_event_handler.php (revision 15130)
@@ -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 CategoryItemsEventHander extends kDBEventHandler
{
/**
* Setting language dependant navigation bar as calculated field
*
* @param kEvent $event
* @return void
* @access protected
* @see kDBEventHandler::OnListBuild()
*/
- protected function SetCustomQuery(kEvent &$event)
+ protected function SetCustomQuery(kEvent $event)
{
parent::SetCustomQuery($event);
$object =& $event->getObject();
/* @var $object kDBList */
$ml_formatter =& $this->Application->recallObject('kMultiLanguage');
/* @var $ml_formatter kMultiLanguage */
$object->addCalculatedField('CategoryName', 'c.' . $ml_formatter->LangFieldName('CachedNavbar'));
}
/**
* Set's new category as primary for product
*
* @param kEvent $event
*/
- function OnSetPrimary(&$event)
+ function OnSetPrimary($event)
{
$object =& $event->getObject(Array ('skip_autoload' => true));
/* @var $object kDBItem */
$ids = $this->StoreSelectedIDs($event);
if ( $ids ) {
$id = array_shift($ids);
$table_info = $object->getLinkedInfo();
$this->Conn->Query('UPDATE ' . $object->TableName . ' SET PrimaryCat = 0 WHERE ' . $table_info['ForeignKey'] . ' = ' . $table_info['ParentId']);
$this->Conn->Query('UPDATE ' . $object->TableName . ' SET PrimaryCat = 1 WHERE (' . $table_info['ForeignKey'] . ' = ' . $table_info['ParentId'] . ') AND (CategoryId = ' . $id . ')');
}
$event->SetRedirectParam('opener', 's');
}
/**
* Apply custom processing to item
*
* @param kEvent $event
* @param string $type
* @return void
* @access protected
*/
- protected function customProcessing(kEvent &$event, $type)
+ protected function customProcessing(kEvent $event, $type)
{
if ( $event->Name == 'OnMassDelete' ) {
$object =& $event->getObject();
$table_info = $object->getLinkedInfo();
switch ($type) {
case 'before':
$ids = $event->getEventParam('ids');
if ( $ids ) {
$sql = 'SELECT CategoryId
FROM ' . $object->TableName . '
WHERE (PrimaryCat = 0) AND (' . $table_info['ForeignKey'] . '=' . $table_info['ParentId'] . ') AND CategoryId IN (' . implode(',', $ids) . ')';
$event->setEventParam('ids', $this->Conn->GetCol($sql));
}
break;
// not needed because 'before' does not allow to delete primary cat!
/*case 'after':
// set 1st not deleted category as primary
$sql = 'SELECT COUNT(*)
FROM ' . $object->TableName . '
WHERE (PrimaryCat = 1) AND (' . $table_info['ForeignKey'] . ' = ' . $table_info['ParentId'] . ')';
$has_primary = $this->Conn->GetOne($sql);
if ( !$has_primary ) {
$sql = 'SELECT CategoryId
FROM ' . $object->TableName . '
WHERE ' . $table_info['ForeignKey'] . ' = ' . $table_info['ParentId'];
$cat_id = $this->Conn->GetOne($sql);
$sql = 'UPDATE ' . $object->TableName . '
SET PrimaryCat = 1
WHERE (' . $table_info['ForeignKey'] . ' = ' . $table_info['ParentId'] . ') AND (CategoryId = ' . $cat_id . ')';
$this->Conn->Query($sql);
}
break;*/
}
}
}
/**
* Removes primary mark from cloned category items record
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnAfterClone(kEvent &$event)
+ protected function OnAfterClone(kEvent $event)
{
parent::OnAfterClone($event);
$id = $event->getEventParam('id');
$table = $this->Application->getUnitOption($event->Prefix, 'TableName');
$id_field = $this->Application->getUnitOption($event->Prefix, 'IDField');
$sql = 'UPDATE %s
SET PrimaryCat = 0
WHERE %s = %s';
$this->Conn->Query(sprintf($sql, $table, $id_field, $id));
}
/**
* Deletes items of requested type from requested categories.
* In case if item is deleted from it's last category, then delete item too.
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnDeleteFromCategory(&$event)
+ protected function OnDeleteFromCategory($event)
{
$category_ids = $event->getEventParam('category_ids');
if ( !$category_ids ) {
return ;
}
$item_prefix = $event->getEventParam('item_prefix');
$item =& $this->Application->recallObject($item_prefix . '.-item', null, Array ('skip_autoload' => true));
/* @var $item kCatDBItem */
$ci_table = $this->Application->getUnitOption($event->Prefix, 'TableName');
$item_table = $this->Application->getUnitOption($item_prefix, 'TableName');
$sql = 'SELECT ItemResourceId, CategoryId
FROM %1$s
INNER JOIN %2$s ON (%1$s.ResourceId = %2$s.ItemResourceId)
WHERE CategoryId IN (%3$s)';
$category_items = $this->Conn->Query( sprintf($sql, $item_table, $ci_table, implode(',', $category_ids)) );
$item_hash = Array ();
foreach ($category_items as $ci_row) {
$item_hash[ $ci_row['ItemResourceId'] ][] = $ci_row['CategoryId'];
}
foreach ($item_hash as $item_resource_id => $delete_category_ids) {
$item->Load($item_resource_id, 'ResourceId');
$item->DeleteFromCategories($delete_category_ids);
}
}
}
\ No newline at end of file
Index: branches/5.2.x/core/units/groups/groups_event_handler.php
===================================================================
--- branches/5.2.x/core/units/groups/groups_event_handler.php (revision 15129)
+++ branches/5.2.x/core/units/groups/groups_event_handler.php (revision 15130)
@@ -1,70 +1,70 @@
<?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 GroupsEventHandler extends kDBEventHandler {
/**
* Adds grouping by user id
*
* @param kEvent $event
* @return void
* @access protected
* @see kDBEventHandler::OnListBuild()
*/
- protected function SetCustomQuery(kEvent &$event)
+ protected function SetCustomQuery(kEvent $event)
{
parent::SetCustomQuery($event);
$object =& $event->getObject();
/* @var $object kDBList */
switch ($event->Special) {
case 'user':
$user_id = $this->Application->GetVar('u_id');
if ( $user_id !== false ) {
// show only groups, that user doesn't belong to
$table_name = $this->Application->GetTempName(TABLE_PREFIX . 'UserGroupRelations', 'prefix:u');
$sql = 'SELECT GroupId
FROM ' . $table_name . '
WHERE PortalUserId = ' . (int)$user_id;
$group_ids = $this->Conn->GetCol($sql);
// add system groups
array_push($group_ids, $this->Application->ConfigValue('User_GuestGroup')); // Guest
array_push($group_ids, $this->Application->ConfigValue('User_LoggedInGroup')); // Everyone
$object->addFilter('already_member_filter', '%1$s.GroupId NOT IN (' . implode(',', $group_ids) . ')');
}
break;
}
}
/**
* Refreshes left tree on save
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnSave(kEvent &$event)
+ protected function OnSave(kEvent $event)
{
parent::OnSave($event);
$this->Application->StoreVar('refresh_tree', 1);
}
}
\ No newline at end of file
Index: branches/5.2.x/core/units/reviews/reviews_event_handler.php
===================================================================
--- branches/5.2.x/core/units/reviews/reviews_event_handler.php (revision 15129)
+++ branches/5.2.x/core/units/reviews/reviews_event_handler.php (revision 15130)
@@ -1,634 +1,634 @@
<?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 ReviewsEventHandler extends kDBEventHandler
{
/**
* Returns special of main item for linking with sub-item
*
* @param kEvent $event
* @return string
* @access protected
*/
- protected function getMainSpecial(kEvent &$event)
+ protected function getMainSpecial(kEvent $event)
{
if ( $event->Special == 'product' && !$this->Application->isAdmin ) {
// rev.product should auto-link
return '';
}
return parent::getMainSpecial($event);
}
/**
* Checks REVIEW/REVIEW.PENDING permission by main object primary category (not current category)
*
* @param kEvent $event
* @return bool
* @access public
*/
- public function CheckPermission(kEvent &$event)
+ public function CheckPermission(kEvent $event)
{
if ( $event->Name == 'OnAddReview' || $event->Name == 'OnCreate' ) {
$perm_helper =& $this->Application->recallObject('PermissionsHelper');
/* @var $perm_helper kPermissionsHelper */
$parent_prefix = $this->Application->getUnitOption($event->Prefix, 'ParentPrefix');
$main_object =& $this->Application->recallObject($parent_prefix);
/* @var $main_object kCatDBItem */
$perm_name = $this->getPermPrefix($event).'.REVIEW';
$res = $this->Application->CheckPermission($perm_name, 0, $main_object->GetDBField('CategoryId')) ||
$this->Application->CheckPermission($perm_name.'.PENDING', 0, $main_object->GetDBField('CategoryId'));
if ( !$res ) {
$event->status = kEvent::erPERM_FAIL;
}
return $res;
}
$check_events = Array (
'OnItemBuild', 'OnUpdate', /*'OnMassApprove', 'OnMassDecline'*/
);
$perm_category = $this->_getReviewCategory($event);
if ( in_array($event->Name, $check_events) ) {
// check for PRODUCT.VIEW permission
$perm_helper =& $this->Application->recallObject('PermissionsHelper');
/* @var $perm_helper kPermissionsHelper */
$perm_prefix = $this->getPermPrefix($event);
if ( $perm_category === false ) {
// no item id present -> allow
return true;
}
switch ($event->Name) {
case 'OnItemBuild':
$res = $this->Application->CheckPermission($perm_prefix . '.VIEW', 0, $perm_category);
break;
case 'OnUpdate':
case 'OnMassApprove':
case 'OnMassDecline':
$res = $this->Application->CheckPermission($perm_prefix . '.ADD', 0, $perm_category) ||
$this->Application->CheckPermission($perm_prefix . '.MODIFY', 0, $perm_category);
break;
default:
$res = false;
break;
}
if ( !$res ) {
$event->status = kEvent::erPERM_FAIL;
}
return $res;
}
return parent::CheckPermission($event);
}
/**
* Returns primary category of review's main item
*
* @param kEvent $event
* @return int
*/
- function _getReviewCategory(&$event)
+ function _getReviewCategory($event)
{
$items_info = $this->Application->GetVar($event->getPrefixSpecial());
if ($items_info) {
// rev:PresetFormFields is used to initialize new review creation
list ($review_id, ) = each($items_info);
}
else {
// when adding new review in admin
$review_id = false;
}
if (!$review_id) {
return false;
}
$object =& $event->getObject();
/* @var $object kDBItem */
// 1. get main item resource id (use object, because of temp tables in admin)
$sql = 'SELECT ItemId
FROM ' . $object->TableName . '
WHERE ' . $object->IDField . ' = ' . $review_id;
$resource_id = $this->Conn->GetOne($sql);
// 2. set main item id (for permission checks)
$parent_prefix = $this->Application->getUnitOption($event->Prefix, 'ParentPrefix');
$sql = 'SELECT ' . $this->Application->getUnitOption($parent_prefix, 'IDField') .'
FROM ' . $this->Application->getUnitOption($parent_prefix, 'TableName') .'
WHERE ResourceId = ' . $resource_id;
$this->Application->SetVar($parent_prefix . '_id', $this->Conn->GetOne($sql));
// 3. get main item category
$sql = 'SELECT CategoryId
FROM ' . $this->Application->getUnitOption('ci', 'TableName') .'
WHERE ItemResourceId = ' . $resource_id .' AND PrimaryCat = 1';
return $this->Conn->GetOne($sql);
}
/**
* Returns prefix for permissions
*
* @param kEvent $event
*/
- function getPermPrefix(&$event)
+ function getPermPrefix($event)
{
$main_prefix = $this->Application->GetTopmostPrefix($event->Prefix, true);
// this will return LINK for l, ARTICLE for n, TOPIC for bb, PRODUCT for p
return $this->Application->getUnitOption($main_prefix, 'PermItemPrefix');
}
/**
* Apply any custom changes to list's sql query
*
* @param kEvent $event
* @access protected
* @see OnListBuild
*/
- protected function SetCustomQuery(kEvent &$event)
+ protected function SetCustomQuery(kEvent $event)
{
parent::SetCustomQuery($event);
$object =& $event->getObject();
/* @var $object kDBList */
if ( !$this->Application->isAdminUser ) {
$object->addFilter('active', '%1$s.Status = ' . STATUS_ACTIVE);
}
switch ($event->Special) {
case 'showall':
$object->clearFilters();
break;
case 'item': // used ?
$object->clearFilters();
$parent_info = $object->getLinkedInfo();
$parent =& $this->Application->recallObject($parent_info['ParentPrefix']);
/* @var $parent kDBItem */
$object->addFilter('item_reviews', '%1$s.ItemId = ' . $parent->GetDBField('ResourceId'));
break;
case 'products': // used in In-Portal (Structure & Data -> Reviews section)
$object->removeFilter('parent_filter'); // this is important
$object->addFilter('product_reviews', 'pr.ResourceId IS NOT NULL');
break;
}
if ( preg_match('/(.*)-rev/', $event->Prefix, $regs) ) {
// "Structure & Data" -> "Reviews" (section in K4)
$item_type = $this->Application->getUnitOption($regs[1], 'ItemType');
$object->addFilter('itemtype_filter', '%1$s.ItemType = ' . $item_type);
if ( $this->Application->isAdmin ) {
// temporarily solution so we can see sub-items on separate grid in Admin
$object->removeFilter('parent_filter');
}
}
if ( $event->getEventParam('type') == 'current_user' ) {
$object->addFilter('current_user', '%1$s.CreatedById = ' . $this->Application->RecallVar('user_id'));
$object->addFilter('current_ip', '%1$s.IPAddress = "' . $_SERVER['REMOTE_ADDR'] . '"');
}
}
/**
* Adds review from front in case if user is logged in
*
* @param kEvent $event
*/
- function OnAddReview(&$event)
+ function OnAddReview($event)
{
$event->CallSubEvent('OnCreate');
}
/**
* Get new review status on user review permission
*
* @param kEvent $event
* @return int
*/
- function getReviewStatus(&$event)
+ function getReviewStatus($event)
{
$parent_prefix = $this->Application->getUnitOption($event->Prefix, 'ParentPrefix');
$main_object =& $this->Application->recallObject($parent_prefix);
/* @var $main_object kCatDBItem */
$ret = STATUS_DISABLED;
$perm_name = $this->getPermPrefix($event).'.REVIEW';
if ($this->Application->CheckPermission($perm_name, 0, $main_object->GetDBField('CategoryId'))) {
$ret = STATUS_ACTIVE;
}
else if ($this->Application->CheckPermission($perm_name.'.PENDING', 0, $main_object->GetDBField('CategoryId'))) {
$ret = STATUS_PENDING;
}
return $ret;
}
/**
* Prefills all fields on front-end
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnBeforeItemCreate(kEvent &$event)
+ protected function OnBeforeItemCreate(kEvent $event)
{
parent::OnBeforeItemCreate($event);
$object =& $event->getObject();
/* @var $object kDBItem */
$parent_info = $object->getLinkedInfo();
$item_type = $this->Application->getUnitOption($parent_info['ParentPrefix'], 'ItemType');
$object->SetDBField('IPAddress', $_SERVER['REMOTE_ADDR']);
$object->SetDBField('ItemType', $item_type);
$object->SetDBField('Module', $this->Application->findModule('Var', $parent_info['ParentPrefix'], 'Name'));
if ( $this->Application->isAdminUser ) {
// don't perform spam control on admin
return ;
}
$spam_helper =& $this->Application->recallObject('SpamHelper');
/* @var $spam_helper SpamHelper */
$spam_helper->InitHelper($parent_info['ParentId'], 'Review', 0);
if ( $spam_helper->InSpamControl() ) {
$event->status = kEvent::erFAIL;
$object->SetError('ReviewText', 'too_frequent', 'lu_ferror_review_duplicate');
return;
}
$rating = $object->GetDBField('Rating');
if ( $rating < 1 || $rating > 5 ) {
$object->SetDBField('Rating', null);
}
$object->SetDBField('ItemId', $parent_info['ParentId']); // ResourceId
$object->SetDBField('CreatedById', $this->Application->RecallVar('user_id'));
$object->SetDBField('Status', $this->getReviewStatus($event));
$object->SetDBField('TextFormat', 0); // set plain text format directly
}
/**
* Sets correct rating value
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnBeforeItemUpdate(kEvent &$event)
+ protected function OnBeforeItemUpdate(kEvent $event)
{
parent::OnBeforeItemUpdate($event);
$object =& $event->getObject();
/* @var $object kDBItem */
$rating = $object->GetDBField('Rating');
if ( !$rating ) {
$object->SetDBField('Rating', null);
}
}
/**
* Updates item review counter
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnAfterItemCreate(kEvent &$event)
+ protected function OnAfterItemCreate(kEvent $event)
{
parent::OnAfterItemCreate($event);
$this->updateSubitemCounters($event);
if ( !$this->Application->isAdminUser ) {
$spam_helper =& $this->Application->recallObject('SpamHelper');
/* @var $spam_helper SpamHelper */
$object =& $event->getObject();
/* @var $object kDBItem */
$parent_info = $object->getLinkedInfo();
$config_mapping = $this->Application->getUnitOption($event->Prefix, 'ConfigMapping');
$review_settings = $config_mapping['ReviewDelayValue'] . ':' . $config_mapping['ReviewDelayInterval'];
$spam_helper->InitHelper($parent_info['ParentId'], 'Review', $review_settings);
$spam_helper->AddToSpamControl();
$review_status = $object->GetDBField('Status');
if ( $review_status == STATUS_ACTIVE || $review_status == STATUS_PENDING ) {
$email_event = $this->getPermPrefix($event) . '.REVIEW.' . ($review_status == STATUS_ACTIVE ? 'ADD' : 'ADD.PENDING');
$this->Application->EmailEventUser($email_event, $object->GetDBField('CreatedById'));
$this->Application->EmailEventAdmin($email_event);
}
}
}
/**
* Updates item review counter
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnAfterItemUpdate(kEvent &$event)
+ protected function OnAfterItemUpdate(kEvent $event)
{
parent::OnAfterItemUpdate($event);
$this->updateSubitemCounters($event);
$object =& $event->getObject();
/* @var $object kDBItem */
if ( $this->Application->isAdminUser && !$object->IsTempTable() ) {
// send email on review status change from reviews grid in admin
$review_status = $object->GetDBField('Status');
$process_status = Array (STATUS_ACTIVE, STATUS_DISABLED);
if ( ($review_status != $object->GetOriginalField('Status')) && in_array($review_status, $process_status) ) {
$this->_loadMainObject($event);
$email_event = $this->getPermPrefix($event) . '.REVIEW.' . ($review_status == STATUS_ACTIVE ? 'APPROVE' : 'DENY');
$this->Application->EmailEventUser($email_event, $object->GetDBField('CreatedById'));
}
}
}
/**
* Loads main object of review (link, article, etc.)
*
* @param kEvent $event
* @return kCatDBItem
*/
- function _loadMainObject(&$event)
+ function _loadMainObject($event)
{
$object =& $event->getObject();
/* @var $object kDBItem */
$parent_prefix = $this->Application->getUnitOption($event->Prefix, 'ParentPrefix');
$parent_table_key = $this->Application->getUnitOption($event->Prefix, 'ParentTableKey');
$foreign_key = $this->Application->getUnitOption($event->Prefix, 'ForeignKey');
$main_object =& $this->Application->recallObject($parent_prefix, null, Array ('skip_autoload' => true));
/* @var $main_object kDBItem */
$main_object->Load($object->GetDBField($foreign_key), $parent_table_key);
}
/**
* Updates total review counter, cached rating, votes count
*
* @param kEvent $event
*/
- function updateSubitemCounters(&$event)
+ function updateSubitemCounters($event)
{
if ( $event->Special == '-item' ) {
// ignore Main Item Copy/Pasting and Deleting
return;
}
$object =& $event->getObject();
/* @var $object kDBItem */
$parent_prefix = $this->Application->getUnitOption($event->Prefix, 'ParentPrefix');
$parent_table = $this->Application->getUnitOption($parent_prefix, 'TableName');
if ( $object->IsTempTable() ) {
$parent_table = $this->Application->GetTempName($parent_table, 'prefix:' . $object->Prefix);
}
$fields_hash = Array ('CachedReviewsQty' => 0, 'CachedRating' => 0, 'CachedVotesQty' => 0);
// 1. update review counter
$sql = 'SELECT COUNT(ReviewId)
FROM ' . $object->TableName . '
WHERE ItemId = ' . $object->GetDBField('ItemId');
$fields_hash['CachedReviewsQty'] = $this->Conn->GetOne($sql);
// 2. update votes counter + rating
$rating = $object->GetDBField('Rating');
$sql = 'SELECT CachedRating, CachedVotesQty
FROM ' . $parent_table . '
WHERE ResourceId = ' . $object->GetDBField('ItemId');
$parent_data = $this->Conn->GetRow($sql);
$avg_rating = $parent_data['CachedRating'];
$votes_count = $parent_data['CachedVotesQty'];
switch ($event->Name) {
case 'OnAfterItemCreate': // adding new review with rating
$this->changeRating($avg_rating, $votes_count, $rating, '+');
break;
case 'OnAfterItemDelete':
$this->changeRating($avg_rating, $votes_count, $rating, '-');
break;
case 'OnAfterItemUpdate':
$this->changeRating($avg_rating, $votes_count, $object->GetOriginalField('Rating'), '-');
$this->changeRating($avg_rating, $votes_count, $rating, '+');
break;
}
$fields_hash['CachedRating'] = "$avg_rating";
$fields_hash['CachedVotesQty'] = $votes_count;
$this->Conn->doUpdate($fields_hash, $parent_table, 'ResourceId = ' . $object->GetDBField('ItemId'));
}
/**
* Changes average rating and votes count based on requested operation
*
* @param float $avg_rating average rating before new vote
* @param int $votes_count votes count before new vote
* @param int $rating new vote (from 1 to 5)
* @param string $operation requested operation (+ / -)
*/
function changeRating(&$avg_rating, &$votes_count, $rating, $operation)
{
if ( $rating < 1 || $rating > 5 ) {
return;
}
if ( $operation == '+' ) {
$avg_rating = (($avg_rating * $votes_count) + $rating) / ($votes_count + 1);
++$votes_count;
}
else {
if ( $votes_count > 1 ) { // escape division by 0
$avg_rating = (($avg_rating * $votes_count) - $rating) / ($votes_count - 1);
}
else {
$avg_rating = (($avg_rating * $votes_count) - $rating) / 1;
}
--$votes_count;
}
}
/**
* Updates main item cached review counter
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnAfterItemDelete(kEvent &$event)
+ protected function OnAfterItemDelete(kEvent $event)
{
parent::OnAfterItemDelete($event);
$this->updateSubitemCounters($event);
}
/**
* Creates review & redirect to confirmation template
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnCreate(kEvent &$event)
+ protected function OnCreate(kEvent $event)
{
parent::OnCreate($event);
if ( $event->status != kEvent::erSUCCESS || $this->Application->isAdmin ) {
return;
}
$object =& $event->getObject();
/* @var $object kDBItem */
if ( $this->Application->GetVar('ajax') == 'yes' ) {
$ajax_form_helper =& $this->Application->recallObject('AjaxFormHelper');
/* @var $ajax_form_helper AjaxFormHelper */
$params = Array ('status' => 'OK');
if ( $event->status != kEvent::erSUCCESS ) {
$ajax_form_helper->prepareJSONErrors($event, $params);
}
// let FormManager decide what template to show
$params['review_status'] = $object->GetDBField('Status');
$ajax_form_helper->sendResponse($event, $params);
}
else {
$event->SetRedirectParam('opener', 's');
$next_template = $object->GetDBField('Status') == STATUS_ACTIVE ? 'success_template' : 'success_pending_template';
$event->redirect = $this->Application->GetVar($next_template);
$parent_prefix = $this->Application->getUnitOption($event->Prefix, 'ParentPrefix');
$event->SetRedirectParam('pass', 'm,'.$parent_prefix);
}
}
/**
* Makes left join to item's table, when in separate grid
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnAfterConfigRead(kEvent &$event)
+ protected function OnAfterConfigRead(kEvent $event)
{
parent::OnAfterConfigRead($event);
if (preg_match('/(.*)-rev/', $event->Prefix, $regs) && $this->Application->prefixRegistred($regs[1])) {
// "Structure & Data" -> "Reviews" (section in K4)
// 1. add join to items table (for "Structure & Data" -> "Reviews" section)
$item_table = $this->Application->getUnitOption($regs[1], 'TableName');
$ci_table = $this->Application->getUnitOption('ci', 'TableName');
$list_sqls = $this->Application->getUnitOption($event->Prefix, 'ListSQLs');
$list_sqls[''] .= ' LEFT JOIN '.$item_table.' item_table ON item_table.ResourceId = %1$s.ItemId';
$list_sqls[''] .= ' LEFT JOIN '.$ci_table.' ci ON item_table.ResourceId = ci.ItemResourceId AND ci.PrimaryCat = 1';
$this->Application->setUnitOption($event->Prefix, 'ListSQLs', $list_sqls);
// 2. add calculated field
$calculated_fields = $this->Application->getUnitOption($event->Prefix, 'CalculatedFields');
$calculated_fields['']['CatalogItemName'] = 'item_table.' . $this->getTitleField($regs[1]);
$calculated_fields['']['CatalogItemId'] = 'item_table.' . $this->Application->getUnitOption($regs[1], 'IDField');
$calculated_fields['']['CatalogItemCategory'] = 'ci.CategoryId';
$this->Application->setUnitOption($event->Prefix, 'CalculatedFields', $calculated_fields);
}
}
/**
* Convert TitleField field of kMultiLanguage formatter used for it
*
* @param string $prefix
* @return string
*/
function getTitleField($prefix)
{
$lang_prefix = 'l'.$this->Application->GetVar('m_lang').'_';
$title_field = $this->Application->getUnitOption($prefix, 'TitleField');
$field_options = $this->Application->getUnitOption($prefix.'.'.$title_field, 'Fields');
$formatter_class = isset($field_options['formatter']) ? $field_options['formatter'] : '';
if ($formatter_class == 'kMultiLanguage' && !isset($field_options['master_field'])) {
$title_field = $lang_prefix.$title_field;
}
return $title_field;
}
/**
* Set's new perpage for Category Item Reviews (used on Front-end)
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnSetPerPage(kEvent &$event)
+ protected function OnSetPerPage(kEvent $event)
{
parent::OnSetPerPage($event);
$parent_prefix = $event->Application->getUnitOption($event->Prefix, 'ParentPrefix');
$event->SetRedirectParam('pass', 'm,' . $event->getPrefixSpecial() . ',' . $parent_prefix);
}
}
\ No newline at end of file
Index: branches/5.2.x/core/units/forms/form_submissions/form_submissions_eh.php
===================================================================
--- branches/5.2.x/core/units/forms/form_submissions/form_submissions_eh.php (revision 15129)
+++ branches/5.2.x/core/units/forms/form_submissions/form_submissions_eh.php (revision 15130)
@@ -1,552 +1,552 @@
<?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 FormSubmissionsEventHandler extends kDBEventHandler {
/**
* Checks user permission to execute given $event
*
* @param kEvent $event
* @return bool
* @access public
*/
- public function CheckPermission(kEvent &$event)
+ public function CheckPermission(kEvent $event)
{
if ( !$this->Application->isAdmin ) {
if ( $event->Name == 'OnCreate' ) {
// anybody can submit forms on front
return true;
}
}
$section = $event->getSection();
$form_id = $this->Application->GetVar('form_id');
$event->setEventParam('PermSection', $section . ':' . $form_id);
return parent::CheckPermission($event);
}
/**
* Always allow to view feedback form
*
* @return void
* @access protected
* @see kEventHandler::$permMapping
*/
protected function mapPermissions()
{
parent::mapPermissions();
$permissions = Array (
'OnItemBuild' => Array ('self' => true),
'OnEdit' => Array ('self' => 'view', 'subitem' => 'view'),
);
$this->permMapping = array_merge($this->permMapping, $permissions);
}
/**
* Returns filter block based on field element type
*
* @param string $element_type
* @return string
*/
function _getFilterBlock($element_type)
{
$mapping = Array (
'text' => 'grid_like_filter',
'select' => 'grid_options_filter',
'radio' => 'grid_options_filter',
'checkbox' => 'grid_options_filter',
'password' => 'grid_like_filter',
'textarea' => 'grid_like_filter',
'label' => 'grid_like_filter',
'upload' => 'grid_empty_filter',
);
return $mapping[$element_type];
}
- function OnBuildFormFields(&$event)
+ function OnBuildFormFields($event)
{
$form_id = $this->Application->GetVar('form_id');
if (!$form_id) return ;
$conf_fields = $this->Application->getUnitOption($event->Prefix, 'Fields');
$conf_grids = $this->Application->getUnitOption($event->Prefix, 'Grids');
$helper =& $this->Application->recallObject('InpCustomFieldsHelper');
/* @var $helper InpCustomFieldsHelper */
$sql = 'SELECT *
FROM ' . TABLE_PREFIX . 'FormFields
WHERE FormId = ' . (int)$form_id . '
ORDER BY Priority DESC';
$fields = $this->Conn->Query($sql, 'FormFieldId');
$use_options = Array ('radio', 'select', 'checkbox');
$check_visibility = $this->Application->LoggedIn() && !$this->Application->isAdminUser;
foreach ($fields as $field_id => $options) {
$field_visible = $check_visibility ? $options['Visibility'] == SubmissionFormField::VISIBILITY_EVERYONE : true;
$field_options = Array('type' => 'string', 'default' => $options['DefaultValue']);
if ($options['Required'] && $field_visible) {
$field_options['required'] = 1;
}
if ($options['Validation'] == 1) {
$field_options['formatter'] = 'kFormatter';
$field_options['regexp'] = '/^(' . REGEX_EMAIL_USER . '@' . REGEX_EMAIL_DOMAIN . ')$/i';
}
if ($options['DisplayInGrid']) {
$title = $options['Prompt'];
if (substr($title, 0, 1) == '+') {
$this->Application->Phrases->AddCachedPhrase('form_col_title' . $field_id, substr($title, 1));
$title = 'form_col_title' . $field_id;
}
$conf_grids['Default']['Fields']['fld_' . $field_id] = Array (
'title' => $title, 'no_special' => 1, 'nl2br' => 1, 'first_chars' => 200,
'filter_block' => $this->_getFilterBlock($options['ElementType'])
);
if ($options['ElementType'] == 'upload') {
$conf_grids['Default']['Fields']['fld_' . $field_id]['data_block'] = 'grid_upload_td';
}
if ($options['Validation'] == 1) {
$conf_grids['Default']['Fields']['fld_' . $field_id]['data_block'] = 'grid_email_td';
}
}
if ($options['ElementType'] == 'checkbox' && !$options['ValueList']) {
// fix case, when user haven't defined any options for checkbox
$options['ValueList'] = '1=la_Yes||0=la_No';
}
if (in_array($options['ElementType'], $use_options) && $options['ValueList']) {
// field type can have options and user have defined them too
$field_options['options'] = $helper->GetValuesHash( $options['ValueList'] );
$field_options['formatter'] = 'kOptionsFormatter';
}
if ($options['ElementType'] == 'password') {
$field_options['formatter'] = 'kPasswordFormatter';
$field_options['encryption_method'] = 'plain';
$field_options['verify_field'] = 'fld_' . $field_id . '_verify';
}
if ($options['ElementType'] == 'upload') {
$field_options['formatter'] = 'kUploadFormatter';
$field_options['upload_dir'] = WRITEBALE_BASE . DIRECTORY_SEPARATOR . 'user_files' . DIRECTORY_SEPARATOR . 'form_submissions';
if ( $options['UploadMaxSize'] ) {
$field_options['max_size'] = $options['UploadMaxSize'] * 1024; // convert Kbytes to bytes
}
if ( $options['UploadExtensions'] ) {
$field_options['file_types'] = '*.' . implode(';*.', explode(',', $options['UploadExtensions']));
}
}
$conf_fields['fld_' . $field_id] = $field_options;
}
$this->Application->setUnitOption($event->Prefix, 'Fields', $conf_fields);
$this->Application->setUnitOption($event->Prefix, 'Grids', $conf_grids);
}
/**
* Apply any custom changes to list's sql query
*
* @param kEvent $event
* @return void
* @access protected
* @see kDBEventHandler::OnListBuild()
*/
- protected function SetCustomQuery(kEvent &$event)
+ protected function SetCustomQuery(kEvent $event)
{
parent::SetCustomQuery($event);
$object =& $event->getObject();
/* @var $object kDBList */
$object->addFilter('form_filter', '%1$s.FormId = ' . (int)$this->Application->GetVar('form_id'));
}
/**
* Allows user to see it's last feedback form data
*
* @param kEvent $event
* @return int
* @access public
*/
- public function getPassedID(kEvent &$event)
+ public function getPassedID(kEvent $event)
{
if ( $event->Special == 'last' ) {
// allow user to see his last submitted form
return $this->Application->RecallVar('last_submission_id');
}
if ( $this->Application->isAdminUser ) {
// don't check ids in admin
return parent::getPassedID($event);
}
// no way to see other user's form submission by giving it's ID directly in url
return 0;
}
/**
* Creates new form submission from Front-End
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnCreate(kEvent &$event)
+ protected function OnCreate(kEvent $event)
{
parent::OnCreate($event);
if ( $event->status != kEvent::erSUCCESS ) {
return;
}
$object =& $event->getObject();
/* @var $object kDBItem */
// allows user to view only it's last submission
$this->Application->StoreVar('last_submission_id', $object->GetID());
$form_submission_helper =& $this->Application->recallObject('FormSubmissionHelper');
/* @var $form_submission_helper FormSubmissionHelper */
$form =& $form_submission_helper->getForm($object);
$notify_email = $form->GetDBField('SubmitNotifyEmail');
if ( $notify_email ) {
$send_params = Array (
'to_name' => $notify_email,
'to_email' => $notify_email,
);
$this->Application->EmailEventAdmin('FORM.SUBMITTED', null, $send_params);
}
else {
$this->Application->EmailEventAdmin('FORM.SUBMITTED');
}
// $this->Application->EmailEventUser('FORM.SUBMITTED', null, 'to_email' => '');
$event->SetRedirectParam('opener', 's');
$event->SetRedirectParam('m_cat_id', 0);
$theme =& $this->Application->recallObject('theme.current');
/* @var $theme kDBItem */
$template = kUtil::unhtmlentities($this->Application->GetVar('success_template')); // kHTTPQuery do htmlspecialchars on everything
$alias_template = $theme->GetField('TemplateAliases', $template);
$event->redirect = $alias_template ? $alias_template : $template;
}
/**
* Processes Captcha code
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnBeforeItemCreate(kEvent &$event)
+ protected function OnBeforeItemCreate(kEvent $event)
{
parent::OnBeforeItemCreate($event);
$object =& $event->getObject();
/* @var $object kDBItem */
$object->SetDBField('IPAddress', $_SERVER['REMOTE_ADDR']);
if ( !$object->GetDBField('ReferrerURL') ) {
$referrer = $this->Application->GetVar('original_referrer');
if ( !$referrer ) {
$base_url = preg_quote($this->Application->BaseURL(), '/');
$referrer = preg_replace('/^' . $base_url . '/', '/', $_SERVER['HTTP_REFERER'], 1);
}
$object->SetDBField('ReferrerURL', $referrer);
}
$form_submission_helper =& $this->Application->recallObject('FormSubmissionHelper');
/* @var $form_submission_helper FormSubmissionHelper */
$form =& $form_submission_helper->getForm($object);
// validate captcha code
if ( $form->GetDBField('UseSecurityImage') && !$this->Application->LoggedIn() ) {
$captcha_helper =& $this->Application->recallObject('CaptchaHelper');
/* @var $captcha_helper kCaptchaHelper */
$captcha_helper->validateCode($event, false);
}
}
/**
* Checks, that target submission was selected for merging
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnBeforeItemUpdate(kEvent &$event)
+ protected function OnBeforeItemUpdate(kEvent $event)
{
parent::OnBeforeItemUpdate($event);
$object =& $event->getObject();
/* @var $object kDBItem */
$object->setRequired('MergeToSubmission', $object->GetDBField('IsMergeToSubmission'));
}
/**
* Passes form_id, when using "Prev"/"Next" toolbar buttons
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnPreSaveAndGo(kEvent &$event)
+ protected function OnPreSaveAndGo(kEvent $event)
{
parent::OnPreSaveAndGo($event);
if ( $event->status == kEvent::erSUCCESS ) {
$event->SetRedirectParam('pass', 'm,form,formsubs');
}
}
/**
* Saves edited item in temp table and goes
* to passed tabs, by redirecting to it with OnPreSave event
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnPreSaveAndGoToTab(kEvent &$event)
+ protected function OnPreSaveAndGoToTab(kEvent $event)
{
parent::OnPreSaveAndGoToTab($event);
if ( $event->status == kEvent::erSUCCESS ) {
$event->SetRedirectParam('pass', 'm,form,formsubs');
}
}
/**
* Set's new per-page for grid
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnSetPerPage(kEvent &$event)
+ protected function OnSetPerPage(kEvent $event)
{
parent::OnSetPerPage($event);
$event->SetRedirectParam('pass', 'm,form,' . $event->getPrefixSpecial());
}
/**
* Occurs when page is changed (only for hooking)
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnSetPage(kEvent &$event)
+ protected function OnSetPage(kEvent $event)
{
parent::OnSetPage($event);
$event->SetRedirectParam('pass', 'm,form,' . $event->getPrefixSpecial());
}
/**
* Fills merge-to dropdown
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnAfterItemLoad(kEvent &$event)
+ protected function OnAfterItemLoad(kEvent $event)
{
parent::OnAfterItemLoad($event);
if ($event->Special == 'merge-to') {
return ;
}
$object =& $event->getObject();
/* @var $object kDBItem */
$form_id = $object->GetDBField('FormId');
$email_field = $this->getFieldByRole($form_id, SubmissionFormField::COMMUNICATION_ROLE_EMAIL);
if (!$email_field) {
return ;
}
$merge_to =& $this->Application->recallObject($event->Prefix . '.merge-to', null, Array ('skip_autoload' => true));
/* @var $merge_to kDBItem */
$sql = $merge_to->GetSelectSQL() . ' WHERE (FormId = ' . $form_id . ') AND (' . $email_field . ' = ' . $this->Conn->qstr( $object->GetDBField($email_field) ) . ')';
$submissions = $this->Conn->Query($sql, $object->IDField);
// remove this submission
unset($submissions[ $object->GetID() ]);
if (!$submissions) {
return ;
}
$options = Array ();
$name_field = $this->getFieldByRole($form_id, SubmissionFormField::COMMUNICATION_ROLE_NAME);
$subject_field = $this->getFieldByRole($form_id, SubmissionFormField::COMMUNICATION_ROLE_SUBJECT);
$language =& $this->Application->recallObject('lang.current');
/* @var $language kDBItem */
$date_format = $language->GetDBField('DateFormat');
foreach ($submissions as $submission_id => $submission_data) {
$option_title = ''; // SenderName (email@address.com) - Subject (06/29/2010)
$merge_to->LoadFromHash($submission_data);
if ($name_field) {
$option_title = $merge_to->GetDBField($name_field) . ' (' . $merge_to->GetDBField($email_field) . ') - ';
}
else {
$option_title = $merge_to->GetDBField($email_field) . ' - ';
}
if ($subject_field) {
$option_title .= $merge_to->GetField($subject_field) . ' (' . $merge_to->GetField('SubmissionTime', $date_format) . ')';
}
else {
$option_title .= $merge_to->GetField('SubmissionTime', $date_format);
}
$options[$submission_id] = $option_title;
}
$object->SetFieldOption('MergeToSubmission', 'options', $options);
}
/**
* Returns submission field name based on given role
*
* @param int $form_id
* @param string $role
* @return string
*/
function getFieldByRole($form_id, $role)
{
static $cache = Array ();
if (!array_key_exists($form_id, $cache)) {
$id_field = $this->Application->getUnitOption('formflds', 'IDField');
$table_name = $this->Application->getUnitOption('formflds', 'TableName');
$sql = 'SELECT ' . $id_field . ', EmailCommunicationRole
FROM ' . $table_name . '
WHERE FormId = ' . $form_id . ' AND EmailCommunicationRole <> 0';
$cache[$form_id] = $this->Conn->GetCol($sql, 'EmailCommunicationRole');
}
// get field name by role
return array_key_exists($role, $cache[$form_id]) ? 'fld_' . $cache[$form_id][$role] : false;
}
/**
* Performs submission merge
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnUpdate(kEvent &$event)
+ protected function OnUpdate(kEvent $event)
{
parent::OnUpdate($event);
if ($event->status == kEvent::erSUCCESS) {
$object =& $event->getObject();
/* @var $object kDBItem */
$merge_to = $object->GetDBField('MergeToSubmission');
if (!$merge_to) {
return ;
}
$form_id = $object->GetDBField('FormId');
$sql = 'SELECT *
FROM ' . TABLE_PREFIX . 'Forms
WHERE FormId = ' . $form_id;
$form_info = $this->Conn->GetRow($sql);
$reply =& $this->Application->recallObject('submission-log.merge', null, Array ('skip_autoload' => true));
/* @var $reply kDBItem */
$email_field = $this->getFieldByRole($form_id, SubmissionFormField::COMMUNICATION_ROLE_EMAIL);
$subject_field = $this->getFieldByRole($form_id, SubmissionFormField::COMMUNICATION_ROLE_SUBJECT);
$body_field = $this->getFieldByRole($form_id, SubmissionFormField::COMMUNICATION_ROLE_BODY);
$reply->SetDBField('FormSubmissionId', $merge_to);
if ($email_field) {
$reply->SetDBField('FromEmail', $object->GetDBField($email_field));
}
$reply->SetDBField('ToEmail', $form_info['ReplyFromEmail']);
if ($subject_field) {
$reply->SetDBField('Subject', $object->GetDBField($subject_field));
}
if ($body_field) {
$reply->SetDBField('Message', $object->GetDBField($body_field));
}
$reply->SetDBField('SentOn_date', $object->GetDBField('SubmissionTime'));
$reply->SetDBField('SentOn_time', $object->GetDBField('SubmissionTime'));
$reply->SetDBField('MessageId', $object->GetDBField('MessageId'));
$reply->SetDBField('SentStatus', SUBMISSION_LOG_SENT);
// as if emails was really received via mailbox
$this->Application->SetVar('client_mode', 1);
if ($reply->Create()) {
// delete submission, since it was merged
$object->Delete();
}
}
}
}
\ No newline at end of file
Index: branches/5.2.x/core/units/forms/drafts/draft_eh.php
===================================================================
--- branches/5.2.x/core/units/forms/drafts/draft_eh.php (revision 15129)
+++ branches/5.2.x/core/units/forms/drafts/draft_eh.php (revision 15130)
@@ -1,59 +1,59 @@
<?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 DraftEventHandler extends kDBEventHandler
{
/**
* Sets user, who created draft
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnBeforeItemCreate(kEvent &$event)
+ protected function OnBeforeItemCreate(kEvent $event)
{
parent::OnBeforeItemCreate($event);
$object =& $event->getObject();
/* @var $object kDBItem */
$user_id = $this->Application->RecallVar('user_id');
$object->SetDBField('CreatedById', $user_id);
}
/**
* Allows to load draft, that best matches given form submission
*
* @param kEvent $event
* @return int
* @access public
*/
- public function getPassedID(kEvent &$event)
+ public function getPassedID(kEvent $event)
{
if ( $event->Special == 'related' ) {
$form_submission =& $this->Application->recallObject('formsubs');
/* @var $form_submission kDBItem */
return Array (
'FormSubmissionId' => $form_submission->GetID(),
'CreatedById' => $this->Application->RecallVar('user_id'),
);
}
return parent::getPassedID($event);
}
}
\ 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 15129)
+++ branches/5.2.x/core/units/forms/forms/forms_eh.php (revision 15130)
@@ -1,627 +1,626 @@
<?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 standard permission mapping
*
* @return void
* @access protected
* @see kEventHandler::$permMapping
*/
protected 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)
+ 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(kEvent &$event)
+ protected function OnSave(kEvent $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(kEvent &$event)
+ protected function OnMassDelete(kEvent $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->HandleEvent(new kEvent('adm:OnResetSections'));
$this->Application->StoreVar('RefreshStructureTree', 1);
}
/**
* Dynamically fills custom data config
*
* @param kEvent $event
*/
- function OnCreateFormFields(&$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)
+ 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, $this->getRequestProtectedFields($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));
+ $this->Application->HandleEvent(new kEvent('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(kEvent &$event)
+ protected function OnBeforeItemCreate(kEvent $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(kEvent &$event)
+ protected function OnBeforeItemUpdate(kEvent $event)
{
parent::OnBeforeItemUpdate($event);
$this->itemChanged($event);
}
/**
* Occurs before item is changed
*
* @param kEvent $event
*/
- function itemChanged(&$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)
+ 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)
+ 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)
+ 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)
+ function OnProcessReplies($event)
{
$this->_processMailbox($event, false);
}
/**
* Queries pop3 server about new incoming mail
*
* @param kEvent $event
*/
- function OnProcessBouncedReplies(&$event)
+ function OnProcessBouncedReplies($event)
{
$this->_processMailbox($event, true);
}
/**
* Queries pop3 server about new incoming mail
*
* @param kEvent $event
* @param bool $bounce_mode
*/
- function _processMailbox(&$event, $bounce_mode = false)
+ 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/forms/form_fields/form_field_eh.php
===================================================================
--- branches/5.2.x/core/units/forms/form_fields/form_field_eh.php (revision 15129)
+++ branches/5.2.x/core/units/forms/form_fields/form_field_eh.php (revision 15130)
@@ -1,52 +1,52 @@
<?php
/**
* @version $Id$
* @package In-Portal
* @copyright Copyright (C) 1997 - 2010 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 FormFieldEventHandler extends kDBEventHandler {
/**
* Returns form field visibility filter
*
* @return string
*/
function getVisiblilityFilter()
{
if ($this->Application->LoggedIn() && !$this->Application->isAdminUser) {
return '%1$s.Visibility = ' . SubmissionFormField::VISIBILITY_EVERYONE;
}
return '';
}
/**
* Shows fields based on user logged-in status
*
* @param kEvent $event
* @return void
* @access protected
* @see kDBEventHandler::OnListBuild()
*/
- protected function SetCustomQuery(kEvent &$event)
+ protected function SetCustomQuery(kEvent $event)
{
parent::SetCustomQuery($event);
$object =& $event->getObject();
/* @var $object kDBList */
$visibility_filter = $this->getVisiblilityFilter();
$object->addFilter('visibility_filter', $visibility_filter);
}
}
Index: branches/5.2.x/core/units/forms/submission_log/submission_log_eh.php
===================================================================
--- branches/5.2.x/core/units/forms/submission_log/submission_log_eh.php (revision 15129)
+++ branches/5.2.x/core/units/forms/submission_log/submission_log_eh.php (revision 15130)
@@ -1,710 +1,710 @@
<?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 SubmissionLogEventHandler extends kDBEventHandler {
/**
* Allows to override standard permission mapping
*
* @return void
* @access protected
* @see kEventHandler::$permMapping
*/
protected function mapPermissions()
{
parent::mapPermissions();
$permissions = Array (
'OnResendReply' => Array ('subitem' => 'add|edit'),
'OnSaveDraft' => Array ('subitem' => 'add|edit'),
'OnUseDraft' => Array ('subitem' => 'add|edit'),
'OnDeleteDraft' => Array ('subitem' => 'add|edit'),
'OnProcessBounceMail' => 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(kEvent &$event)
+ public function CheckPermission(kEvent $event)
{
$section = $event->getSection();
$form_id = $this->Application->GetVar('form_id');
if ( $form_id ) {
// copy form_id to env to be passed info upload links
$this->Application->SetVar($event->getPrefixSpecial() . '_form_id', $form_id);
}
else {
$form_id = $this->Application->GetVar($event->getPrefixSpecial() . '_form_id');
}
$event->setEventParam('PermSection', $section . ':' . $form_id);
return parent::CheckPermission($event);
}
/**
* Prepares new kDBItem object
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnNew(kEvent &$event)
+ protected function OnNew(kEvent $event)
{
parent::OnNew($event);
$object =& $event->getObject();
/* @var $object kDBItem */
$form_submission =& $this->Application->recallObject('formsubs');
/* @var $form_submission kDBItem */
$form_submission_helper =& $this->Application->recallObject('FormSubmissionHelper');
/* @var $form_submission_helper FormSubmissionHelper */
$form =& $form_submission_helper->getForm($form_submission);
/* @var $form kDBItem */
$from_email = $form->GetDBField('ReplyFromEmail');
$to_email = $form_submission_helper->getFieldByRole($form_submission, SubmissionFormField::COMMUNICATION_ROLE_EMAIL);
if ( $this->Application->GetVar('client_mode') ) {
// debug code for sending email from client
$object->SetDBField('FromEmail', $to_email);
$object->SetDBField('ToEmail', $from_email);
}
else {
$object->SetDBField('FromEmail', $from_email);
$object->SetDBField('ToEmail', $to_email);
}
$object->SetDBField('Cc', $form->GetDBField('ReplyCc'));
$object->SetDBField('Bcc', $form->GetDBField('ReplyBcc'));
$ids = $this->StoreSelectedIDs($event);
if ( $ids ) {
$org_message =& $this->Application->recallObject($event->Prefix . '.-item', null, Array ('skip_autoload' => true));
/* @var $org_message kDBItem */
$org_message->Load(array_shift($ids));
// client could reply from different email, so compare to admin email!
if ( $org_message->GetDBField('ToEmail') == $from_email ) {
// can reply only to client email, not own :)
// transform subject
$message_subject = $org_message->GetDBField('Subject');
if ( $message_subject ) {
$object->SetDBField('Subject', $this->_transformSubject($message_subject, 'Re'));
}
// add signature
$message_body = $form->GetDBField('ReplyMessageSignature');
if ( $org_message->GetDBField('Message') ) {
// add replied marks
$message_body .= '> ' . preg_replace('/([\r]*\n)/', '\\1> ', $org_message->GetDBField('Message'));
}
$object->SetDBField('ToEmail', $org_message->GetDBField('FromEmail')); // user client's email from reply
$object->SetDBField('Message', $message_body);
$object->SetDBField('ReplyTo', $org_message->GetID());
}
}
else {
$sql = 'SELECT COUNT(*)
FROM ' . $object->TableName . '
WHERE FormSubmissionId = ' . $form_submission->GetID();
$replies_found = $this->Conn->GetOne($sql);
if ( !$replies_found ) {
// 1st message from admin -> quote subject & text from feedback
$message_subject = $form_submission_helper->getFieldByRole($form_submission, SubmissionFormField::COMMUNICATION_ROLE_SUBJECT, true);
if ( $message_subject ) {
$object->SetDBField('Subject', $this->_transformSubject($message_subject, 'Re'));
}
// add signature
$message_body = $form->GetDBField('ReplyMessageSignature');
// add replied marks
$original_message_body = $form_submission_helper->getFieldByRole($form_submission, SubmissionFormField::COMMUNICATION_ROLE_BODY);
if ( $original_message_body ) {
$message_body .= '> ' . preg_replace('/([\r]*\n)/', '\\1> ', $original_message_body);
}
$object->SetDBField('Message', $message_body);
}
}
$this->clearSelectedIDs($event);
}
/**
* Parses $search string in subject and reformats it
* Used for replying and forwarding
*
* @param string $subject
* @param string $search
* @return string
*/
function _transformSubject($subject, $search = 'Re')
{
$regex = '/'.$search.'(\[([\d]+)\]){0,1}:/i';
preg_match_all($regex, $subject, $regs);
if ($regs[2]) {
$reply_count = 0; // reply count without numbers (equals to "re[1]")
$max_reply_number = 0; // maximal reply number
sort($regs[2], SORT_NUMERIC); // sort ascending (non-numeric replies first)
foreach ($regs[2] as $match) {
if (!$match) {
// found "re:"
$reply_count++;
}
elseif ($match > $max_reply) {
// found "re:[number]"
$max_reply_number = $match;
}
}
return $search.'['.($reply_count + $max_reply_number + 1).']: '.trim(preg_replace($regex, '', $subject));
}
return $search.': '.$subject;
}
/**
* Resends reply, that was not sent last time
*
* @param kEvent $event
*/
- function OnResendReply(&$event)
+ function OnResendReply($event)
{
$ids = $this->StoreSelectedIDs($event);
if (!$ids) {
return ;
}
$object =& $event->getObject( Array('skip_autoload' => true) );
/* @var $object kDBItem */
$sql = 'SELECT f.ReplyFromEmail, sl.' . $object->IDField . '
FROM ' . $object->TableName . ' sl
JOIN ' . $this->Application->getUnitOption('formsubs', 'TableName') . ' fs ON fs.FormSubmissionId = sl.FormSubmissionId
JOIN ' . $this->Application->getUnitOption('form', 'TableName') . ' f ON f.FormId = fs.FormId
WHERE sl.' . $object->IDField . ' IN (' . implode(',', $ids) . ')';
$reply_emails = $this->Conn->GetCol($sql, $object->IDField);
foreach ($ids as $id) {
$object->Load($id);
// allow to send messages, that were successfully sended before :(
if (($object->GetDBField('ToEmail') != $reply_emails[$id]) && ($object->GetDBField('SentStatus') != SUBMISSION_LOG_SENT)) {
$object->SetOriginalField('SentStatus', 0); // reset sent status to update sent date automatically
$this->_sendEmail($object); // resend email here
}
}
$this->clearSelectedIDs($event);
if (!$this->Application->GetVar('from_list')) {
$event->SetRedirectParam('opener', 'u');
}
}
/**
* Updates last operation dates for log record
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnBeforeItemCreate(kEvent &$event)
+ protected function OnBeforeItemCreate(kEvent $event)
{
parent::OnBeforeItemCreate($event);
$this->_validateRecipients($event);
$this->_updateStatusDates($event);
}
/**
* Updates last operation dates for log record
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnBeforeItemUpdate(kEvent &$event)
+ protected function OnBeforeItemUpdate(kEvent $event)
{
parent::OnBeforeItemUpdate($event);
$this->_validateRecipients($event);
$this->_updateStatusDates($event);
}
/**
* Validates email recipients
*
* @param kEvent $event
*/
- function _validateRecipients(&$event)
+ function _validateRecipients($event)
{
$object =& $event->getObject();
/* @var $object kDBItem */
$esender =& $this->Application->recallObject('EmailSender');
/* @var $esender kEmailSendingHelper */
$cc = $object->GetDBField('Cc');
if ($cc && ($esender->GetRecipients($cc) === false)) {
$object->SetError('Cc', 'invalid_format');
}
$bcc = $object->GetDBField('Bcc');
if ($bcc && ($esender->GetRecipients($bcc) === false)) {
$object->SetError('Bcc', 'invalid_format');
}
}
/**
* Generates verification code and sets it inside sent message
*
* @param kDBItem $object
* @return string
*/
function _generateVerificationCode(&$object)
{
$code = Array (
$object->GetDBField('FromEmail'),
$object->GetDBField('ToEmail'),
$object->GetID(),
microtime(true)
);
$object->SetDBField('VerifyCode', md5( implode('-', $code) ));
}
/**
* Sends email based on fields from given submission-log record
*
* @param kDBItem $object
*/
function _sendEmail(&$object)
{
if ($this->Application->GetVar('client_mode')) {
return ;
}
if (!$object->GetDBField('VerifyCode')) {
$this->_generateVerificationCode($object);
}
$form_submission =& $this->_getFormSubmission($object);
$form_submission_helper =& $this->Application->recallObject('FormSubmissionHelper');
/* @var $form_submission_helper FormSubmissionHelper */
$form =& $form_submission_helper->getForm($form_submission);
$send_params = Array (
'from_name' => $form->GetDBField('ReplyFromName'),
'from_email' => $object->GetDBField('FromEmail'),
'to_email' => $object->GetDBField('ToEmail'),
'subject' => $object->GetDBField('Subject'),
'message' => $object->GetDBField('Message'),
);
$to_name = $form_submission_helper->getFieldByRole($form_submission, SubmissionFormField::COMMUNICATION_ROLE_NAME);
if ($to_name) {
$send_params['to_name'] = $to_name;
}
$esender =& $this->Application->recallObject('EmailSender');
/* @var $esender kEmailSendingHelper */
$esender->SetReturnPath( $form->GetDBField('BounceEmail') );
if ($object->GetDBField('Cc')) {
$recipients = $esender->GetRecipients( $object->GetDBField('Cc') );
foreach ($recipients as $recipient_info) {
$esender->AddCc($recipient_info['Email'], $recipient_info['Name']);
}
}
if ($object->GetDBField('Bcc')) {
$recipients = $esender->GetRecipients( $object->GetDBField('Bcc') );
foreach ($recipients as $recipient_info) {
$esender->AddBcc($recipient_info['Email'], $recipient_info['Name']);
}
}
if ($object->GetDBField('Attachment')) {
$attachments = explode('|', $object->GetField('Attachment', 'file_paths'));
foreach ($attachments as $attachment) {
$esender->AddAttachment($attachment);
}
}
$this->Application->EmailEventAdmin('FORM.SUBMISSION.REPLY.TO.USER', null, $send_params);
// mark as sent after sending is finished
$object->SetDBField('SentStatus', SUBMISSION_LOG_SENT);
// reset bounce status before (re-)sending
$object->SetDBField('BounceInfo', NULL);
$object->SetDBField('BounceDate_date', NULL);
$object->SetDBField('BounceDate_time', NULL);
if ($object->GetDBField('DraftId')) {
$temp_handler =& $this->Application->recallObject('draft_TempHandler', 'kTempTablesHandler');
/* @var $temp_handler kTempTablesHandler */
$temp_handler->DeleteItems('draft', '', Array ($object->GetDBField('DraftId')));
$object->SetDBField('DraftId', 0);
}
$object->Update();
}
/**
* Sends new email after log record was created
* Updates last update time for submission
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnAfterItemCreate(kEvent &$event)
+ protected function OnAfterItemCreate(kEvent $event)
{
parent::OnAfterItemCreate($event);
$object =& $event->getObject();
/* @var $object kDBItem */
$this->_sendEmail($object); // send email
$this->_updateSubmission($event);
$reply_to = $object->GetDBField('ReplyTo');
if ( !$reply_to ) {
$reply_to = $this->_getLastMessageId($event, !$this->Application->GetVar('client_mode'));
}
if ( $reply_to ) {
// this is reply to other message -> mark it as replied
$org_message =& $this->Application->recallObject($event->Prefix . '.-item', null, Array ('skip_autoload' => true));
/* @var $org_message kDBItem */
$org_message->Load($reply_to);
$org_message->SetDBField('ReplyStatus', SUBMISSION_LOG_REPLIED);
$org_message->Update();
}
if ( $this->Application->GetVar('client_mode') ) {
// new reply from client received -> send notification about it
$this->Application->EmailEventAdmin('FORM.SUBMISSION.REPLY.FROM.USER');
}
}
/**
* Returns last message id (client OR admin)
*
* @param kEvent $event
* @param bool $from_client
* @return int
*/
- function _getLastMessageId(&$event, $from_client = false)
+ function _getLastMessageId($event, $from_client = false)
{
$object =& $event->getObject();
/* @var $object kDBItem */
$form_submission =& $this->_getFormSubmission($object);
$form_submission_helper =& $this->Application->recallObject('FormSubmissionHelper');
/* @var $form_submission_helper FormSubmissionHelper */
$form =& $form_submission_helper->getForm($form_submission);
$reply_email = $form->GetDBField('ReplyFromEmail');
$sql = 'SELECT MAX(' . $object->IDField . ')
FROM ' . $object->TableName . '
WHERE (FormSubmissionId = ' . $form_submission->GetID() . ') AND (ToEmail' . ($from_client ? ' = ' : ' <> ') . $this->Conn->qstr($reply_email) . ')';
return $this->Conn->GetOne($sql);
}
/**
* Updates last update time for submission
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnAfterItemUpdate(kEvent &$event)
+ protected function OnAfterItemUpdate(kEvent $event)
{
parent::OnAfterItemUpdate($event);
$this->_updateSubmission($event);
$object =& $event->getObject();
/* @var $object kDBItem */
// send out email event to admin for bouncing
$sent_status = $object->GetDBField('SentStatus');
if ( $object->GetOriginalField('SentStatus') != $sent_status && $sent_status == SUBMISSION_LOG_BOUNCE ) {
$this->Application->EmailEventAdmin('FORM.SUBMISSION.REPLY.FROM.USER.BOUNCED');
}
}
/**
* Sets last sent/reply dates based on field changes in log record
*
* @param kEvent $event
*/
- function _updateStatusDates(&$event)
+ function _updateStatusDates($event)
{
$object =& $event->getObject();
/* @var $object kDBItem */
$now = adodb_mktime();
$sent_status = $object->GetDBField('SentStatus');
if (($event->Special != 'merge') && ($sent_status == SUBMISSION_LOG_SENT) && ($sent_status != $object->GetOriginalField('SentStatus'))) {
// sent status was set
$object->SetDBField('SentOn_date', $now);
$object->SetDBField('SentOn_time', $now);
}
$reply_status = $object->GetDBField('ReplyStatus');
if (($reply_status == SUBMISSION_LOG_REPLIED) && ($reply_status != $object->GetOriginalField('ReplyStatus'))) {
// sent status was set
$object->SetDBField('RepliedOn_date', $now);
$object->SetDBField('RepliedOn_time', $now);
}
}
/**
* Returns form submission by given event of submission log
*
* @param kDBItem $object
* @return kDBItem
*/
function &_getFormSubmission(&$object)
{
$submission_id = $object->GetDBField('FormSubmissionId');
$form_submission =& $this->Application->recallObject('formsubs.-item', null, Array ('skip_autoload' => true));
/* @var $form_submission kDBItem */
if ($form_submission->isLoaded() && ($form_submission->GetID() == $submission_id)) {
// already loaded AND has needed id
return $form_submission;
}
$form_submission->Load($submission_id);
return $form_submission;
}
/**
* Sets last updated field for form submission
*
* @param kEvent $event
*/
- function _updateSubmission(&$event)
+ function _updateSubmission($event)
{
$object =& $event->getObject();
/* @var $object kDBItem */
$form_submission =& $this->_getFormSubmission($object);
// 1. set last updated
$last_updated = max ($object->GetDBField('SentOn'), $object->GetDBField('RepliedOn'));
if ($form_submission->GetDBField('LastUpdatedOn') < $last_updated) {
// don't set smaller last update, that currenly set
$form_submission->SetDBField('LastUpdatedOn_date', $last_updated);
$form_submission->SetDBField('LastUpdatedOn_time', $last_updated);
}
// 2. update submission status
$form_submission_helper =& $this->Application->recallObject('FormSubmissionHelper');
/* @var $form_submission_helper FormSubmissionHelper */
$form =& $form_submission_helper->getForm($form_submission);
$client_responce = $form->GetDBField('ReplyFromEmail') == $object->GetDBField('ToEmail');
$replied = $object->GetDBField('ReplyStatus') == SUBMISSION_LOG_REPLIED;
if (!$client_responce && !$replied) {
// admin sends new email to client
$form_submission->SetDBField('LogStatus', SUBMISSION_REPLIED);
}
elseif ($client_responce) {
// client email becomes replied OR receiving new unreplied email from client
$form_submission->SetDBField('LogStatus', $replied ? SUBMISSION_REPLIED : SUBMISSION_NEW_EMAIL);
}
if ($object->GetDBField('SentStatus') == SUBMISSION_LOG_BOUNCE) {
// propagate bounce status from reply
$form_submission->SetDBField('LogStatus', SUBMISSION_BOUNCE);
}
$form_submission->Update();
}
/**
* Saves current unsent message as draft
*
* @param kEvent $event
*/
- function OnSaveDraft(&$event)
+ function OnSaveDraft($event)
{
$object =& $event->getObject( Array('skip_autoload' => true) );
/* @var $object kDBItem */
$draft =& $this->Application->recallObject('draft', null, Array('skip_autoload' => true));
/* @var $draft kDBItem */
$items_info = $this->Application->GetVar( $event->getPrefixSpecial(true) );
if ($items_info) {
foreach ($items_info as $id => $field_values) {
$object->setID($id);
$object->SetFieldsFromHash($field_values, $this->getRequestProtectedFields($field_values));
$load_keys = Array (
'FormSubmissionId' => $object->GetDBField('FormSubmissionId'),
'CreatedById' => $this->Application->RecallVar('user_id'),
);
// get existing draft for given submission and user
$draft->Load($load_keys);
$draft->SetDBField('Message', $object->GetDBField('Message'));
if ($draft->isLoaded()) {
$draft->Update();
}
else {
$draft->SetDBFieldsFromHash($load_keys);
$draft->Create();
}
}
}
$this->Application->SetVar($event->getPrefixSpecial() . '_SaveEvent', 'OnCreate');
$event->SetRedirectParam('opener', 'u');
}
/**
* Uses found draft instead of submission reply body
*
* @param kEvent $event
*/
- function OnUseDraft(&$event)
+ function OnUseDraft($event)
{
$object =& $event->getObject( Array('skip_autoload' => true) );
/* @var $object kDBItem */
$draft =& $this->Application->recallObject('draft', null, Array('skip_autoload' => true));
/* @var $draft kDBItem */
$items_info = $this->Application->GetVar( $event->getPrefixSpecial(true) );
if ($items_info) {
foreach ($items_info as $id => $field_values) {
$object->setID($id);
$object->SetFieldsFromHash($field_values, $this->getRequestProtectedFields($field_values));
$load_keys = Array (
'FormSubmissionId' => $object->GetDBField('FormSubmissionId'),
'CreatedById' => $this->Application->RecallVar('user_id'),
);
// get existing draft for given submission and user
$draft->Load($load_keys);
if ($draft->isLoaded()) {
$object->SetDBField('Message', $draft->GetDBField('Message'));
$object->SetDBField('DraftId', $draft->GetID());
}
}
}
$this->Application->SetVar($event->getPrefixSpecial() . '_SaveEvent', 'OnCreate');
$event->redirect = false;
}
/**
* Deletes draft, that matches given user and form submission
*
* @param kEvent $event
*/
- function OnDeleteDraft(&$event)
+ function OnDeleteDraft($event)
{
$object =& $event->getObject( Array('skip_autoload' => true) );
/* @var $object kDBItem */
$draft =& $this->Application->recallObject('draft', null, Array('skip_autoload' => true));
/* @var $draft kDBItem */
$items_info = $this->Application->GetVar( $event->getPrefixSpecial(true) );
if ($items_info) {
foreach ($items_info as $id => $field_values) {
$object->setID($id);
$object->SetFieldsFromHash($field_values, $this->getRequestProtectedFields($field_values));
$object->SetDBField('DraftId', 0);
$load_keys = Array (
'FormSubmissionId' => $object->GetDBField('FormSubmissionId'),
'CreatedById' => $this->Application->RecallVar('user_id'),
);
// get existing draft for given submission and user
$draft->Load($load_keys);
if ($draft->isLoaded()) {
$temp_handler =& $this->Application->recallObject('draft_TempHandler', 'kTempTablesHandler');
/* @var $temp_handler kTempTablesHandler */
$temp_handler->DeleteItems('draft', '', Array ($draft->GetID()));
}
}
}
$this->Application->SetVar($event->getPrefixSpecial() . '_SaveEvent', 'OnCreate');
$event->redirect = false;
}
}
\ No newline at end of file
Index: branches/5.2.x/core/units/admin/admin_events_handler.php
===================================================================
--- branches/5.2.x/core/units/admin/admin_events_handler.php (revision 15129)
+++ branches/5.2.x/core/units/admin/admin_events_handler.php (revision 15130)
@@ -1,1188 +1,1188 @@
<?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 AdminEventsHandler extends kDBEventHandler {
/**
* Allows to override standard permission mapping
*
* @return void
* @access protected
* @see kEventHandler::$permMapping
*/
protected function mapPermissions()
{
parent::mapPermissions();
$permissions = Array (
'OnSaveColumns' => Array ('self' => true),
'OnClosePopup' => Array ('self' => true),
'OnSaveSetting' => Array ('self' => true),
'OnDropTempTablesByWID' => 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(kEvent &$event)
+ public function CheckPermission(kEvent $event)
{
$perm_value = null;
$system_events = Array (
'OnResetModRwCache', 'OnResetSections', 'OnResetConfigsCache', 'OnResetParsedData', 'OnResetMemcache',
'OnDeleteCompiledTemplates', 'OnCompileTemplates', 'OnGenerateTableStructure', 'OnSynchronizeDBRevisions',
'OnDeploy', 'OnRebuildThemes', 'OnCheckPrefixConfig', 'OnMemoryCacheGet', 'OnMemoryCacheSet'
);
if ( in_array($event->Name, $system_events) ) {
// events from "Tools -> System Tools" section are controlled via that section "edit" permission
$perm_value = /*$this->Application->isDebugMode() ||*/ $this->Application->CheckPermission($event->getSection() . '.edit');
}
$tools_events = Array (
'OnBackup' => 'in-portal:backup.view',
'OnBackupProgress' => 'in-portal:backup.view',
'OnDeleteBackup' => 'in-portal:backup.view',
'OnBackupCancel' => 'in-portal:backup.view',
'OnRestore' => 'in-portal:restore.view',
'OnRestoreProgress' => 'in-portal:restore.view',
'OnRestoreCancel' => 'in-portal:backup.view',
'OnSqlQuery' => 'in-portal:sql_query.view',
);
if ( array_key_exists($event->Name, $tools_events) ) {
$perm_value = $this->Application->CheckPermission($tools_events[$event->Name]);
}
if ( $event->Name == 'OnSaveMenuFrameWidth' ) {
$perm_value = $this->Application->isAdminUser;
}
$perm_helper =& $this->Application->recallObject('PermissionsHelper');
/* @var $perm_helper kPermissionsHelper */
$csv_events = Array ('OnCSVImportBegin', 'OnCSVImportStep', 'OnExportCSV', 'OnGetCSV');
if ( in_array($event->Name, $csv_events) ) {
$csv_helper =& $this->Application->recallObject('CSVHelper');
/* @var $csv_helper kCSVHelper */
$prefix = $csv_helper->getPrefix(stripos($event->Name, 'import') !== false);
$perm_mapping = Array (
'OnCSVImportBegin' => 'OnProcessSelected',
'OnCSVImportStep' => 'OnProcessSelected',
'OnExportCSV' => 'OnLoad',
'OnGetCSV' => 'OnLoad',
);
$tmp_event = new kEvent($prefix . ':' . $perm_mapping[$event->Name] );
$perm_value = $perm_helper->CheckEventPermission($tmp_event, $this->permMapping);
}
if ( isset($perm_value) ) {
return $perm_helper->finalizePermissionCheck($event, $perm_value);
}
return parent::CheckPermission($event);
}
/**
* Reset mod-rewrite url cache
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnResetModRwCache(kEvent &$event)
+ protected function OnResetModRwCache(kEvent $event)
{
if ( $this->Application->GetVar('ajax') == 'yes' ) {
$event->status = kEvent::erSTOP;
}
$this->Conn->Query('DELETE FROM ' . TABLE_PREFIX . 'CachedUrls');
$event->SetRedirectParam('action_completed', 1);
}
/**
* Resets tree section cache and refreshes admin section tree
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnResetSections(kEvent &$event)
+ protected function OnResetSections(kEvent $event)
{
if ($this->Application->GetVar('ajax') == 'yes') {
$event->status = kEvent::erSTOP;
}
if ($this->Application->isCachingType(CACHING_TYPE_MEMORY)) {
$this->Application->rebuildCache('master:sections_parsed', kCache::REBUILD_LATER, CacheSettings::$sectionsParsedRebuildTime);
}
else {
$this->Application->rebuildDBCache('sections_parsed', kCache::REBUILD_LATER, CacheSettings::$sectionsParsedRebuildTime);
}
$event->SetRedirectParam('refresh_tree', 1);
$event->SetRedirectParam('action_completed', 1);
}
/**
* Resets unit config cache
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnResetConfigsCache(kEvent &$event)
+ protected function OnResetConfigsCache(kEvent $event)
{
if ( $this->Application->GetVar('ajax') == 'yes' ) {
$event->status = kEvent::erSTOP;
}
if ( $this->Application->isCachingType(CACHING_TYPE_MEMORY) ) {
$this->Application->rebuildCache('master:config_files', kCache::REBUILD_LATER, CacheSettings::$unitCacheRebuildTime);
}
else {
$this->Application->rebuildDBCache('config_files', kCache::REBUILD_LATER, CacheSettings::$unitCacheRebuildTime);
}
$this->OnResetParsedData($event);
$skin_helper =& $this->Application->recallObject('SkinHelper');
/* @var $skin_helper SkinHelper */
$skin_helper->deleteCompiled();
}
/**
* Resets parsed data from unit configs
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnResetParsedData(kEvent &$event)
+ protected function OnResetParsedData(kEvent $event)
{
if ( $this->Application->GetVar('ajax') == 'yes' ) {
$event->status = kEvent::erSTOP;
}
$this->Application->DeleteUnitCache();
if ( $this->Application->GetVar('validate_configs') ) {
$event->SetRedirectParam('validate_configs', 1);
}
$event->SetRedirectParam('action_completed', 1);
}
/**
* Resets memory cache
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnResetMemcache(kEvent &$event)
+ protected function OnResetMemcache(kEvent $event)
{
if ($this->Application->GetVar('ajax') == 'yes') {
$event->status = kEvent::erSTOP;
}
$this->Application->resetCache();
$event->SetRedirectParam('action_completed', 1);
}
/**
* Compiles all templates (with a progress bar)
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnCompileTemplates(kEvent &$event)
+ protected function OnCompileTemplates(kEvent $event)
{
$compiler =& $this->Application->recallObject('NParserCompiler');
/* @var $compiler NParserCompiler */
$compiler->CompileTemplatesStep();
$event->status = kEvent::erSTOP;
}
/**
* Deletes all compiled templates
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnDeleteCompiledTemplates(kEvent &$event)
+ protected function OnDeleteCompiledTemplates(kEvent $event)
{
if ( $this->Application->GetVar('ajax') == 'yes' ) {
$event->status = kEvent::erSTOP;
}
$base_path = WRITEABLE . DIRECTORY_SEPARATOR . 'cache';
// delete debugger reports
$debugger_reports = glob(RESTRICTED . '/debug_@*@.txt');
if ( $debugger_reports ) {
foreach ($debugger_reports as $debugger_report) {
unlink($debugger_report);
}
}
$this->_deleteCompiledTemplates($base_path);
$event->SetRedirectParam('action_completed', 1);
}
/**
* Deletes compiled templates in a given folder
*
* @param string $folder
* @param bool $unlink_folder
* @return void
* @access protected
*/
protected function _deleteCompiledTemplates($folder, $unlink_folder = false)
{
$sub_folders = glob($folder . '/*', GLOB_ONLYDIR);
if ( is_array($sub_folders) ) {
foreach ($sub_folders as $sub_folder) {
$this->_deleteCompiledTemplates($sub_folder, true);
}
}
$files = glob($folder . '/*.php');
if ( is_array($files) ) {
foreach ($files as $file) {
unlink($file);
}
}
if ( $unlink_folder ) {
rmdir($folder);
}
}
/**
* Generates structure for specified table
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnGenerateTableStructure(kEvent &$event)
+ protected function OnGenerateTableStructure(kEvent $event)
{
$types_hash = Array (
'string' => 'varchar|text|mediumtext|longtext|date|datetime|time|timestamp|char|year|enum|set',
'int' => 'smallint|mediumint|int|bigint|tinyint',
'float' => 'float|double|decimal',
);
$table_name = $this->Application->GetVar('table_name');
if ( !$table_name ) {
echo 'error: no table name specified';
return;
}
if ( TABLE_PREFIX && !preg_match('/^' . preg_quote(TABLE_PREFIX, '/') . '(.*)/', $table_name) && (strtolower($table_name) != $table_name) ) {
// table name without prefix, then add it (don't affect K3 tables named in lowercase)
$table_name = TABLE_PREFIX . $table_name;
}
if ( !$this->Conn->TableFound($table_name) ) {
// table with prefix doesn't exist, assume that just config prefix passed -> resolve table name from it
$prefix = preg_replace('/^' . preg_quote(TABLE_PREFIX, '/') . '/', '', $table_name);
if ( $this->Application->prefixRegistred($prefix) ) {
// when prefix is found -> use it's table (don't affect K3 tables named in lowecase)
$table_name = $this->Application->getUnitOption($prefix, 'TableName');
}
}
$table_info = $this->Conn->Query('DESCRIBE '.$table_name);
// 1. prepare config keys
$grids = Array (
'Default' => Array (
'Icons' => Array ('default' => 'icon16_item.png'),
'Fields' => Array (),
)
);
$grid_fields = Array();
$id_field = '';
$fields = Array ();
$float_types = Array ('float', 'double', 'numeric');
foreach ($table_info as $field_info) {
if ( preg_match('/l[\d]+_.*/', $field_info['Field']) ) {
// don't put multilingual fields in config
continue;
}
$field_options = Array ();
$grid_col_options = Array (
'title' => 'la_col_' . $field_info['Field'],
'filter_block' => 'grid_like_filter',
);
// 1. get php field type by mysql field type
foreach ($types_hash as $php_type => $db_types) {
if ( preg_match('/' . $db_types . '/', $field_info['Type']) ) {
$field_options['type'] = $php_type;
break;
}
}
// 2. get field default value
$default_value = $field_info['Default'];
$not_null = $field_info['Null'] != 'YES';
if ( is_numeric($default_value) ) {
$default_value = preg_match('/[\.,]/', $default_value) ? (float)$default_value : (int)$default_value;
}
if ( is_null($default_value) && $not_null ) {
$default_value = $field_options['type'] == 'string' ? '' : 0;
}
if ( in_array($php_type, $float_types) ) {
// this is float number
if ( preg_match('/' . $db_types . '\([\d]+,([\d]+)\)/i', $field_info['Type'], $regs) ) {
// size is described in structure -> add formatter
$field_options['formatter'] = 'kFormatter';
$field_options['format'] = '%01.' . $regs[1] . 'f';
if ( $not_null ) {
// null fields, will most likely have NULL as default value
$default_value = 0;
}
}
elseif ( $not_null ) {
// no size information, just convert to float
// null fields, will most likely have NULL as default value
$default_value = (float)$default_value;
}
}
if ( preg_match('/varchar\(([\d]+)\)/i', $field_info['Type'], $regs) ) {
$field_options['max_len'] = (int)$regs[1];
}
if ( preg_match('/tinyint\([\d]+\)/i', $field_info['Type']) ) {
$field_options['formatter'] = 'kOptionsFormatter';
$field_options['options'] = Array (1 => 'la_Yes', 0 => 'la_No');
$field_options['use_phrases'] = 1;
$grid_col_options['filter_block'] = 'grid_options_filter';
}
if ( $not_null ) {
$field_options['not_null'] = 1;
}
if ( $field_info['Key'] == 'PRI' ) {
$default_value = 0;
$id_field = $field_info['Field'];
}
if ( $php_type == 'int' && !$not_null ) {
// numeric null field
if ( preg_match('/(On|Date)$/', $field_info['Field']) || $field_info['Field'] == 'Modified' ) {
$field_options['formatter'] = 'kDateFormatter';
$grid_col_options['filter_block'] = 'grid_date_rage_filter';
}
}
if ( $php_type == 'int' && ($not_null || is_numeric($default_value)) ) {
// is integer field AND not null
$field_options['default'] = (int)$default_value;
}
else {
$field_options['default'] = $default_value;
}
$fields[$field_info['Field']] = $field_options;
$grids_fields[$field_info['Field']] = $grid_col_options;
}
$grids['Default']['Fields'] = $grids_fields;
$ret = Array (
'IDField' => $id_field,
'Fields' => $fields,
'Grids' => $grids,
);
$decorator = new UnitConfigDecorator();
$ret = $decorator->decorate($ret);
$this->Application->InitParser();
ob_start();
echo $this->Application->ParseBlock(Array('name' => 'incs/header', 'body_properties' => 'style="background-color: #E7E7E7; margin: 8px;"'));
?>
<script type="text/javascript">
set_window_title('Table "<?php echo $table_name; ?>" Structure');
</script>
<a href="javascript:window_close();">Close Window</a><br /><br />
<?php echo $GLOBALS['debugger']->highlightString($ret); ?>
<br /><br /><a href="javascript:window_close();">Close Window</a><br />
<?php
echo $this->Application->ParseBlock(Array('name' => 'incs/footer'));
echo ob_get_clean();
$event->status = kEvent::erSTOP;
}
/**
* Refreshes ThemeFiles & Themes tables by actual content on HDD
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnRebuildThemes(kEvent &$event)
+ protected function OnRebuildThemes(kEvent $event)
{
if ( $this->Application->GetVar('ajax') == 'yes' ) {
$event->status = kEvent::erSTOP;
}
$themes_helper =& $this->Application->recallObject('ThemesHelper');
/* @var $themes_helper kThemesHelper */
$themes_helper->refreshThemes();
$event->SetRedirectParam('action_completed', 1);
}
/**
* Saves grid column widths after their resize by user
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnSaveColumns(kEvent &$event)
+ protected function OnSaveColumns(kEvent $event)
{
$picker_helper =& $this->Application->recallObject('ColumnPickerHelper');
/* @var $picker_helper kColumnPickerHelper */
$picker_helper->SetGridName($this->Application->GetLinkedVar('grid_name'));
$picked = trim($this->Application->GetVar('picked_str'), '|');
$hidden = trim($this->Application->GetVar('hidden_str'), '|');
$main_prefix = $this->Application->GetVar('main_prefix');
$picker_helper->SaveColumns($main_prefix, $picked, $hidden);
$this->finalizePopup($event);
}
/**
* Saves various admin settings via ajax
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnSaveSetting(kEvent &$event)
+ protected function OnSaveSetting(kEvent $event)
{
if ( $this->Application->GetVar('ajax') != 'yes' ) {
return;
}
$var_name = $this->Application->GetVar('var_name');
$var_value = $this->Application->GetVar('var_value');
$this->Application->StorePersistentVar($var_name, $var_value);
$event->status = kEvent::erSTOP;
}
/**
* Just closes popup & deletes last_template & opener_stack if popup, that is closing
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnClosePopup(kEvent &$event)
+ protected function OnClosePopup(kEvent $event)
{
$event->SetRedirectParam('opener', 'u');
}
/**
* Occurs right after initialization of the kernel, used mainly as hook-to event
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnStartup(kEvent &$event)
+ protected function OnStartup(kEvent $event)
{
if ( $this->Application->isAdmin ) {
return;
}
$base_url = preg_quote($this->Application->BaseURL(), '/');
$referrer = isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '';
if ( $referrer && !preg_match('/^' . $base_url . '/', $referrer) ) {
$this->Application->Session->SetCookie('original_referrer', $referrer);
$this->Application->SetVar('original_referrer', $referrer);
}
}
/**
* Occurs right before echoing the output, in Done method of application, used mainly as hook-to event
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnBeforeShutdown(kEvent &$event)
+ protected function OnBeforeShutdown(kEvent $event)
{
}
/**
* Is called after tree was build (when not from cache)
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnAfterBuildTree(kEvent &$event)
+ protected function OnAfterBuildTree(kEvent $event)
{
}
/**
* Called by AJAX to perform CSV export
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnExportCSV(kEvent &$event)
+ protected function OnExportCSV(kEvent $event)
{
$csv_helper =& $this->Application->recallObject('CSVHelper');
/* @var $csv_helper kCSVHelper */
$csv_helper->PrefixSpecial = $csv_helper->getPrefix(false);
$csv_helper->grid = $this->Application->GetVar('grid');
$csv_helper->ExportStep();
$event->status = kEvent::erSTOP;
}
/**
* Returning created by AJAX CSV file
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnGetCSV(kEvent &$event)
+ protected function OnGetCSV(kEvent $event)
{
$csv_helper =& $this->Application->recallObject('CSVHelper');
/* @var $csv_helper kCSVHelper */
$csv_helper->GetCSV();
}
/**
* Start CSV import
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnCSVImportBegin(kEvent &$event)
+ protected function OnCSVImportBegin(kEvent $event)
{
$object =& $event->getObject(Array ('skip_autoload' => true));
/* @var $object kDBItem */
$field_values = $this->getSubmittedFields($event);
$object->SetFieldsFromHash($field_values, $this->getRequestProtectedFields($field_values));
$event->redirect = false;
$result = 'required';
if ( $object->GetDBField('ImportFile') ) {
$csv_helper =& $this->Application->recallObject('CSVHelper');
/* @var $csv_helper kCSVHelper */
$csv_helper->PrefixSpecial = $csv_helper->getPrefix(true);
$csv_helper->grid = $this->Application->GetVar('grid');
$result = $csv_helper->ImportStart($object->GetField('ImportFile', 'file_paths'));
if ( $result === true ) {
$event->redirect = $this->Application->GetVar('next_template');
$event->SetRedirectParam('PrefixSpecial', $this->Application->GetVar('PrefixSpecial'));
$event->SetRedirectParam('grid', $this->Application->GetVar('grid'));
}
}
if ( $event->redirect === false ) {
$object->SetError('ImportFile', $result);
$event->status = kEvent::erFAIL;
}
}
/**
* Performs one CSV import step
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnCSVImportStep(kEvent &$event)
+ protected function OnCSVImportStep(kEvent $event)
{
$import_helper =& $this->Application->recallObject('CSVHelper');
/* @var $import_helper kCSVHelper */
$import_helper->ImportStep();
$event->status = kEvent::erSTOP;
}
/**
* Shows unit config filename, where requested prefix is defined
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnCheckPrefixConfig(kEvent &$event)
+ protected function OnCheckPrefixConfig(kEvent $event)
{
$prefix = $this->Application->GetVar('config_prefix');
$config_file = $this->Application->UnitConfigReader->prefixFiles[$prefix];
$this->Application->InitParser();
ob_start();
echo $this->Application->ParseBlock(Array('name' => 'incs/header', 'body_properties' => 'style="background-color: #E7E7E7; margin: 8px;"'));
?>
<script type="text/javascript">
set_window_title('Unit Config of "<?php echo $prefix; ?>" prefix');
</script>
<a href="javascript:window_close();">Close Window</a><br /><br />
<strong>Prefix:</strong> <?php echo $prefix; ?><br />
<strong>Unit Config:</strong> <?php echo $GLOBALS['debugger']->highlightString($config_file); ?><br />
<br /><a href="javascript:window_close();">Close Window</a><br />
<?php
echo $this->Application->ParseBlock(Array ('name' => 'incs/footer'));
echo ob_get_clean();
$event->status = kEvent::erSTOP;
}
/**
* Deletes temp tables, when user closes window using "x" button in top right corner
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnDropTempTablesByWID(kEvent &$event)
+ protected function OnDropTempTablesByWID(kEvent $event)
{
$sid = $this->Application->GetSID();
$wid = $this->Application->GetVar('m_wid');
$tables = $this->Conn->GetCol('SHOW TABLES');
$mask_edit_table = '/' . TABLE_PREFIX . 'ses_' . $sid . '_' . $wid . '_edit_(.*)$/';
foreach ($tables as $table) {
if ( preg_match($mask_edit_table, $table, $rets) ) {
$this->Conn->Query('DROP TABLE IF EXISTS ' . $table);
}
}
echo 'OK';
$event->status = kEvent::erSTOP;
}
/**
* Backup all data
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnBackup(kEvent &$event)
+ protected function OnBackup(kEvent $event)
{
$backup_helper =& $this->Application->recallObject('BackupHelper');
/* @var $backup_helper BackupHelper */
if ( !$backup_helper->initBackup() ) {
$event->status = kEvent::erFAIL;
}
$event->redirect = 'tools/backup2';
}
/**
* Perform next backup step
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnBackupProgress(kEvent &$event)
+ protected function OnBackupProgress(kEvent $event)
{
$backup_helper =& $this->Application->recallObject('BackupHelper');
/* @var $backup_helper BackupHelper */
$done_percent = $backup_helper->performBackup();
if ( $done_percent == 100 ) {
$event->redirect = 'tools/backup3';
return;
}
$event->status = kEvent::erSTOP;
echo $done_percent;
}
/**
* Stops Backup & redirect to Backup template
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnBackupCancel(kEvent &$event)
+ protected function OnBackupCancel(kEvent $event)
{
$event->redirect = 'tools/backup1';
}
/**
* Starts restore process
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnRestore(kEvent &$event)
+ protected function OnRestore(kEvent $event)
{
$backup_helper =& $this->Application->recallObject('BackupHelper');
/* @var $backup_helper BackupHelper */
$backup_helper->initRestore();
$event->redirect = 'tools/restore3';
}
/**
* Performs next restore step
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnRestoreProgress(kEvent &$event)
+ protected function OnRestoreProgress(kEvent $event)
{
$backup_helper =& $this->Application->recallObject('BackupHelper');
/* @var $backup_helper BackupHelper */
$done_percent = $backup_helper->performRestore();
if ( $done_percent == BackupHelper::SQL_ERROR_DURING_RESTORE ) {
$event->redirect = 'tools/restore4';
}
elseif ( $done_percent == BackupHelper::FAILED_READING_BACKUP_FILE ) {
$this->Application->StoreVar('adm.restore_error', 'File read error');
$event->redirect = 'tools/restore4';
}
elseif ( $done_percent == 100 ) {
$backup_helper->replaceRestoredFiles();
$this->Application->StoreVar('adm.restore_success', 1);
$event->redirect = 'tools/restore4';
}
else {
$event->status = kEvent::erSTOP;
echo $done_percent;
}
}
/**
* Stops Restore & redirect to Restore template
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnRestoreCancel(kEvent &$event)
+ protected function OnRestoreCancel(kEvent $event)
{
$event->redirect = 'tools/restore1';
}
/**
* Deletes one backup file
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnDeleteBackup(kEvent &$event)
+ protected function OnDeleteBackup(kEvent $event)
{
$backup_helper =& $this->Application->recallObject('BackupHelper');
/* @var $backup_helper BackupHelper */
$backup_helper->delete();
}
/**
* Starts restore process
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnSqlQuery(kEvent &$event)
+ protected function OnSqlQuery(kEvent $event)
{
$sql = $this->Application->GetVar('sql');
if ( $sql ) {
$start = microtime(true);
$result = $this->Conn->Query($sql);
$this->Application->SetVar('sql_time', round(microtime(true) - $start, 7));
if ( $result ) {
if ( is_array($result) ) {
$this->Application->SetVar('sql_has_rows', 1);
$this->Application->SetVar('sql_rows', serialize($result));
}
}
$check_sql = trim(strtolower($sql));
if ( preg_match('/^(insert|update|replace|delete)/', $check_sql) ) {
$this->Application->SetVar('sql_has_affected', 1);
$this->Application->SetVar('sql_affected', $this->Conn->getAffectedRows());
}
}
$this->Application->SetVar('query_status', 1);
$event->status = kEvent::erFAIL;
}
/**
* Occurs after unit config cache was successfully rebuilt
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnAfterCacheRebuild(kEvent &$event)
+ protected function OnAfterCacheRebuild(kEvent $event)
{
}
/**
* Removes "Community -> Groups" section when it is not allowed
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnAfterConfigRead(kEvent &$event)
+ protected function OnAfterConfigRead(kEvent $event)
{
parent::OnAfterConfigRead($event);
$section_adjustments = $this->Application->getUnitOption($event->Prefix, 'SectionAdjustments', Array());
if ( !$this->Application->ConfigValue('AdvancedUserManagement') ) {
$section_adjustments['in-portal:user_groups'] = 'remove';
}
$section_adjustments['in-portal:root'] = Array (
'label' => $this->Application->ConfigValue('Site_Name')
);
$this->Application->setUnitOption($event->Prefix, 'SectionAdjustments', $section_adjustments);
}
/**
* Saves menu (tree) frame width
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnSaveMenuFrameWidth(kEvent &$event)
+ protected function OnSaveMenuFrameWidth(kEvent $event)
{
$event->status = kEvent::erSTOP;
if ( !$this->Application->ConfigValue('ResizableFrames') ) {
return;
}
$this->Application->SetConfigValue('MenuFrameWidth', (int)$this->Application->GetVar('width'));
}
/**
* Retrieves data from memory cache
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnMemoryCacheGet(kEvent &$event)
+ protected function OnMemoryCacheGet(kEvent $event)
{
$event->status = kEvent::erSTOP;
$ret = Array ('message' => '', 'code' => 0); // 0 - ok, > 0 - error
$key = $this->Application->GetVar('key');
if ( !$key ) {
$ret['code'] = 1;
$ret['message'] = 'Key name missing';
}
else {
$value = $this->Application->getCache($key);
$ret['value'] =& $value;
$ret['size'] = is_string($value) ? kUtil::formatSize(strlen($value)) : '?';
$ret['type'] = gettype($value);
if ( kUtil::IsSerialized($value) ) {
$value = unserialize($value);
}
if ( is_array($value) ) {
$ret['value'] = print_r($value, true);
}
if ( $ret['value'] === false ) {
$ret['code'] = 2;
$ret['message'] = 'Key "' . $key . '" doesn\'t exist';
}
}
$json_helper =& $this->Application->recallObject('JSONHelper');
/* @var $json_helper JSONHelper */
echo $json_helper->encode($ret);
}
/**
* Retrieves data from memory cache
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnMemoryCacheSet(kEvent &$event)
+ protected function OnMemoryCacheSet(kEvent $event)
{
$event->status = kEvent::erSTOP;
$ret = Array ('message' => '', 'code' => 0); // 0 - ok, > 0 - error
$key = $this->Application->GetVar('key');
if ( !$key ) {
$ret['code'] = 1;
$ret['message'] = 'Key name missing';
}
else {
$value = $this->Application->GetVar('value');
$res = $this->Application->setCache($key, $value);
$ret['result'] = $res ? 'OK' : 'FAILED';
}
$json_helper =& $this->Application->recallObject('JSONHelper');
/* @var $json_helper JSONHelper */
echo $json_helper->encode($ret);
}
/**
* Deploy changes
*
* Usage: "php tools/run_event.php adm:OnDeploy b674006f3edb1d9cd4d838c150b0567d"
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnDeploy(kEvent &$event)
+ protected function OnDeploy(kEvent $event)
{
$deployment_helper =& $this->Application->recallObject('DeploymentHelper');
/* @var $deployment_helper DeploymentHelper */
$deployment_helper->deployAll();
if ( $deployment_helper->isCommandLine ) {
// command line invocation -> don't render template
$event->status = kEvent::erSTOP;
}
else {
// browser invocation -> don't perform redirect
$event->redirect = false;
}
$event->SetRedirectParam('action_completed', 1);
}
/**
* Synchronizes database revisions from "project_upgrades.sql" file
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnSynchronizeDBRevisions(kEvent &$event)
+ protected function OnSynchronizeDBRevisions(kEvent $event)
{
$deployment_helper =& $this->Application->recallObject('DeploymentHelper');
/* @var $deployment_helper DeploymentHelper */
if ( $deployment_helper->deployAll(true) ) {
$this->Application->SetVar('action_completed', 1);
}
if ( $deployment_helper->isCommandLine ) {
// command line invocation -> don't render template
$event->status = kEvent::erSTOP;
}
else {
// browser invocation -> don't perform redirect
$event->redirect = false;
}
}
/**
* [SCHEDULED TASK]
* 1. Delete all Debug files from system/.restricted folder (format debug_@977827436@.txt)
* 2. Run MySQL OPTIMIZE SQL one by one on all In-Portal tables (found by prefix).
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnOptimizePerformance(kEvent &$event)
+ protected function OnOptimizePerformance(kEvent $event)
{
$start_time = adodb_mktime();
$sql = 'SELECT SessionKey
FROM ' . TABLE_PREFIX . 'UserSessions
WHERE LastAccessed > ' . $start_time;
$active_sessions = array_flip($this->Conn->GetCol($sql));
$files = scandir(RESTRICTED);
$file_path = RESTRICTED . '/';
foreach ($files AS $file_name) {
if ( !preg_match('#^debug_@([0-9]{9})@.txt$#', $file_name, $matches) ) {
// not debug file
continue;
}
$sid = $matches[1];
if ( isset($active_sessions[$sid]) || (filemtime($file_path . $file_name) > $start_time) ) {
// debug file belongs to an active session
// debug file is recently created (after sessions snapshot)
continue;
}
unlink($file_path . $file_name);
}
$system_tables = $this->Conn->GetCol('SHOW TABLES LIKE "' . TABLE_PREFIX . '%"');
foreach ($system_tables AS $table_name) {
$this->Conn->Query('OPTIMIZE TABLE ' . $table_name);
}
}
}
class UnitConfigDecorator {
var $parentPath = Array ();
/**
* Decorates given array
*
* @param Array $var
* @param int $level
* @return string
*/
public function decorate($var, $level = 0)
{
$ret = '';
$deep_level = count($this->parentPath);
if ( $deep_level && ($this->parentPath[0] == 'Fields') ) {
$expand = $level < 2;
}
elseif ( $deep_level && ($this->parentPath[0] == 'Grids') ) {
if ( $deep_level == 3 && $this->parentPath[2] == 'Icons' ) {
$expand = false;
}
else {
$expand = $level < 4;
}
}
else {
$expand = $level == 0;
}
if ( is_array($var) ) {
$ret .= 'Array (';
$prepend = $expand ? "\n" . str_repeat("\t", $level + 1) : '';
foreach ($var as $key => $value) {
array_push($this->parentPath, $key);
$ret .= $prepend . (is_string($key) ? "'" . $key . "'" : $key) . ' => ' . $this->decorate($value, $level + 1) . ', ';
array_pop($this->parentPath);
}
$prepend = $expand ? "\n" . str_repeat("\t", $level) : '';
$ret = rtrim($ret, ', ') . $prepend . ')';
}
else {
if ( is_null($var) ) {
$ret = 'NULL';
}
elseif ( is_string($var) ) {
$ret = "'" . $var . "'";
}
else {
$ret = $var;
}
}
return $ret;
}
}
\ No newline at end of file
Index: branches/5.2.x/core/units/admin/admin_tag_processor.php
===================================================================
--- branches/5.2.x/core/units/admin/admin_tag_processor.php (revision 15129)
+++ branches/5.2.x/core/units/admin/admin_tag_processor.php (revision 15130)
@@ -1,1122 +1,1122 @@
<?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 AdminTagProcessor extends kDBTagProcessor {
/**
* Allows to execute js script after the page is fully loaded
*
* @param Array $params
* @return string
*/
function AfterScript($params)
{
$after_script = $this->Application->GetVar('after_script');
if ($after_script) {
return '<script type="text/javascript">'.$after_script.'</script>';
}
return '';
}
/**
* Returns section title with #section# keyword replaced with current section
*
* @param Array $params
* @return string
*/
function GetSectionTitle($params)
{
if (array_key_exists('default', $params)) {
return $params['default'];
}
return $this->Application->Phrase( kUtil::replaceModuleSection($params['phrase']) );
}
/**
* Returns section icon with #section# keyword replaced with current section
*
* @param Array $params
* @return string
*/
function GetSectionIcon($params)
{
return kUtil::replaceModuleSection($params['icon']);
}
/**
* Returns version of module by name
*
* @param Array $params
* @return string
*/
function ModuleVersion($params)
{
return $this->Application->findModule('Name', $params['module'], 'Version');
}
/**
* Used in table form section drawing
*
* @param Array $params
* @return string
*/
function DrawTree($params)
{
static $deep_level = 0;
// when processings, then sort children by priority (key of children array)
$ret = '';
$section_name = $params['section_name'];
$params['name'] = $this->SelectParam($params, 'name,render_as,block');
$sections_helper =& $this->Application->recallObject('SectionsHelper');
/* @var $sections_helper kSectionsHelper */
$section_data =& $sections_helper->getSectionData($section_name);
$params['children_count'] = isset($section_data['children']) ? count($section_data['children']) : 0;
$params['deep_level'] = $deep_level++;
$template = $section_data['url']['t'];
unset($section_data['url']['t']);
$section_data['section_url'] = $this->Application->HREF($template, '', $section_data['url']);
$ret .= $this->Application->ParseBlock( array_merge($params, $section_data) );
if (!isset($section_data['children'])) {
return $ret;
}
ksort($section_data['children'], SORT_NUMERIC);
foreach ($section_data['children'] as $section_name) {
if (!$sections_helper->sectionVisible($section_name)) {
continue;
}
$params['section_name'] = $section_name;
$ret .= $this->DrawTree($params);
$deep_level--;
}
return $ret;
}
function SectionInfo($params)
{
$section = $params['section'];
if ($section == '#session#') {
$section = $this->Application->RecallVar('section');
}
$sections_helper =& $this->Application->recallObject('SectionsHelper');
/* @var $sections_helper kSectionsHelper */
$section_data =& $sections_helper->getSectionData($section);
if (!$section_data) {
throw new Exception('Use of undefined section "<strong>' . $section . '</strong>" in "<strong>' . __METHOD__ . '</strong>"');
return '';
}
if (array_key_exists('parent', $params) && $params['parent']) {
do {
$section = $section_data['parent'];
$section_data =& $sections_helper->getSectionData($section);
} while (array_key_exists('use_parent_header', $section_data) && $section_data['use_parent_header']);
}
$info = $params['info'];
switch ($info) {
case 'module_path':
if (isset($params['module']) && $params['module']) {
$module = $params['module'];
}
elseif (isset($section_data['icon_module'])) {
$module = $section_data['icon_module'];
}
else {
$module = '#session#';
}
$res = $this->ModulePath(array('module' => $module));
break;
case 'perm_section':
$res = $sections_helper->getPermSection($section);
break;
case 'label':
if ($section && ($section != 'in-portal:root')) {
// don't translate label for top section, because it's already translated
$no_editing = array_key_exists('no_editing', $params) ? $params['no_editing'] : false;
$res = $this->Application->Phrase($section_data['label'], !$no_editing);
}
else {
$res = '';
}
break;
default:
$res = $section_data[$info];
break;
}
if (array_key_exists('as_label', $params) && $params['as_label']) {
$res = $this->Application->Phrase($res);
}
return $res;
}
function PrintSection($params)
{
$section_name = $params['section_name'];
if ($section_name == '#session#') {
$section_name = $this->Application->RecallVar('section');
}
$sections_helper =& $this->Application->recallObject('SectionsHelper');
/* @var $sections_helper kSectionsHelper */
if (isset($params['use_first_child']) && $params['use_first_child']) {
$section_name = $sections_helper->getFirstChild($section_name, true);
}
$section_data =& $sections_helper->getSectionData($section_name);
$params['name'] = $this->SelectParam($params, 'name,render_as,block');
$params['section_name'] = $section_name;
$template = $section_data['url']['t'];
unset($section_data['url']['t']);
$section_data['section_url'] = $this->Application->HREF($template, '', $section_data['url']);
$ret = $this->Application->ParseBlock( array_merge($params, $section_data) );
return $ret;
}
/**
* Used in XML drawing for tree
*
* @param Array $params
* @return string
*/
function PrintSections($params)
{
// when processings, then sort children by priority (key of children array)
$ret = '';
$section_name = $params['section_name'];
if ($section_name == '#session#') {
$section_name = $this->Application->RecallVar('section');
}
$sections_helper =& $this->Application->recallObject('SectionsHelper');
/* @var $sections_helper kSectionsHelper */
$section_data =& $sections_helper->getSectionData($section_name);
$params['name'] = $this->SelectParam($params, 'name,render_as,block');
if (!isset($section_data['children'])) {
return '';
}
ksort($section_data['children'], SORT_NUMERIC);
foreach ($section_data['children'] as $section_name) {
$params['section_name'] = $section_name;
$section_data =& $sections_helper->getSectionData($section_name);
if (!$sections_helper->sectionVisible($section_name)) {
continue;
}
else {
$show_mode = isset($section_data['show_mode']) ? $section_data['show_mode'] : smNORMAL;
$section_data['debug_only'] = ($show_mode == smDEBUG) || ($show_mode == smSUPER_ADMIN) ? 1 : 0;
}
if (isset($section_data['tabs_only']) && $section_data['tabs_only']) {
$perm_status = false;
$folder_label = $section_data['label'];
ksort($section_data['children'], SORT_NUMERIC);
foreach ($section_data['children'] as $priority => $section_name) {
// if only tabs in this section & none of them have permission, then skip section too
$section_name = $sections_helper->getPermSection($section_name);
$perm_status = $this->Application->CheckPermission($section_name.'.view', 1);
if ($perm_status) {
break;
}
}
if (!$perm_status) {
// no permission for all tabs -> don't display tree node either
continue;
}
$params['section_name'] = $section_name;
$section_data =& $sections_helper->getSectionData($section_name);
$section_data['label'] = $folder_label; // use folder label in tree
$section_data['is_tab'] = 1;
}
else {
$section_name = $sections_helper->getPermSection($section_name);
if (!$this->Application->CheckPermission($section_name.'.view', 1)) continue;
}
$params['children_count'] = isset($section_data['children']) ? count($section_data['children']) : 0;
// remove template, so it doesn't appear as additional parameter in url
$template = $section_data['url']['t'];
unset($section_data['url']['t']);
$section_data['section_url'] = $this->Application->HREF($template, '', $section_data['url']);
$late_load = getArrayValue($section_data, 'late_load');
if ($late_load) {
$t = $late_load['t'];
unset($late_load['t']);
$section_data['late_load'] = $this->Application->HREF($t, '', $late_load);
$params['children_count'] = 99;
}
else {
$section_data['late_load'] = '';
}
// restore template
$section_data['url']['t'] = $template;
$ret .= $this->Application->ParseBlock( array_merge($params, $section_data) );
$params['section_name'] = $section_name;
}
return preg_replace("/\r\n|\n/", '', $ret);
}
function ListSectionPermissions($params)
{
$section_name = isset($params['section_name']) ? $params['section_name'] : $this->Application->GetVar('section_name');
$sections_helper =& $this->Application->recallObject('SectionsHelper');
/* @var $sections_helper kSectionsHelper */
$section_data =& $sections_helper->getSectionData($section_name);
$block_params = array_merge($section_data, Array('name' => $params['render_as'], 'section_name' => $section_name));
$ret = '';
foreach ($section_data['permissions'] as $perm_name) {
if (preg_match('/^advanced:(.*)/', $perm_name) != $params['type']) continue;
$block_params['perm_name'] = $perm_name;
$ret .= $this->Application->ParseBlock($block_params);
}
return $ret;
}
function ModuleInclude($params)
{
foreach ($params as $param_name => $param_value) {
$params[$param_name] = kUtil::replaceModuleSection($param_value);
}
return $this->Application->ProcessParsedTag('m', 'ModuleInclude', $params);
}
function TodayDate($params)
{
return date($params['format']);
}
function TreeEditWarrning($params)
{
$ret = $this->Application->Phrase($params['label']);
$ret = str_replace(Array('&lt;', '&gt;', 'br/', 'br /', "\n", "\r"), Array('<', '>', 'br', 'br', '', ''), $ret);
if (getArrayValue($params, 'escape')) {
$ret = addslashes($ret);
}
$ret = str_replace('<br>', '\n', $ret);
return $ret;
}
/**
* Draws section tabs using block name passed
*
* @param Array $params
*/
function ListTabs($params)
{
$sections_helper =& $this->Application->recallObject('SectionsHelper');
/* @var $sections_helper kSectionsHelper */
$section_data =& $sections_helper->getSectionData($params['section_name']);
$ret = '';
$block_params = Array('name' => $params['render_as']);
ksort($section_data['children'], SORT_NUMERIC);
foreach ($section_data['children'] as $priority => $section_name) {
$perm_section = $sections_helper->getPermSection($section_name);
if ( !$this->Application->CheckPermission($perm_section.'.view') ) {
continue;
}
$tab_data =& $sections_helper->getSectionData($section_name);
$block_params['t'] = $tab_data['url']['t'];
$block_params['title'] = $tab_data['label'];
$block_params['main_prefix'] = $section_data['SectionPrefix'];
$ret .= $this->Application->ParseBlock($block_params);
}
return $ret;
}
/**
* Returns list of module item tabs that have view permission in current category
*
* @param Array $params
*/
function ListCatalogTabs($params)
{
$ret = '';
$special = isset($params['special']) ? $params['special'] : '';
$replace_main = isset($params['replace_m']) && $params['replace_m'];
$skip_prefixes = isset($params['skip_prefixes']) ? explode(',', $params['skip_prefixes']) : Array();
$block_params = $this->prepareTagParams($params);
$block_params['name'] = $params['render_as'];
foreach ($this->Application->ModuleInfo as $module_name => $module_info) {
$prefix = $module_info['Var'];
if ($prefix == 'm' && $replace_main) {
$prefix = 'c';
}
if (in_array($prefix, $skip_prefixes) || !$this->Application->prefixRegistred($prefix) || !$this->Application->getUnitOption($prefix, 'CatalogItem')) {
continue;
}
$icon = $this->Application->getUnitOption($prefix, 'CatalogTabIcon');
if (strpos($icon, ':') !== false) {
list ($icon_module, $icon) = explode(':', $icon, 2);
}
else {
$icon_module = 'core';
}
$label = $this->Application->getUnitOption($prefix, $params['title_property']);
$block_params['title'] = $label;
$block_params['prefix'] = $prefix;
$block_params['icon_module'] = $icon_module;
$block_params['icon'] = $icon;
$ret .= $this->Application->ParseBlock($block_params);
}
return $ret;
}
/**
* Renders inividual catalog tab based on prefix and title_property given
*
* @param Array $params
* @return string
*/
function CatalogTab($params)
{
$icon = $this->Application->getUnitOption($params['prefix'], 'CatalogTabIcon');
if (strpos($icon, ':') !== false) {
list ($icon_module, $icon) = explode(':', $icon, 2);
}
else {
$icon_module = 'core';
}
$block_params = $this->prepareTagParams($params);
$block_params['name'] = $params['render_as'];
$block_params['icon_module'] = $icon_module;
$block_params['icon'] = $icon;
$block_params['title'] = $this->Application->getUnitOption($params['prefix'], $params['title_property']);
return $this->Application->ParseBlock($block_params);
}
/**
* Allows to construct link for opening any type of catalog item selector
*
* @param Array $params
* @return string
*/
function SelectorLink($params)
{
$mode = 'catalog';
if (isset($params['mode'])) { // {catalog, advanced_view}
$mode = $params['mode'];
unset($params['mode']);
}
$params['t'] = 'catalog/item_selector/item_selector_'.$mode;
$params['m_cat_id'] = $this->Application->getBaseCategory();
$default_params = Array('no_amp' => 1, 'pass' => 'all,'.$params['prefix']);
unset($params['prefix']);
$pass_through = Array();
if (isset($params['tabs_dependant'])) { // {yes, no}
$pass_through['td'] = $params['tabs_dependant'];
unset($params['tabs_dependant']);
}
if (isset($params['selection_mode'])) { // {single, multi}
$pass_through['tm'] = $params['selection_mode'];
unset($params['selection_mode']);
}
if (isset($params['tab_prefixes'])) { // {all, none, <comma separated prefix list>}
$pass_through['tp'] = $params['tab_prefixes'];
unset($params['tab_prefixes']);
}
if ($pass_through) {
// add pass_through to selector url if any
$params['pass_through'] = implode(',', array_keys($pass_through));
$params = array_merge($params, $pass_through);
}
// user can override default parameters (except pass_through of course)
$params = array_merge($default_params, $params);
return $this->Application->ProcessParsedTag('m', 'T', $params);
}
function TimeFrame($params)
{
$w = adodb_date('w');
$m = adodb_date('m');
$y = adodb_date('Y');
//FirstDayOfWeek is 0 for Sunday and 1 for Monday
$fdow = $this->Application->ConfigValue('FirstDayOfWeek');
if ( $fdow && $w == 0 ) {
$w = 7;
}
$today_start = adodb_mktime(0, 0, 0, adodb_date('m'), adodb_date('d'), $y);
$first_day_of_this_week = $today_start - ($w - $fdow) * 86400;
$first_day_of_this_month = adodb_mktime(0, 0, 0, $m, 1, $y);
$this_quater = ceil($m / 3);
$this_quater_start = adodb_mktime(0, 0, 0, $this_quater * 3 - 2, 1, $y);
switch ( $params['type'] ) {
case 'last_week_start':
$timestamp = $first_day_of_this_week - 86400 * 7;
break;
case 'last_week_end':
$timestamp = $first_day_of_this_week - 1;
break;
case 'last_month_start':
$timestamp = $m == 1 ? adodb_mktime(0, 0, 0, 12, 1, $y - 1) : adodb_mktime(0, 0, 0, $m - 1, 1, $y);
break;
case 'last_month_end':
$timestamp = $first_day_of_this_month = adodb_mktime(0, 0, 0, $m, 1, $y) - 1;
break;
case 'last_quater_start':
$timestamp = $this_quater == 1 ? adodb_mktime(0, 0, 0, 10, 1, $y - 1) : adodb_mktime(0, 0, 0, ($this_quater - 1) * 3 - 2, 1, $y);
break;
case 'last_quater_end':
$timestamp = $this_quater_start - 1;
break;
case 'last_6_months_start':
$timestamp = $m <= 6 ? adodb_mktime(0, 0, 0, $m + 6, 1, $y - 1) : adodb_mktime(0, 0, 0, $m - 6, 1, $y);
break;
case 'last_year_start':
$timestamp = adodb_mktime(0, 0, 0, 1, 1, $y - 1);
break;
case 'last_year_end':
$timestamp = adodb_mktime(23, 59, 59, 12, 31, $y - 1);
break;
default:
$timestamp = 0;
break;
}
if ( isset($params['format']) ) {
$format = $params['format'];
if ( preg_match("/_regional_(.*)/", $format, $regs) ) {
$lang =& $this->Application->recallObject('lang.current');
/* @var $lang LanguagesItem */
$format = $lang->GetDBField($regs[1]);
}
return adodb_date($format, $timestamp);
}
return $timestamp;
}
/**
* Redirect to cache rebuild template, when required by installator
*
* @param Array $params
*/
function CheckPermCache($params)
{
// we have separate session between install wizard and admin console, so store in cache
$global_mark = $this->Application->getDBCache('ForcePermCacheUpdate');
$local_mark = $this->Application->RecallVar('PermCache_UpdateRequired');
if ($global_mark || $local_mark) {
$this->Application->RemoveVar('PermCache_UpdateRequired');
if ($this->Application->ConfigValue('QuickCategoryPermissionRebuild')) {
$updater =& $this->Application->makeClass('kPermCacheUpdater');
/* @var $updater kPermCacheUpdater */
$updater->OneStepRun();
- $this->Application->HandleEvent($event, 'c:OnResetCMSMenuCache');
+ $this->Application->HandleEvent(new kEvent('c:OnResetCMSMenuCache'));
}
else {
// update with progress bar
return true;
}
}
return false;
}
/**
* Checks if current protocol is SSL
*
* @param Array $params
* @return int
*/
function IsSSL($params)
{
return (PROTOCOL == 'https://')? 1 : 0;
}
function PrintColumns($params)
{
$picker_helper =& $this->Application->RecallObject('ColumnPickerHelper');
$picker_helper->SetGridName($this->Application->GetLinkedVar('grid_name'));
/* @var $picker_helper kColumnPickerHelper */
$main_prefix = $this->Application->RecallVar('main_prefix');
$cols = $picker_helper->LoadColumns($main_prefix);
$this->Application->Phrases->AddCachedPhrase('__FREEZER__', '-------------');
$o = '';
if (isset($params['hidden']) && $params['hidden']) {
foreach ($cols['hidden_fields'] as $col) {
$title = $this->Application->Phrase($cols['titles'][$col]);
$o .= "<option value='$col'>".$title;
}
}
else {
foreach ($cols['order'] as $col) {
if (in_array($col, $cols['hidden_fields'])) continue;
$title = $this->Application->Phrase($cols['titles'][$col]);
$o .= "<option value='$col'>".$title;
}
}
return $o;
}
/**
* Allows to set popup size (key - current template name)
*
* @param Array $params
*/
function SetPopupSize($params)
{
$width = $params['width'];
$height = $params['height'];
if ($this->Application->GetVar('ajax') == 'yes') {
// during AJAX request just output size
die($width.'x'.$height);
}
if (!$this->UsePopups($params)) {
return ;
}
$t = $this->Application->GetVar('t');
$sql = 'SELECT *
FROM '.TABLE_PREFIX.'PopupSizes
WHERE TemplateName = '.$this->Conn->qstr($t);
$popup_info = $this->Conn->GetRow($sql);
if (!$popup_info) {
// create new popup size record
$fields_hash = Array (
'TemplateName' => $t,
'PopupWidth' => $width,
'PopupHeight' => $height,
);
$this->Conn->doInsert($fields_hash, TABLE_PREFIX.'PopupSizes');
}
elseif ($popup_info['PopupWidth'] != $width || $popup_info['PopupHeight'] != $height) {
// popup found and size in tag differs from one in db -> update in db
$fields_hash = Array (
'PopupWidth' => $width,
'PopupHeight' => $height,
);
$this->Conn->doUpdate($fields_hash, TABLE_PREFIX.'PopupSizes', 'PopupId = '.$popup_info['PopupId']);
}
}
/**
* Returns popup size (by template), if not cached, then parse template to get value
*
* @param Array $params
* @return string
*/
function GetPopupSize($params)
{
$t = $this->Application->GetVar('template_name');
$sql = 'SELECT *
FROM '.TABLE_PREFIX.'PopupSizes
WHERE TemplateName = '.$this->Conn->qstr($t);
$popup_info = $this->Conn->GetRow($sql);
if (!$popup_info) {
$this->Application->InitParser();
$this->Application->ParseBlock(array('name' => $t)); // dies when SetPopupSize tag found & in ajax requrest
return '750x400'; // tag SetPopupSize not found in template -> use default size
}
return $popup_info['PopupWidth'].'x'.$popup_info['PopupHeight'];
}
/**
* Allows to check if popups are generally enabled OR to check for "popup" or "modal" mode is enabled
*
* @param Array $params
* @return bool
*/
function UsePopups($params)
{
if ($this->Application->GetVar('_force_popup')) {
return true;
}
$use_popups = (int)$this->Application->ConfigValue('UsePopups');
if (array_key_exists('mode', $params)) {
$mode_mapping = Array ('popup' => 1, 'modal' => 2);
return $use_popups == $mode_mapping[ $params['mode'] ];
}
return $use_popups;
}
function UseToolbarLabels($params)
{
return (int)$this->Application->ConfigValue('UseToolbarLabels');
}
/**
* Checks if debug mode enabled (optionally) and specified constant is on
*
* @param Array $params
* @return bool
* @todo Could be a duplicate of kMainTagProcessor::ConstOn
*/
function ConstOn($params)
{
$constant_name = $this->SelectParam($params, 'name,const');
$debug_mode = isset($params['debug_mode']) && $params['debug_mode'] ? $this->Application->isDebugMode() : true;
return $debug_mode && kUtil::constOn($constant_name);
}
/**
* Builds link to last template in main frame of admin
*
* @param Array $params
* @return string
*/
function MainFrameLink($params)
{
$persistent = isset($params['persistent']) && $params['persistent'];
if ($persistent && $this->Application->ConfigValue('RememberLastAdminTemplate')) {
// check last_template in persistent session
$last_template = $this->Application->RecallPersistentVar('last_template_popup');
}
else {
// check last_template in session
$last_template = $this->Application->RecallVar('last_template_popup'); // because of m_opener=s there
}
if (!$last_template) {
$params['persistent'] = 1;
return $persistent ? false : $this->MainFrameLink($params);
}
list($index_file, $env) = explode('|', $last_template);
$vars = $this->Application->processQueryString($env, 'pass');
$recursion_templates = Array ('login', 'index', 'no_permission');
if (isset($vars['admin']) && $vars['admin'] == 1) {
// index template doesn't begin recursion on front-end (in admin frame)
$vars['m_theme'] = '';
if (isset($params['m_opener']) && $params['m_opener'] == 'r') {
// front-end link for highlighting purposes
$vars['t'] = 'index';
$vars['m_cat_id'] = $this->Application->getBaseCategory();
}
unset($recursion_templates[ array_search('index', $recursion_templates)]);
}
if (in_array($vars['t'], $recursion_templates)) {
// prevents redirect recursion OR old in-portal pages
$params['persistent'] = 1;
return $persistent ? false : $this->MainFrameLink($params);
}
$vars = array_merge($vars, $params);
$t = $vars['t'];
unset($vars['t'], $vars['persistent']);
// substitute language in link to current (link will work, even when language will be changed)
$vars['m_lang'] = $this->Application->GetVar('m_lang');
return $this->Application->HREF($t, '', $vars, $index_file);
}
/**
* Returns menu frame width or 200 in case, when invalid width specified in config
*
* @param Array $params
* @return string
*/
function MenuFrameWidth($params)
{
$width = (int)$this->Application->ConfigValue('MenuFrameWidth');
return $width > 0 ? $width : 200;
}
function AdminSkin($params)
{
$skin_helper =& $this->Application->recallObject('SkinHelper');
/* @var $skin_helper SkinHelper */
return $skin_helper->AdminSkinTag($params);
}
/**
* Prints errors, discovered during mass template compilation
*
* @param $params
* @return string
* @access protected
*/
protected function PrintCompileErrors($params)
{
$block_params = $this->prepareTagParams($params);
$block_params['name'] = $params['render_as'];
$errors = $this->Application->RecallVar('compile_errors');
if ( !$errors ) {
return '';
}
$ret = '';
$errors = unserialize($errors);
foreach ($errors as $an_error) {
$block_params['file'] = str_replace(FULL_PATH, '', $an_error['file']);
$block_params['line'] = $an_error['line'];
$block_params['message'] = $an_error['msg'];
$ret .= $this->Application->ParseBlock($block_params);
}
$this->Application->RemoveVar('compile_errors');
return $ret;
}
function CompileErrorCount($params)
{
$errors = $this->Application->RecallVar('compile_errors');
if (!$errors) {
return 0;
}
return count( unserialize($errors) );
}
function ExportData($params)
{
$export_helper =& $this->Application->recallObject('CSVHelper');
/* @var $export_helper kCSVHelper */
$result = $export_helper->ExportData( $this->SelectParam($params, 'var,name,field') );
return ($result === false) ? '' : $result;
}
function ImportData($params)
{
$import_helper =& $this->Application->recallObject('CSVHelper');
/* @var $import_helper kCSVHelper */
$result = $import_helper->ImportData( $this->SelectParam($params, 'var,name,field') );
return ($result === false) ? '' : $result;
}
function PrintCSVNotImportedLines($params)
{
$import_helper =& $this->Application->recallObject('CSVHelper');
/* @var $import_helper kCSVHelper */
return $import_helper->GetNotImportedLines();
}
/**
* Returns input field name to
* be placed on form (for correct
* event processing)
*
* @param Array $params
* @return string
* @access public
*/
function InputName($params)
{
list($id, $field) = $this->prepareInputName($params);
$ret = $this->getPrefixSpecial().'[0]['.$field.']'; // 0 always, as has no idfield
if( getArrayValue($params, 'as_preg') ) $ret = preg_quote($ret, '/');
return $ret;
}
/**
* Returns list of all backup file dates formatted
* in passed block
*
* @param Array $params
* @return string
* @access public
*/
function PrintBackupDates($params)
{
$backup_helper =& $this->Application->recallObject('BackupHelper');
/* @var $backup_helper BackupHelper */
$ret = '';
$dates = $backup_helper->getBackupFiles();
foreach ($dates as $date) {
$params['backuptimestamp'] = $date['filedate'];
$params['backuptime'] = date('F j, Y, g:i a', $date['filedate']);
$params['backupsize'] = round($date['filesize'] / 1024 / 1024, 2); // MBytes
$ret .= $this->Application->ParseBlock($params);
}
return $ret;
}
/**
* Returns phpinfo() output
*
* @param Array $params
* @return string
*/
function PrintPHPinfo($params)
{
ob_start();
phpinfo();
return ob_get_clean();
}
function PrintSqlCols($params)
{
$a_data = unserialize($this->Application->GetVar('sql_rows'));
$ret = '';
$block = $params['render_as'];
foreach ($a_data AS $a_row)
{
foreach ($a_row AS $col => $value)
{
$ret .= $this->Application->ParseBlock(Array('name'=>$block, 'value'=>$col));
}
break;
}
return $ret;
}
function PrintSqlRows($params)
{
$a_data = unserialize($this->Application->GetVar('sql_rows'));
$ret = '';
$block = $params['render_as'];
foreach ($a_data AS $a_row)
{
$cells = '';
foreach ($a_row AS $col => $value)
{
$cells .= '<td>'.$value.'</td>';
}
$ret .= $this->Application->ParseBlock(Array('name'=>$block, 'cells'=>$cells));
}
return $ret;
}
/**
* Prints available and enabled import sources using given block
*
* @param Array $params
* @return string
*/
function PrintImportSources($params)
{
$sql = 'SELECT *
FROM ' . TABLE_PREFIX . 'ImportScripts
WHERE (Status = ' . STATUS_ACTIVE . ') AND (Type = "CSV")';
$import_sources = $this->Conn->Query($sql);
$block_params = $this->prepareTagParams($params);
$block_params['name'] = $params['render_as'];
$ret = '';
foreach ($import_sources as $import_source) {
$block_params['script_id'] = $import_source['ImportId'];
$block_params['script_module'] = mb_strtolower($import_source['Module']);
$block_params['script_name'] = $import_source['Name'];
$block_params['script_prefix'] = $import_source['Prefix'];
$block_params['module_path'] = $this->Application->findModule('Name', $import_source['Module'], 'Path');
$ret .= $this->Application->ParseBlock($block_params);
}
return $ret;
}
/**
* Checks, that new window should be opened in "incs/close_popup" template instead of refreshing parent window
*
* @param Array $params
* @return bool
*/
function OpenNewWindow($params)
{
if (!$this->UsePopups($params)) {
return false;
}
$diff = array_key_exists('diff', $params) ? $params['diff'] : 0;
$wid = $this->Application->GetVar('m_wid');
$stack_name = rtrim('opener_stack_' . $wid, '_');
$opener_stack = $this->Application->RecallVar($stack_name);
$opener_stack = $opener_stack ? unserialize($opener_stack) : Array ();
return count($opener_stack) >= 2 - $diff;
}
/**
* Allows to dynamically change current language in template
*
* @param Array $params
*/
function SetLanguage($params)
{
$this->Application->SetVar('m_lang', $params['language_id']);
$this->Application->Phrases->Init('phrases', '', $params['language_id']);
}
/**
* Performs HTTP Authentification for administrative console
*
* @param Array $params
*/
function HTTPAuth($params)
{
if (!$this->Application->ConfigValue('UseHTTPAuth')) {
// http authentification not required
return true;
}
$super_admin_ips = defined('SA_IP') ? SA_IP : false;
$auth_bypass_ips = $this->Application->ConfigValue('HTTPAuthBypassIPs');
if (($auth_bypass_ips && kUtil::ipMatch($auth_bypass_ips)) || ($super_admin_ips && kUtil::ipMatch($super_admin_ips))) {
// user ip is in ip bypass list
return true;
}
if (!array_key_exists('PHP_AUTH_USER', $_SERVER)) {
// ask user to authentificate, when not authentificated before
return $this->_httpAuthentificate();
}
else {
// validate user credentials (browsers remembers user/password
// and sends them each time page is visited, so no need to save
// authentification result in session)
if ($this->Application->ConfigValue('HTTPAuthUsername') != $_SERVER['PHP_AUTH_USER']) {
// incorrect username
return $this->_httpAuthentificate();
}
$password_formatter =& $this->Application->recallObject('kPasswordFormatter');
/* @var $password_formatter kPasswordFormatter */
$password = $password_formatter->EncryptPassword($_SERVER['PHP_AUTH_PW'], 'b38');
if ($this->Application->ConfigValue('HTTPAuthPassword') != $password) {
// incorrect password
return $this->_httpAuthentificate();
}
}
return true;
}
/**
* Ask user to authentificate
*
* @return false
*/
function _httpAuthentificate()
{
$realm = strip_tags( $this->Application->ConfigValue('Site_Name') );
header('WWW-Authenticate: Basic realm="' . $realm . '"');
header('HTTP/1.0 401 Unauthorized');
return false;
}
/**
* Checks, that we are using memory cache
*
* @param Array $params
* @return bool
*/
function MemoryCacheEnabled($params)
{
return $this->Application->isCachingType(CACHING_TYPE_MEMORY);
}
}
\ No newline at end of file
Index: branches/5.2.x/core/units/config_search/config_search_event_handler.php
===================================================================
--- branches/5.2.x/core/units/config_search/config_search_event_handler.php (revision 15129)
+++ branches/5.2.x/core/units/config_search/config_search_event_handler.php (revision 15130)
@@ -1,154 +1,154 @@
<?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 ConfigSearchEventHandler extends kDBEventHandler {
/**
* Changes permission section to one from REQUEST, not from config
*
* @param kEvent $event
* @return bool
* @access public
*/
- public function CheckPermission(kEvent &$event)
+ public function CheckPermission(kEvent $event)
{
$module = $this->Application->GetVar('module');
$main_prefix = $this->Application->findModule('Name', $module, 'Var');
$section = $this->Application->getUnitOption($main_prefix.'.search', 'PermSection');
$event->setEventParam('PermSection', $section);
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(kEvent &$event)
+ protected function SetCustomQuery(kEvent $event)
{
parent::SetCustomQuery($event);
$object =& $event->getObject();
/* @var $object kDBList */
// show only items that belong to selected module
$module = $this->Application->GetVar('module');
$object->addFilter('module_filter', '%1$s.ModuleName = ' . $this->Conn->qstr($module));
// don't show disabled search items
$object->addFilter('active_filter', '%1$s.SimpleSearch <> -1');
}
/**
* Updates kDBItem
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnUpdate(kEvent &$event)
+ protected function OnUpdate(kEvent $event)
{
if ($this->Application->CheckPermission('SYSTEM_ACCESS.READONLY', 1)) {
$event->status = kEvent::erFAIL;
return ;
}
parent::OnUpdate($event);
$conf_update = new kEvent('conf:OnUpdate');
$conf_update->redirect = false;
$this->Application->HandleEvent($conf_update);
$event->SetRedirectParam('opener', 's');
// keeps module and section in REQUEST to ensure, that last admin template will work
$event->SetRedirectParam('module', $this->Application->GetVar('module'));
$event->SetRedirectParam('module_key', $this->Application->GetVar('module_key'));
$event->SetRedirectParam('section', $this->Application->GetVar('section'));
}
/**
* Cancels kDBItem Editing/Creation
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnCancel(kEvent &$event)
+ protected function OnCancel(kEvent $event)
{
parent::OnCancel($event);
$event->SetRedirectParam('opener', 's');
}
/**
* [HOOK] Creates search config record corresponding to custom field, that was just created
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnCreateCustomField(&$event)
+ protected function OnCreateCustomField($event)
{
$custom_field =& $event->MasterEvent->getObject();
/* @var $custom_field kDBItem */
if ( $custom_field->GetDBField('Type') == 6 || $custom_field->GetDBField('IsSystem') == 1 ) {
// user & system custom fields are not searchable
return ;
}
$object =& $event->getObject(Array ('skip_autoload' => true));
/* @var $object kDBItem */
$custom_id = $custom_field->GetID();
if ( !$object->isLoaded() || ($object->GetDBField('CustomFieldId') != $custom_id) ) {
$object->Load($custom_id, 'CustomFieldId');
}
$cf_search = Array ();
$element_type = $custom_field->GetDBField('ElementType');
$cf_search['DisplayOrder'] = $custom_field->GetDBField('DisplayOrder');
$cf_search['FieldType'] = $element_type;
$cf_search['DisplayName'] = $custom_field->GetDBField('FieldLabel');
$cf_search['FieldName'] = $custom_field->GetDBField('FieldName');
$cf_search['Description'] = $custom_field->GetDBField('Prompt');
$cf_search['ConfigHeader'] = $custom_field->GetDBField('Heading'); // 'la_Text_CustomFields';
$cf_search['SimpleSearch'] = in_array($element_type, Array ('text', 'range', 'select', 'multiselect')) ? 1 : 0;
$cf_search['TableName'] = 'CustomFields';
$sql = 'SELECT Module
FROM ' . TABLE_PREFIX . 'ItemTypes
WHERE ItemType = ' . $custom_field->GetDBField('Type');
$cf_search['ModuleName'] = $this->Conn->GetOne($sql);
$object->SetFieldsFromHash($cf_search);
$object->SetDBField('CustomFieldId', $custom_id);
if ( $object->isLoaded() ) {
$object->Update();
}
else {
$object->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 15129)
+++ branches/5.2.x/core/units/user_profile/user_profile_eh.php (revision 15130)
@@ -1,93 +1,93 @@
<?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 standard permission mapping
*
* @return void
* @access protected
* @see kEventHandler::$permMapping
*/
protected 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
* @return void
* @access protected
*/
- protected function OnUpdate(kEvent &$event)
+ protected function OnUpdate(kEvent $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/relationship/relationship_event_handler.php
===================================================================
--- branches/5.2.x/core/units/relationship/relationship_event_handler.php (revision 15129)
+++ branches/5.2.x/core/units/relationship/relationship_event_handler.php (revision 15130)
@@ -1,300 +1,300 @@
<?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 RelationshipEventHandler extends kDBEventHandler
{
/**
* Allows to override standard permission mapping
*
* @return void
* @access protected
* @see kEventHandler::$permMapping
*/
protected function mapPermissions()
{
parent::mapPermissions();
$permissions = Array (
'OnProcessSelected' => Array ('subitem' => 'add|edit')
);
$this->permMapping = array_merge($this->permMapping, $permissions);
}
/**
* Initializes new relation
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnNew(kEvent &$event)
+ protected function OnNew(kEvent $event)
{
parent::OnNew($event);
$object =& $event->getObject();
/* @var $object kDBItem */
$table_info = $object->getLinkedInfo();
$object->SetDBField('SourceId', $table_info['ParentId']);
$source_itemtype = $this->Application->getUnitOption($table_info['ParentPrefix'], 'ItemType');
$object->SetDBField('SourceType', $source_itemtype);
$object->SetDBField('TargetId', $this->Application->GetVar('target_id'));
$object->SetDBField('TargetType', $this->Application->GetVar('target_type'));
$this->OnAfterItemLoad($event);
}
/**
* Add new relation
*
* @param kEvent $event
*/
- function OnProcessSelected(&$event)
+ function OnProcessSelected($event)
{
$dst_field = $this->Application->RecallVar('dst_field');
if ( $dst_field == 'TargetId' ) {
// prepare target_id & target_type
$object =& $event->getObject(Array ('skip_autoload' => true));
$target_id = 0;
$target_prefix = false;
$selected_ids = $this->Application->GetVar('selected_ids');
foreach ($selected_ids as $selected_prefix => $target_id) {
if ( $target_id > 0 ) {
$target_prefix = $selected_prefix;
break;
}
}
if ( !$target_prefix ) {
$event->SetRedirectParam('opener', 'u');
return;
}
$sql = 'SELECT ResourceId
FROM ' . $this->Application->getUnitOption($target_prefix, 'TableName') . '
WHERE ' . $this->Application->getUnitOption($target_prefix, 'IDField') . ' IN (' . $target_id . ')';
$target_id = $this->Conn->GetOne($sql);
$target_type = $this->Application->getUnitOption($target_prefix, 'ItemType');
// don't add same relation twice
$table_info = $object->getLinkedInfo();
$sql = 'SELECT TargetId
FROM ' . $object->TableName . '
WHERE (SourceId = ' . $table_info['ParentId'] . ') AND (TargetId = ' . $target_id . ')';
$duplicate_relation = $this->Conn->GetOne($sql) == $target_id;
$event->SetRedirectParam('opener', 'u');
if ( !$duplicate_relation ) {
// place correct template in opener stack
$source_prefix = $this->Application->getUnitOption($event->Prefix, 'ParentPrefix');
$template = $this->Application->getUnitOption($source_prefix, 'AdminTemplatePath') . '/relations_edit';
$redirect_params = Array (
$event->Prefix . '_event' => 'OnNew',
'target_id' => $target_id,
'm_opener' => 's',
'target_type' => $target_type,
'pass' => 'all,' . $event->Prefix,
);
$this->Application->EventManager->openerStackPush($template, $redirect_params);
}
}
else {
$event->SetRedirectParam('opener', 'u');
}
}
/**
* Set ItemName & ItemType virtual fields based on loaded item data
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnAfterItemLoad(kEvent &$event)
+ protected function OnAfterItemLoad(kEvent $event)
{
parent::OnAfterItemLoad($event);
$object =& $event->getObject();
/* @var $object kDBItem */
$sql = 'SELECT Prefix
FROM ' . TABLE_PREFIX . 'ItemTypes
WHERE ItemType = ' . $object->GetDBField('TargetType');
$target_prefix = $this->Conn->GetOne($sql);
$title_field = $this->getTitleField($target_prefix);
$title_phrase = $this->Application->getUnitOption($target_prefix, 'TitlePhrase');
$sql = 'SELECT ' . $title_field . '
FROM ' . $this->Application->getUnitOption($target_prefix, 'TableName') . '
WHERE ResourceId = ' . $object->GetDBField('TargetId');
$object->SetDBField('ItemName', $this->Conn->GetOne($sql));
$object->SetDBField('ItemType', $this->Application->Phrase($title_phrase));
}
/**
* Creates needed sql query to load list,
* if no query is defined in config for
* special requested, then use default
* query
*
* @param kEvent $event
* @return string
* @access protected
*/
- protected function ListPrepareQuery(kEvent &$event)
+ protected function ListPrepareQuery(kEvent $event)
{
return $this->BaseQuery($event, 'ListSQLs');
}
/**
* Creates needed sql query to load item,
* if no query is defined in config for
* special requested, then use list query
*
* @param kEvent $event
* @return string
* @access protected
*/
- protected function ItemPrepareQuery(kEvent &$event)
+ protected function ItemPrepareQuery(kEvent $event)
{
return $this->BaseQuery($event, 'ItemSQLs');
}
/**
* Get item name & type based on relation type & modules installed
*
* @param kEvent $event
* @param string $sql_field
*/
- function BaseQuery(&$event, $sql_field)
+ function BaseQuery($event, $sql_field)
{
$sqls = $this->Application->getUnitOption($event->Prefix,$sql_field);
$sql = isset($sqls[$event->Special]) ? $sqls[$event->Special] : $sqls[''];
$configs = $this->extractModulesInfo();
// 2. build sql based on information queried
$sql_templates['ItemName'] = 'IFNULL(%s.%s,\' \')';
$sql_templates['TableJoin'] = 'LEFT JOIN %1$s ON %1$s.ResourceId = rel.TargetId';
$sql_templates['TargetName'] = 'IF(rel.TargetType = %s, \'%s\', %s)';
$sql_parts = Array();
$sql_parts['TargetName'] = "''";
foreach ($configs as $prefix => $config_data) {
$title_field = $this->getTitleField($prefix);
$sql_parts['ItemName'][] = sprintf($sql_templates['ItemName'], $config_data['TableName'], $title_field);
$sql_parts['TableJoin'][] = sprintf($sql_templates['TableJoin'], $config_data['TableName']);
$sql_parts['TargetName'] = sprintf( $sql_templates['TargetName'],
$config_data['ItemType'],
'!'.$config_data['TitlePhrase'].'!',
$sql_parts['TargetName']);
$sql_parts['TargetName'] = str_replace('rel','%1$s',$sql_parts['TargetName']);
}
$object =& $event->getObject();
$vars = Array('#ITEM_NAMES#', '#ITEM_TYPES#');
$replacements = Array( implode(', ',$sql_parts['ItemName']), $sql_parts['TargetName'] );
$calculated_fields = $object->getCalculatedFields();
foreach ($calculated_fields as $field_name => $field_expression) {
$calculated_fields[$field_name] = str_replace($vars, $replacements, $field_expression);
}
$object->setCalculatedFields($calculated_fields);
$sql = str_replace('#ITEM_JOIN#', implode(' ',$sql_parts['TableJoin']), $sql);
$sql = str_replace('rel.','%1$s.',$sql);
return $sql;
}
/**
* Convert TitleField field of kMultiLanguage formatter used for it
*
* @param string $prefix
* @return string
*/
function getTitleField($prefix)
{
$lang_prefix = 'l'.$this->Application->GetVar('m_lang').'_';
$title_field = $this->Application->getUnitOption($prefix, 'TitleField');
$field_options = $this->Application->getUnitOption($prefix.'.'.$title_field, 'Fields');
$formatter_class = isset($field_options['formatter']) ? $field_options['formatter'] : '';
if ($formatter_class == 'kMultiLanguage' && !isset($field_options['master_field'])) {
$title_field = $lang_prefix.$title_field;
}
return $title_field;
}
/**
* Get configs from modules installed
*
* @return Array
* @access private
*/
function extractModulesInfo()
{
// get installed modules & their config info
// maybe we should leave only prefixes, that have "view" permission
$configs = Array();
foreach ($this->Application->ModuleInfo as $module_name => $module_data) {
$prefix = $module_data['Var'];
if ($prefix == 'm') {
$prefix = 'c';
}
if (!$this->Application->prefixRegistred($prefix)) continue;
$configs[$prefix] = $this->Application->getUnitOptions($prefix);
if($configs[$prefix] === false) unset($configs[$prefix]);
if(!isset($configs[$prefix]['CatalogItem']) || !$configs[$prefix]['CatalogItem']) unset($configs[$prefix]);
}
return $configs;
}
/**
* Deletes relations to hooked item from other items
*
* @param kEvent $event
*/
- function OnDeleteForeignRelations(&$event)
+ function OnDeleteForeignRelations($event)
{
$main_object =& $event->MasterEvent->getObject();
/* @var $main_object kDBItem */
$sql = 'DELETE FROM ' . $this->Application->getUnitOption($event->Prefix, 'TableName') . '
WHERE TargetId = ' . $main_object->GetDBField('ResourceId');
$this->Conn->Query($sql);
}
}
\ No newline at end of file
Index: branches/5.2.x/core/units/captcha/captcha_eh.php
===================================================================
--- branches/5.2.x/core/units/captcha/captcha_eh.php (revision 15129)
+++ branches/5.2.x/core/units/captcha/captcha_eh.php (revision 15130)
@@ -1,47 +1,47 @@
<?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 CaptchaEventHandler extends kEventHandler {
/**
* [HOOK] Validates captcha code in item
*
* @param kEvent $event
*/
- function OnValidateCode(&$event)
+ function OnValidateCode($event)
{
$captcha_helper =& $this->Application->recallObject('CaptchaHelper');
/* @var $captcha_helper kCaptchaHelper */
$captcha_helper->validateCode($event->MasterEvent);
}
/**
* [HOOK] Initializes captcha code processing routine
*
* @param kEvent $event
*/
- function OnPrepareCaptcha(&$event)
+ function OnPrepareCaptcha($event)
{
$captcha_helper =& $this->Application->recallObject('CaptchaHelper');
/* @var $captcha_helper kCaptchaHelper */
// create field for captcha code storage
$virtual_fields = $this->Application->getUnitOption($event->MasterEvent->Prefix, 'VirtualFields');
$virtual_fields['Captcha'] = Array ('type' => 'string', 'default' => '');
$this->Application->setUnitOption($event->MasterEvent->Prefix, 'VirtualFields', $virtual_fields);
}
}
Index: branches/5.2.x/core/units/phrases/phrases_event_handler.php
===================================================================
--- branches/5.2.x/core/units/phrases/phrases_event_handler.php (revision 15129)
+++ branches/5.2.x/core/units/phrases/phrases_event_handler.php (revision 15130)
@@ -1,497 +1,497 @@
<?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 PhrasesEventHandler extends kDBEventHandler
{
/**
* Allows to override standard permission mapping
*
* @return void
* @access protected
* @see kEventHandler::$permMapping
*/
protected function mapPermissions()
{
parent::mapPermissions();
$permissions = Array (
'OnItemBuild' => Array ('self' => true, 'subitem' => true),
'OnPreparePhrase' => Array ('self' => true, 'subitem' => true),
'OnExportPhrases' => Array ('self' => 'view'),
);
$this->permMapping = array_merge($this->permMapping, $permissions);
}
/**
* 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, kEvent &$event)
+ protected function prepareObject(&$object, kEvent $event)
{
// don't call parent
if ( $event->Special == 'import' || $event->Special == 'export' ) {
$this->RemoveRequiredFields($object);
$object->setRequired(Array ('LangFile', 'PhraseType', 'Module'));
// allow multiple phrase types to be selected during import/export
$object->SetFieldOption('PhraseType', 'type', 'string');
}
}
/**
* Allow to create phrases from front end in debug mode with DBG_PHRASES constant set
*
* @param kEvent $event
* @return bool
* @access public
*/
- public function CheckPermission(kEvent &$event)
+ public function CheckPermission(kEvent $event)
{
if ( !$this->Application->isAdmin && $this->Application->isDebugMode(false) && kUtil::constOn('DBG_PHRASES') ) {
$allow_events = Array ('OnCreate', 'OnUpdate');
if ( in_array($event->Name, $allow_events) ) {
return true;
}
}
return parent::CheckPermission($event);
}
/**
* Prepares phrase for translation
*
* @param kEvent $event
*/
- function OnPreparePhrase(&$event)
+ function OnPreparePhrase($event)
{
$label = $this->Application->GetVar($event->getPrefixSpecial() . '_label');
if (!$label) {
return ;
}
// we got label, try to get it's ID then if any
$phrase_id = $this->_getPhraseId($label);
if ($phrase_id) {
$event->SetRedirectParam($event->getPrefixSpecial(true) . '_id', $phrase_id);
$event->SetRedirectParam('pass', 'm,' . $event->getPrefixSpecial());
$next_template = $this->Application->GetVar('next_template');
if ($next_template) {
$event->SetRedirectParam('next_template', $next_template);
}
}
else {
$event->CallSubEvent('OnNew');
}
if ($this->Application->GetVar('simple_mode')) {
$event->SetRedirectParam('simple_mode', 1);
}
}
function _getPhraseId($phrase)
{
$sql = 'SELECT ' . $this->Application->getUnitOption($this->Prefix, 'IDField') . '
FROM ' . $this->Application->getUnitOption($this->Prefix, 'TableName') . '
WHERE PhraseKey = ' . $this->Conn->qstr( mb_strtoupper($phrase) );
return $this->Conn->GetOne($sql);
}
/**
* Sets phrase type based on place where it's created (to display on form only)
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnPreCreate(kEvent &$event)
+ protected function OnPreCreate(kEvent $event)
{
parent::OnPreCreate($event);
$object =& $event->getObject();
/* @var $object kDBItem */
$this->_setPhraseModule($object);
}
/**
* Forces new label in case if issued from get link
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnNew(kEvent &$event)
+ protected function OnNew(kEvent $event)
{
parent::OnNew($event);
$object =& $event->getObject();
/* @var $object kDBItem */
$label = $this->Application->GetVar($event->getPrefixSpecial() . '_label');
if ( $label ) {
// phrase is created in language, used to display phrases
$object->SetDBField('Phrase', $label);
$object->SetDBField('PhraseType', $this->_getPhraseType($label)); // to show on form
$object->SetDBField('PrimaryTranslation', $this->_getPrimaryTranslation($label));
}
$this->_setPhraseModule($object);
if ( $event->Special == 'export' || $event->Special == 'import' ) {
$object->SetDBField('PhraseType', '|0|1|2|');
$object->SetDBField('Module', '|' . implode('|', array_keys($this->Application->ModuleInfo)) . '|');
}
}
/**
* Returns given phrase translation on primary language
*
* @param string $phrase
* @return string
* @access protected
*/
protected function _getPrimaryTranslation($phrase)
{
$sql = 'SELECT l' . $this->Application->GetDefaultLanguageId() . '_Translation
FROM ' . $this->Application->getUnitOption($this->Prefix, 'TableName') . '
WHERE PhraseKey = ' . $this->Conn->qstr( mb_strtoupper($phrase) );
return $this->Conn->GetOne($sql);
}
/**
* Sets new phrase module
*
* @param kDBItem $object
* @return void
* @access protected
*/
protected function _setPhraseModule(&$object)
{
$last_module = $this->Application->GetVar('last_module');
if ( $last_module ) {
$object->SetDBField('Module', $last_module);
}
}
/**
* Forces create to use live table
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnCreate(kEvent &$event)
+ protected function OnCreate(kEvent $event)
{
if ( $this->Application->GetVar($event->Prefix . '_label') ) {
$object =& $event->getObject(Array ('skip_autoload' => true));
/* @var $object kDBItem */
if ( $this->Application->GetVar('m_lang') != $this->Application->GetVar('lang_id') ) {
$object->SwitchToLive();
}
$this->returnToOriginalTemplate($event);
}
parent::OnCreate($event);
}
/**
* Redirects to original template after phrase is being update
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnUpdate(kEvent &$event)
+ protected function OnUpdate(kEvent $event)
{
if ( $this->Application->GetVar($event->Prefix . '_label') ) {
$this->returnToOriginalTemplate($event);
}
parent::OnUpdate($event);
}
/**
* Returns to original template after phrase adding/editing
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function returnToOriginalTemplate(kEvent &$event)
+ protected function returnToOriginalTemplate(kEvent $event)
{
$next_template = $this->Application->GetVar('next_template');
if ( $next_template ) {
$event->redirect = $next_template;
$event->SetRedirectParam('opener', 's');
}
}
/**
* Set last change info, when phrase is created
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnBeforeItemCreate(kEvent &$event)
+ protected function OnBeforeItemCreate(kEvent $event)
{
parent::OnBeforeItemCreate($event);
$object =& $event->getObject();
/* @var $object kDBItem */
$primary_language_id = $this->Application->GetDefaultLanguageId();
if ( !$object->GetDBField('l' . $primary_language_id . '_Translation') ) {
// no translation on primary language -> try to copy from other language
$src_languages = Array ('lang_id', 'm_lang'); // editable language, theme language
foreach ($src_languages as $src_language) {
$src_language = $this->Application->GetVar($src_language);
$src_value = $src_language ? $object->GetDBField('l' . $src_language . '_Translation') : false;
if ( $src_value ) {
$object->SetDBField('l' . $primary_language_id . '_Translation', $src_value);
break;
}
}
}
$this->_phraseChanged($event);
}
/**
* Update last change info, when phrase is updated
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnBeforeItemUpdate(kEvent &$event)
+ protected function OnBeforeItemUpdate(kEvent $event)
{
parent::OnBeforeItemUpdate($event);
$this->_phraseChanged($event);
}
/**
* Set's phrase key and last change info, used for phrase updating and loading
*
* @param kEvent $event
*/
- function _phraseChanged(&$event)
+ function _phraseChanged($event)
{
$object =& $event->getObject();
/* @var $object kDBItem */
$label = $object->GetDBField('Phrase');
$object->SetDBField('PhraseKey', mb_strtoupper($label));
$object->SetDBField('PhraseType', $this->_getPhraseType($label));
if ( $this->translationChanged($object) ) {
$object->SetDBField('LastChanged_date', adodb_mktime() );
$object->SetDBField('LastChanged_time', adodb_mktime() );
$object->SetDBField('LastChangeIP', $_SERVER['REMOTE_ADDR']);
}
$this->Application->Session->SetCookie('last_module', $object->GetDBField('Module'));
}
/**
* Returns phrase type, that corresponds given phrase label
*
* @param string $label
* @return int
* @access protected
*/
protected function _getPhraseType($label)
{
$phrase_type_map = Array (
'LU' => Language::PHRASE_TYPE_FRONT,
'LA' => Language::PHRASE_TYPE_ADMIN,
'LC' => Language::PHRASE_TYPE_COMMON
);
$label = mb_strtoupper($label);
$label_prefix = substr($label, 0, 2);
return isset($phrase_type_map[$label_prefix]) ? $phrase_type_map[$label_prefix] : Language::PHRASE_TYPE_COMMON;
}
/**
* Checks, that at least one of phrase's translations was changed
*
* @param kDBItem $object
* @return bool
*/
function translationChanged(&$object)
{
$changed_fields = array_keys( $object->GetChangedFields() );
$translation_fields = Array ('Translation', 'HintTranslation', 'ColumnTranslation');
foreach ($changed_fields as $changed_field) {
$changed_field = preg_replace('/^l[\d]+_/', '', $changed_field);
if ( in_array($changed_field, $translation_fields) ) {
return true;
}
}
return false;
}
/**
* Changes default module to custom (when available)
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnAfterConfigRead(kEvent &$event)
+ protected function OnAfterConfigRead(kEvent $event)
{
parent::OnAfterConfigRead($event);
if ($this->Application->findModule('Name', 'Custom')) {
$fields = $this->Application->getUnitOption($event->Prefix, 'Fields');
$fields['Module']['default'] = 'Custom';
$this->Application->setUnitOption($event->Prefix, 'Fields', $fields);
}
// make sure, that PrimaryTranslation column always refrers to primary language column
$language_id = $this->Application->GetVar('lang_id');
if (!$language_id) {
$language_id = $this->Application->GetVar('m_lang');
}
$primary_language_id = $this->Application->GetDefaultLanguageId();
$calculated_fields = $this->Application->getUnitOption($event->Prefix, 'CalculatedFields');
foreach ($calculated_fields[''] as $field_name => $field_expression) {
$field_expression = str_replace('%5$s', $language_id, $field_expression);
$field_expression = str_replace('%4$s', $primary_language_id, $field_expression);
$calculated_fields[''][$field_name] = $field_expression;
}
$this->Application->setUnitOption($event->Prefix, 'CalculatedFields', $calculated_fields);
if ($this->Application->GetVar('regional')) {
$this->Application->setUnitOption($event->Prefix, 'PopulateMlFields', true);
}
}
/**
* Saves changes & changes language
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnPreSaveAndChangeLanguage(kEvent &$event)
+ protected function OnPreSaveAndChangeLanguage(kEvent $event)
{
$label = $this->Application->GetVar($event->getPrefixSpecial() . '_label');
if ( $label && !$this->UseTempTables($event) ) {
$phrase_id = $this->_getPhraseId($label);
if ( $phrase_id ) {
$event->CallSubEvent('OnUpdate');
$event->SetRedirectParam('opener', 's');
}
else {
$event->CallSubEvent('OnCreate');
$event->SetRedirectParam('opener', 's');
}
if ( $event->status != kEvent::erSUCCESS ) {
return;
}
$event->SetRedirectParam($event->getPrefixSpecial() . '_event', 'OnPreparePhrase');
$event->SetRedirectParam('pass_events', true);
}
if ( $this->Application->GetVar('simple_mode') ) {
$event->SetRedirectParam('simple_mode', 1);
}
parent::OnPreSaveAndChangeLanguage($event);
}
/**
* Prepare temp tables and populate it
* with items selected in the grid
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnEdit(kEvent &$event)
+ protected function OnEdit(kEvent $event)
{
parent::OnEdit($event);
// use language from grid, instead of primary language used by default
$event->SetRedirectParam('m_lang', $this->Application->GetVar('m_lang'));
}
/**
* Stores ids of selected phrases and redirects to export language step 1
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnExportPhrases(kEvent &$event)
+ protected function OnExportPhrases(kEvent $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', $this->Application->GetVar('m_lang'));
$event->setRedirectParams(
Array (
'phrases.export_event' => 'OnNew',
'pass' => 'all,phrases.export',
'export_mode' => $event->Prefix,
)
);
}
}
\ 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 15129)
+++ branches/5.2.x/core/units/languages/languages_event_handler.php (revision 15130)
@@ -1,685 +1,685 @@
<?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 standard permission mapping
*
* @return void
* @access protected
* @see kEventHandler::$permMapping
*/
protected 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(kEvent &$event)
+ public function CheckPermission(kEvent $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
* @return int
* @access public
*/
- public function getPassedID(kEvent &$event)
+ public function getPassedID(kEvent $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)
+ 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 */
$ml_helper->massCreateFields();
$event->SetRedirectParam('action_completed', 1);
}
/**
* Allows to set selected language as primary
*
* @param kEvent $event
*/
- function OnSetPrimary(&$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)
+ 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
* @return void
* @access protected
*/
- protected function OnAfterConfigRead(kEvent &$event)
+ protected function OnAfterConfigRead(kEvent $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(kEvent &$event)
+ protected function OnBeforeItemUpdate(kEvent $event)
{
parent::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(kEvent &$event)
+ protected function SetCustomQuery(kEvent $event)
{
parent::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(kEvent &$event)
+ protected function OnAfterItemCreate(kEvent $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(kEvent &$event)
+ protected function OnSave(kEvent $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(kEvent &$event)
+ protected function OnPreCreate(kEvent $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(kEvent &$event)
+ protected function OnBeforeDeleteFromLive(kEvent $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)
+ function OnChangeLanguage($event)
{
$language_id = $this->Application->GetVar('language');
$language_field = $this->Application->isAdmin ? 'AdminLanguage' : 'FrontLanguage';
$this->Application->SetVar('m_lang', $language_id);
// set new language for this session
$this->Application->Session->SetField('Language', $language_id);
// remember last user language
if ($this->Application->RecallVar('user_id') == USER_ROOT) {
$this->Application->StorePersistentVar($language_field, $language_id);
}
else {
$object =& $this->Application->recallObject('u.current');
/* @var $object kDBItem */
$object->SetDBField($language_field, $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);
}
/**
* Parse language XML file into temp tables and redirect to progress bar screen
*
* @param kEvent $event
*/
- function OnImportLanguage(&$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, $this->getRequestProtectedFields($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)
+ 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',
'export_mode' => $event->Prefix,
)
);
}
/**
* Saves selected languages to xml file passed
*
* @param kEvent $event
*/
- function OnExportProgress(&$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, $this->getRequestProtectedFields($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');
}
$export_mode = $this->Application->GetVar('export_mode');
if ( $export_mode == $event->Prefix ) {
$language_import_helper->setExportLimit('phrases', $field_values['ExportPhrases']);
$language_import_helper->setExportLimit('emailevents', $field_values['ExportEmailEvents']);
}
else {
$language_import_helper->setExportLimit($export_mode);
$language_import_helper->setExportLimit($export_mode == 'phrases' ? 'emailevents' : 'phrases', '-');
}
$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
* @return void
* @access protected
*/
- protected function OnGoBack(kEvent &$event)
+ protected function OnGoBack(kEvent $event)
{
$event->SetRedirectParam('opener', 'u');
}
- function OnScheduleTopFrameReload(&$event)
+ function OnScheduleTopFrameReload($event)
{
$this->Application->StoreVar('RefreshTopFrame',1);
}
/**
* Do now allow deleting current language
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnBeforeItemDelete(kEvent &$event)
+ protected function OnBeforeItemDelete(kEvent $event)
{
parent::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
* @return void
* @access protected
*/
- protected function OnAfterItemDelete(kEvent &$event)
+ protected function OnAfterItemDelete(kEvent $event)
{
parent::OnAfterItemDelete($event);
$object =& $event->getObject();
/* @var $object kDBItem */
// clean EmailEvents 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,
'l' . $object->GetID() . '_HintTranslation' => NULL,
'l' . $object->GetID() . '_ColumnTranslation' => 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)
+ 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 . 'Languages
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 . 'LanguageLabels
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 15129)
+++ branches/5.2.x/core/units/permissions/permissions_event_handler.php (revision 15130)
@@ -1,266 +1,266 @@
<?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 standard permission mapping
*
* @return void
* @access protected
* @see kEventHandler::$permMapping
*/
protected 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)
+ 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)
+ 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)
+ 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
* @return void
* @access protected
*/
- protected function OnBeforeDeleteFromLive(kEvent &$event)
+ protected function OnBeforeDeleteFromLive(kEvent $event)
{
parent::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 15129)
+++ branches/5.2.x/core/units/email_events/email_events_event_handler.php (revision 15130)
@@ -1,1272 +1,1272 @@
<?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 standard permission mapping
*
* @return void
* @access protected
* @see kEventHandler::$permMapping
*/
protected function mapPermissions()
{
parent::mapPermissions();
$permissions = Array (
'OnFrontOnly' => Array ('self' => 'edit'),
'OnSaveSelected' => Array ('self' => 'view'),
'OnProcessEmailQueue' => Array ('self' => 'add|edit'),
'OnExportEmailEvents' => Array ('self' => 'view'),
'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(kEvent &$event)
+ public function CheckPermission(kEvent $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(kEvent &$event)
+ protected function SetCustomQuery(kEvent $event)
{
parent::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);
}
}
/**
* Prepares new kDBItem object
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnNew(kEvent &$event)
+ protected function OnNew(kEvent $event)
{
parent::OnNew($event);
$mapping = Array ('conf' => 'VariableValue', 'site-domain' => 'DefaultEmailRecipients');
if ( isset($mapping[$event->Special]) ) {
$object =& $event->getObject();
/* @var $object kDBItem */
$target_object =& $this->Application->recallObject($event->Special);
/* @var $target_object kDBList */
$object->SetDBField('Recipients', $target_object->GetDBField($mapping[$event->Special]));
}
}
/**
* Set default headers
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnPreCreate(kEvent &$event)
+ protected function OnPreCreate(kEvent $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)
+ 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
* @return void
* @access protected
*/
- protected function OnSelectUser(kEvent &$event)
+ protected function OnSelectUser(kEvent $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)
+ function OnSaveSelected($event)
{
$this->StoreSelectedIDs($event);
}
/**
* Returns email event object based on given kEvent object
*
* @param kEvent $event
* @return kDBItem
*/
- function &_getEmailEvent(&$event)
+ 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 ())
+ 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 . 'Users
WHERE Username = ' . $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('DefaultEmailSender');
}
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
* @return Array
*/
- function _processRecipients(&$event, &$direct_params = Array ())
+ 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 ();
$this->_addRecipientsFromXml($all_recipients, $object->GetDBField('Recipients'));
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 ) {
$language_field = $event->getEventParam('EmailEventType') == EmailEvent::EVENT_TYPE_FRONTEND ? 'FrontLanguage' : 'AdminLanguage';
$sql = 'SELECT FirstName, LastName, Email, ' . $language_field . ' AS Language
FROM ' . TABLE_PREFIX . 'Users
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']),
);
if ( $user_info['Language'] && !isset($direct_params['language_id']) ) {
$direct_params['language_id'] = $user_info['Language'];
}
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
$this->_addDefaultRecipient($all_recipients);
}
// 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
$this->_addDefaultRecipient($all_recipients);
}
$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('DefaultEmailSender');
foreach ($all_recipients as $recipient_type => $recipients) {
// add recipients to email
$pairs = Array ();
foreach ($recipients as $recipient) {
$address = $recipient['RecipientAddress'];
$address_type = $recipient['RecipientAddressType'];
$recipient_name = $recipient['RecipientName'];
switch ($address_type) {
case EmailEvent::ADDRESS_TYPE_EMAIL:
$pairs[] = Array ('email' => $address, 'name' => $recipient_name);
break;
case EmailEvent::ADDRESS_TYPE_USER:
$sql = 'SELECT FirstName, LastName, Email
FROM ' . TABLE_PREFIX . 'Users
WHERE Username = ' . $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 : $recipient_name,
);
}
break;
case EmailEvent::ADDRESS_TYPE_GROUP:
$sql = 'SELECT u.FirstName, u.LastName, u.Email
FROM ' . TABLE_PREFIX . 'UserGroups g
JOIN ' . TABLE_PREFIX . 'UserGroupRelations ug ON ug.GroupId = g.GroupId
JOIN ' . TABLE_PREFIX . 'Users u ON u.PortalUserId = ug.PortalUserId
WHERE g.Name = ' . $this->Conn->qstr($address);
$users = $this->Conn->Query($sql);
foreach ($users as $user_info) {
$name = trim($user_info['FirstName'] . ' ' . $user_info['LastName']);
$pairs[] = Array (
'email' => $user_info['Email'],
'name' => $name ? $name : $recipient_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
*
* @param Array $recipients
* @return void
*/
function _addDefaultRecipient(&$recipients)
{
$xml = $this->Application->ConfigValue('DefaultEmailRecipients');
if ( !$this->_addRecipientsFromXml($recipients, $xml) ) {
$recipient = Array (
'RecipientName' => $this->Application->ConfigValue('DefaultEmailSender'),
'RecipientAddressType' => EmailEvent::ADDRESS_TYPE_EMAIL,
'RecipientAddress' => $this->Application->ConfigValue('DefaultEmailSender'),
);
array_unshift($recipients[EmailEvent::RECIPIENT_TYPE_TO], $recipient);
}
}
/**
* Adds multiple recipients from an XML
*
* @param Array $recipients
* @param string $xml
* @return bool
* @access protected
*/
protected function _addRecipientsFromXml(&$recipients, $xml)
{
if ( !$xml ) {
return false;
}
$minput_helper =& $this->Application->recallObject('MInputHelper');
/* @var $minput_helper MInputHelper */
// group recipients by type
$records = $minput_helper->parseMInputXML($xml);
foreach ($records as $record) {
$recipient_type = $record['RecipientType'];
if ( !array_key_exists($recipient_type, $recipients) ) {
$recipients[$recipient_type] = Array ();
}
$recipients[$recipient_type][] = $record;
}
return true;
}
/**
* Returns email event message by ID (headers & body in one piece)
*
* @param kEvent $event
* @param int $language_id
* @return string
*/
- function _getMessageBody(&$event, $language_id = null)
+ 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="Username"',
'<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)
+ 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');
$log_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( $this->removeSendingParams($send_params) ),
);
$esender->setLogData($log_fields_hash);
$event->status = $esender->Deliver() ? kEvent::erSUCCESS : kEvent::erFAIL;
}
/**
* Removes parameters, used during e-mail sending
*
* @param Array $params
* @return Array
* @access protected
*/
protected function removeSendingParams($params)
{
$send_keys = Array ('from_email', 'from_name', 'to_email', 'to_name', 'message');
foreach ($send_keys as $send_key) {
unset($params[$send_key]);
}
return $params;
}
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)
+ 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
* @return void
* @access protected
*/
- protected function OnAfterConfigRead(kEvent &$event)
+ protected function OnAfterConfigRead(kEvent $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
* @return void
* @access protected
*/
- protected function OnEdit(kEvent &$event)
+ protected function OnEdit(kEvent $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(kEvent &$event)
+ protected function OnAfterItemLoad(kEvent $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)
+ 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);
}
if ( $this->translationChanged($object) ) {
$object->SetDBField('LastChanged_date', TIMENOW);
$object->SetDBField('LastChanged_time', TIMENOW);
}
}
/**
* Checks, that at least one of phrase's translations was changed
*
* @param kDBItem $object
* @return bool
*/
function translationChanged(&$object)
{
$changed_fields = array_keys( $object->GetChangedFields() );
$translation_fields = Array ('Subject', 'Body');
foreach ($changed_fields as $changed_field) {
$changed_field = preg_replace('/^l[\d]+_/', '', $changed_field);
if ( in_array($changed_field, $translation_fields) ) {
return true;
}
}
return false;
}
/**
* Validates address using given field prefix
*
* @param kEvent $event
* @param string $field_prefix
*/
- function _validateAddress(&$event, $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 . 'Users
WHERE Username = ' . $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 . 'UserGroups
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(kEvent &$event)
+ protected function OnBeforeItemCreate(kEvent $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(kEvent &$event)
+ protected function OnBeforeItemUpdate(kEvent $event)
{
parent::OnBeforeItemUpdate($event);
$this->_itemChanged($event);
}
/**
* Suggest address based on typed address and selected address type
*
* @param kEvent $event
*/
- function OnSuggestAddress(&$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 . 'Users';
break;
case EmailEvent::ADDRESS_TYPE_USER:
$field = 'Username';
$table_name = TABLE_PREFIX . 'Users';
break;
case EmailEvent::ADDRESS_TYPE_GROUP:
$field = 'Name';
$table_name = TABLE_PREFIX . 'UserGroups';
break;
default:
$field = $table_name = '';
break;
}
if ( $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');
}
}
/**
* Stores ids of selected phrases and redirects to export language step 1
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnExportEmailEvents(kEvent &$event)
+ protected function OnExportEmailEvents(kEvent $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', $this->Application->GetVar('m_lang'));
$event->setRedirectParams(
Array (
'phrases.export_event' => 'OnNew',
'pass' => 'all,phrases.export',
'export_mode' => $event->Prefix,
)
);
}
}
\ No newline at end of file
Index: branches/5.2.x/core/units/stylesheets/stylesheets_event_handler.php
===================================================================
--- branches/5.2.x/core/units/stylesheets/stylesheets_event_handler.php (revision 15129)
+++ branches/5.2.x/core/units/stylesheets/stylesheets_event_handler.php (revision 15130)
@@ -1,44 +1,44 @@
<?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 StylesheetsEventHandler extends kDBEventHandler {
/**
* [HOOK] Compile stylesheet file based on theme definitions
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnCompileStylesheet(&$event)
+ protected function OnCompileStylesheet($event)
{
$object =& $event->getObject( Array ('skip_autoload' => true) );
/* @var $object StylesheetsItem */
$object->SwitchToLive();
$ids = explode(',', $event->MasterEvent->getEventParam('ids'));
if ( !$ids ) {
return ;
}
foreach ($ids as $id) {
$object->Load($id);
$object->Compile();
}
}
}
\ No newline at end of file
Index: branches/5.2.x/core/units/page_revisions/page_revision_eh.php
===================================================================
--- branches/5.2.x/core/units/page_revisions/page_revision_eh.php (revision 15129)
+++ branches/5.2.x/core/units/page_revisions/page_revision_eh.php (revision 15130)
@@ -1,375 +1,375 @@
<?php
/**
* @version $Id$
* @package In-Portal
* @copyright Copyright (C) 1997 - 2011 Intechnic. All rights reserved.
* @license GNU/GPL
* In-Portal is Open Source software.
* This means that this software may have been modified pursuant
* the GNU General Public License, and as distributed it includes
* or is derivative of works licensed under the GNU General Public License
* or other free or open source software licenses.
* See http://www.in-portal.org/license for copyright notices and details.
*/
defined('FULL_PATH') or die('restricted access!');
class PageRevisionEventHandler extends kDBEventHandler {
/**
* Checks permissions of user
*
* @param kEvent $event
* @return bool
* @access public
*/
- public function CheckPermission(kEvent &$event)
+ public function CheckPermission(kEvent $event)
{
if ( $event->Name == 'OnItemBuild' ) {
return true;
}
if ( $event->Name == 'OnGetInfo' || $event->Name == 'OnDiscard' ) {
return $this->Application->isAdminUser;
}
$perm_helper =& $this->Application->recallObject('PermissionsHelper');
/* @var $perm_helper kPermissionsHelper */
if ( $event->Name == 'OnSave' ) {
$perm_status = $this->Application->CheckPermission('CATEGORY.REVISION.ADD', 0) || $this->Application->CheckPermission('CATEGORY.REVISION.ADD.PENDING', 0);
return $perm_helper->finalizePermissionCheck($event, $perm_status);
}
if ( $event->Name == 'OnPublish' || $event->Name == 'OnDecline' ) {
$perm_status = $this->Application->CheckPermission('CATEGORY.REVISION.MODERATE', 0);
return $perm_helper->finalizePermissionCheck($event, $perm_status);
}
return parent::CheckPermission($event);
}
/**
* Lists all current page revisions
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function SetCustomQuery(kEvent &$event)
+ protected function SetCustomQuery(kEvent $event)
{
parent::SetCustomQuery($event);
$object =& $event->getObject();
/* @var $object kDBList */
$page_id = $event->getEventParam('page_id');
if ( $this->Application->isAdmin ) {
$user_id = $this->Application->RecallVar('user_id');
}
else {
$user_id = $this->Application->RecallVar('admin_user_id');
}
$object->addFilter('draft_filter', 'IF(%1$s.IsDraft = 1, %1$s.CreatedById = ' . $user_id . ', TRUE)');
if ( $page_id !== false ) {
$object->addFilter('parent_filter', '%1$s.PageId = ' . $page_id);
}
}
/**
* Returns current page revision
*
* @param kEvent $event
* @return int
* @access public
*/
- public function getPassedID(kEvent &$event)
+ public function getPassedID(kEvent $event)
{
if ( $event->Special == 'current' ) {
$page =& $this->Application->recallObject('st.-virtual');
/* @var $page kDBItem */
$page_helper =& $this->Application->recallObject('PageHelper');
/* @var $page_helper PageHelper */
$page_id = $page->GetID();
$revision_clause = $page_helper->getRevsionWhereClause($page_id, $page->GetDBField('LiveRevisionNumber'));
$sql = 'SELECT RevisionId
FROM ' . TABLE_PREFIX . 'PageRevisions
WHERE (PageId = ' . $page_id . ') AND (' . $revision_clause . ')
ORDER BY IsDraft DESC, RevisionNumber DESC';
$id = $this->Conn->GetOne($sql);
if ( $id ) {
return $id;
}
// no revisions -> create live revision
$object =& $event->getObject();
/* @var $object kDBItem */
$object->SetDBField('PageId', $page_id);
$object->SetDBField('RevisionNumber', 1);
$object->SetDBField('Status', STATUS_ACTIVE);
$object->Create();
return $object->GetID();
}
return parent::getPassedID($event);
}
/**
* Remembers, who created revision
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnBeforeItemCreate(kEvent &$event)
+ protected function OnBeforeItemCreate(kEvent $event)
{
parent::OnBeforeItemCreate($event);
$object =& $event->getObject();
/* @var $object kDBItem */
if ( $this->Application->isAdmin ) {
$object->SetDBField('CreatedById', $this->Application->RecallVar('user_id'));
}
else {
$object->SetDBField('CreatedById', $this->Application->RecallVar('admin_user_id'));
}
}
/**
* Updates revision creation time
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnBeforeItemUpdate(kEvent &$event)
+ protected function OnBeforeItemUpdate(kEvent $event)
{
parent::OnBeforeItemUpdate($event);
$object =& $event->getObject();
/* @var $object kDBItem */
if ( $object->GetDBField('IsDraft') == 0 && $object->GetOriginalField('IsDraft') == 1 ) {
$object->SetDBField('CreatedOn_date', adodb_mktime());
$object->SetDBField('CreatedOn_time', adodb_mktime());
}
}
/**
* Creates new content blocks based on source revision
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnAfterItemCreate(kEvent &$event)
+ protected function OnAfterItemCreate(kEvent $event)
{
parent::OnAfterItemCreate($event);
$object =& $event->getObject();
/* @var $object kDBItem */
if ( !$object->GetDBField('FromRevisionId') ) {
return ;
}
$content =& $this->Application->recallObject('content.-item', null, Array ('skip_autoload' => true));
/* @var $content kDBItem */
$sql = $content->GetSelectSQL() . '
WHERE pr.RevisionId = ' . $object->GetDBField('FromRevisionId');
$content_blocks = $this->Conn->Query($sql);
foreach ($content_blocks as $content_block) {
$content->LoadFromHash($content_block);
$content->SetDBField('RevisionId', $object->GetID());
$content->Create();
}
}
/**
* Mark revision as current, once it's approved
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnAfterItemUpdate(kEvent &$event)
+ protected function OnAfterItemUpdate(kEvent $event)
{
parent::OnAfterItemUpdate($event);
$object =& $event->getObject();
/* @var $object kDBItem */
$status = $object->GetDBField('Status');
if ( $status != $object->GetOriginalField('Status') && $status == STATUS_ACTIVE ) {
$page =& $this->Application->recallObject('c.revision', null, Array ('skip_autoload' => true));
/* @var $page kDBItem */
$page->Load($object->GetDBField('PageId'));
$page->SetDBField('LiveRevisionNumber', $object->GetDBField('RevisionNumber'));
$page->Update();
}
}
/**
* Returns user, who are editing current page right now
*
* @param kEvent $event
*/
- function OnGetInfo(&$event)
+ function OnGetInfo($event)
{
$event->status = kEvent::erSTOP;
if ( $this->Application->GetVar('ajax') != 'yes' ) {
return ;
}
$page_helper =& $this->Application->recallObject('PageHelper');
/* @var $page_helper PageHelper */
$page_id = $this->Application->GetVar('m_cat_id');
echo json_encode( $page_helper->getPageInfo($page_id) );
}
/**
* Saves user draft into live revision
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnSave(kEvent &$event)
+ protected function OnSave(kEvent $event)
{
$revision_id = $this->getCurrentDraftRevision($event);
if ( $revision_id ) {
$object =& $event->getObject(Array ('skip_autoload' => true));
/* @var $object kDBItem */
$object->Load($revision_id);
$object->SetDBField('IsDraft', 0);
$object->SetDBField('RevisionNumber', $this->getNextAvailableRevision($event));
if ( $this->Application->CheckPermission('CATEGORY.REVISION.ADD', 0) ) {
$object->SetDBField('Status', STATUS_ACTIVE);
}
elseif ( $this->Application->CheckPermission('CATEGORY.REVISION.ADD.PENDING', 0) ) {
$object->SetDBField('Status', STATUS_PENDING);
}
$object->Update();
}
$event->SetRedirectParam('opener', 'u');
}
/**
* Discards user draft
*
* @param kEvent $event
*/
- function OnDiscard(&$event)
+ function OnDiscard($event)
{
$revision_id = $this->getCurrentDraftRevision($event);
if ( $revision_id ) {
$temp_handler =& $this->Application->recallObject($event->getPrefixSpecial() . '_TempHandler', 'kTempTablesHandler');
/* @var $temp_handler kTempTablesHandler */
$temp_handler->DeleteItems($event->Prefix, $event->Special, Array ($revision_id));
}
$event->SetRedirectParam('opener', 'u');
}
/**
* Makes revision live
*
* @param kEvent $event
*/
- function OnPublish(&$event)
+ function OnPublish($event)
{
$revision =& $this->Application->recallObject('page-revision.current');
/* @var $revision kDBItem */
if ( !$revision->isLoaded() || $revision->GetDBField('Status') == STATUS_ACTIVE || $revision->GetDBField('IsDraft') ) {
return ;
}
$revision->SetDBField('Status', STATUS_ACTIVE);
$revision->Update();
$event->SetRedirectParam('opener', 'u');
}
/**
* Denies changes made in revision
*
* @param kEvent $event
*/
- function OnDecline(&$event)
+ function OnDecline($event)
{
$revision =& $this->Application->recallObject('page-revision.current');
/* @var $revision kDBItem */
if ( !$revision->isLoaded() || $revision->GetDBField('Status') == STATUS_DISABLED || $revision->GetDBField('IsLive') || $revision->GetDBField('IsDraft') ) {
return ;
}
$revision->SetDBField('Status', STATUS_DISABLED);
$revision->Update();
$event->SetRedirectParam('opener', 'u');
}
/**
* Returns revision id of user's draft
*
* @param kEvent $event
* @return int
*/
- function getCurrentDraftRevision(&$event)
+ function getCurrentDraftRevision($event)
{
$where_clause = Array (
'IsDraft = 1',
'PageId = ' . $this->Application->GetVar('m_cat_id'),
'CreatedById = ' . $this->Application->RecallVar('user_id'),
);
$sql = 'SELECT ' . $this->Application->getUnitOption($event->Prefix, 'IDField') . '
FROM ' . $this->Application->getUnitOption($event->Prefix, 'TableName') . '
WHERE (' . implode(') AND (', $where_clause) . ')';
return $this->Conn->GetOne($sql);
}
/**
* Returns next available revision number for current page
*
* @param kEvent $event
* @return int
*/
- function getNextAvailableRevision(&$event)
+ function getNextAvailableRevision($event)
{
$sql = 'SELECT MAX(RevisionNumber)
FROM ' . $this->Application->getUnitOption($event->Prefix, 'TableName') . '
WHERE PageId = ' . $this->Application->GetVar('m_cat_id');
$max_revision = (int)$this->Conn->GetOne($sql);
return $max_revision + 1;
}
}
Index: branches/5.2.x/core/units/site_domains/site_domain_eh.php
===================================================================
--- branches/5.2.x/core/units/site_domains/site_domain_eh.php (revision 15129)
+++ branches/5.2.x/core/units/site_domains/site_domain_eh.php (revision 15130)
@@ -1,294 +1,294 @@
<?php
/**
* @version $Id$
* @package In-Portal
* @copyright Copyright (C) 1997 - 2010 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 SiteDomainEventHandler extends kDBEventHandler {
/**
* Checks user permission to execute given $event
*
* @param kEvent $event
* @return bool
* @access public
*/
- public function CheckPermission(kEvent &$event)
+ public function CheckPermission(kEvent $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);
}
/**
* Returns ID of site domain, that matches current url
*
* @param kEvent $event
* @return int
* @access public
*/
- public function getPassedID(kEvent &$event)
+ public function getPassedID(kEvent $event)
{
if ( $event->Special == 'current' ) {
if ( $this->Application->isAdmin ) {
$event->setEventParam('raise_warnings', 0);
}
else {
if ( PROTOCOL == 'https://' ) {
return $this->querySiteDomain('SSLUrl', rtrim($this->Application->BaseURL(), '/'));
}
return $this->querySiteDomain('DomainName', $_SERVER['HTTP_HOST']);
}
}
return parent::getPassedID($event);
}
function querySiteDomain($field, $value)
{
$site_helper =& $this->Application->recallObject('SiteHelper');
/* @var $site_helper SiteHelper */
$site_domains = $site_helper->getSiteDomains();
$domain_by_name = $site_helper->getDomainByName($field, $value);
$domain_by_ip = $site_helper->getDomainByIP();
if ($domain_by_ip) {
$site_domain = $site_domains[$domain_by_ip];
$redirect_mode = $site_domain['RedirectOnIPMatch'];
if (($redirect_mode == SITE_DOMAIN_REDIRECT_EXTERNAL) && ($domain_by_ip == $domain_by_name)) {
// redirect to external url (when visiting protected domain)
$external_url = $site_domain['ExternalUrl'];
if (preg_match('/^http[s]{0,1}:\/\//', $external_url)) {
$this->Application->Redirect('external:' . $external_url);
}
else {
$this->Application->Redirect('external:' . PROTOCOL . $external_url . $_SERVER['REQUEST_URI']);
}
}
elseif (($redirect_mode == SITE_DOMAIN_REDIRECT_CURRENT) && ($domain_by_ip != $domain_by_name)) {
// redirect to a domain detected by IP (when not already on it)
if ((PROTOCOL == 'https://') && !$site_domain['SSLUrlUsesRegExp'] && $site_domain['SSLUrl']) {
// need to remove sub folder from ssl url
$ssl_url = preg_replace('/^(https:\/\/[^\/]*)(\/.*){0,1}$/', '\\1', $site_domain['SSLUrl']);
$this->Application->Redirect('external:' . $ssl_url . $_SERVER['REQUEST_URI']);
}
elseif ((PROTOCOL == 'http://') && !$site_domain['DomainNameUsesRegExp']) {
$this->Application->Redirect('external:http://' . $site_domain['DomainName'] . $_SERVER['REQUEST_URI']);
}
}
return $domain_by_ip;
}
return $domain_by_name;
}
/**
* Load item if id is available
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function LoadItem(kEvent &$event)
+ protected function LoadItem(kEvent $event)
{
if ( $this->Application->isAdmin ) {
// don't load domain data from cache
parent::LoadItem($event);
return;
}
$object =& $event->getObject();
/* @var $object kDBItem */
$id = (int)$this->getPassedID($event);
if ( $object->isLoaded() && ($object->GetID() == $id) ) {
// object is already loaded by same id
return;
}
$site_helper =& $this->Application->recallObject('SiteHelper');
/* @var $site_helper SiteHelper */
$site_domains = $site_helper->getSiteDomains();
$domain_data = array_key_exists($id, $site_domains) ? $site_domains[$id] : false;
if ( $object->LoadFromHash($domain_data) ) {
$actions =& $this->Application->recallObject('kActions');
/* @var $actions Params */
$actions->Set($event->getPrefixSpecial() . '_id', $object->GetID());
}
else {
$object->setID($id);
}
}
/**
* Removes In-Commerce related fields, when it's not installed
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnAfterConfigRead(kEvent &$event)
+ protected function OnAfterConfigRead(kEvent $event)
{
parent::OnAfterConfigRead($event);
if (!$this->Application->isModuleEnabled('In-Commerce')) {
$remove_fields = Array (
'BillingCountry', 'ShippingCountry',
'PrimaryCurrencyId', 'Currencies',
'PrimaryPaymentTypeId', 'PaymentTypes'
);
// remove field definitions
$fields = $this->Application->getUnitOption($event->Prefix, 'Fields');
foreach ($remove_fields as $remove_field) {
unset($fields[$remove_field]);
}
$this->Application->setUnitOption($event->Prefix, 'Fields', $fields);
// remove grid columns
$grids = $this->Application->getUnitOption($event->Prefix, 'Grids', Array ());
/* @var $grids Array */
foreach ($grids as $grid_name => $grid_info) {
foreach ($remove_fields as $remove_field) {
if (array_key_exists($remove_field, $grid_info['Fields'])) {
unset($grids[$grid_name]['Fields'][$remove_field]);
}
}
}
$this->Application->setUnitOption($event->Prefix, 'Grids', $grids);
}
}
/**
* Delete cached information about site domains
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnSave(kEvent &$event)
+ protected function OnSave(kEvent $event)
{
parent::OnSave($event);
if ( $event->status == kEvent::erSUCCESS ) {
$this->_deleteCache();
}
}
/**
* Deletes cached information about site domains
*/
function _deleteCache()
{
if ( $this->Application->isCachingType(CACHING_TYPE_MEMORY) ) {
$this->Application->rebuildCache('master:domains_parsed', kCache::REBUILD_LATER, CacheSettings::$domainsParsedRebuildTime);
}
else {
$this->Application->rebuildDBCache('domains_parsed', kCache::REBUILD_LATER, CacheSettings::$domainsParsedRebuildTime);
}
$sql = 'DELETE FROM ' . TABLE_PREFIX . 'CachedUrls';
$this->Conn->Query($sql);
}
/**
* Sets required fields based on redirect mode
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnAfterItemLoad(kEvent &$event)
+ protected function OnAfterItemLoad(kEvent $event)
{
parent::OnAfterItemLoad($event);
$this->_setRequired($event);
}
/**
* Set's required fields based on redirect mode
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnBeforeItemCreate(kEvent &$event)
+ protected function OnBeforeItemCreate(kEvent $event)
{
parent::OnBeforeItemCreate($event);
$this->_itemChanged($event);
}
/**
* Set's required fields based on redirect mode
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnBeforeItemUpdate(kEvent &$event)
+ protected function OnBeforeItemUpdate(kEvent $event)
{
parent::OnBeforeItemUpdate($event);
$this->_itemChanged($event);
}
/**
* Occurs before item is changed
*
* @param kEvent $event
*/
- function _itemChanged(&$event)
+ function _itemChanged($event)
{
$object =& $event->getObject();
/* @var $object kDBItem */
$email_event_data = $this->Application->GetVar('emailevents_' . $event->Prefix);
$object->SetDBField('DefaultEmailRecipients', $email_event_data[0]['Recipients']);
$this->_setRequired($event);
}
/**
* Set's required fields
*
* @param kEvent $event
*/
- function _setRequired(&$event)
+ function _setRequired($event)
{
$object =& $event->getObject();
/* @var $object kDBItem */
$redirect_mode = $object->GetDBField('RedirectOnIPMatch');
$object->setRequired('ExternalUrl', $redirect_mode == SITE_DOMAIN_REDIRECT_EXTERNAL);
$object->setRequired('DomainIPRange', $redirect_mode > 0);
}
}
Index: branches/5.2.x/core/units/spam_reports/spam_report_eh.php
===================================================================
--- branches/5.2.x/core/units/spam_reports/spam_report_eh.php (revision 15129)
+++ branches/5.2.x/core/units/spam_reports/spam_report_eh.php (revision 15130)
@@ -1,147 +1,147 @@
<?php
/**
* @version $Id$
* @package In-Portal
* @copyright Copyright (C) 1997 - 2011 Intechnic. All rights reserved.
* @license GNU/GPL
* In-Portal is Open Source software.
* This means that this software may have been modified pursuant
* the GNU General Public License, and as distributed it includes
* or is derivative of works licensed under the GNU General Public License
* or other free or open source software licenses.
* See http://www.in-portal.org/license for copyright notices and details.
*/
defined('FULL_PATH') or die('restricted access!');
class SpamReportEventHandler extends kDBEventHandler {
/**
* Allows to override standard permission mapping
*
* @return void
* @access protected
* @see kEventHandler::$permMapping
*/
protected function mapPermissions()
{
parent::mapPermissions();
$permissions = Array (
'OnNewReport' => Array ('self' => true),
'OnDeleteAssocItem' => Array ('self' => 'delete'),
);
$this->permMapping = array_merge($this->permMapping, $permissions);
}
/**
* Checks permissions
*
* @param kEvent $event
*/
-// function CheckPermission(&$event)
+// function CheckPermission($event)
// {
// if ( $event->Name == 'OnNewReport' ) {
// $perm_helper =& $this->Application->recallObject('PermissionsHelper');
// /* @var $perm_helper kPermissionsHelper */
//
// return $perm_helper->finalizePermissionCheck($event, $this->Application->LoggedIn());
// }
//
// return parent::CheckPermission($event);
// }
/**
* Prefills missing fields
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnBeforeItemCreate(kEvent &$event)
+ protected function OnBeforeItemCreate(kEvent $event)
{
parent::OnBeforeItemCreate($event);
$object =& $event->getObject();
/* @var $object kDBItem */
$item_prefix = $this->Application->GetVar('item_prefix');
$item_id = $this->Application->GetVar($item_prefix . '_id');
if ( $item_id ) {
$object->SetDBField('ItemPrefix', $item_prefix);
$object->SetDBField('ItemId', $item_id);
}
$object->SetDBField('ReportedById', $this->Application->RecallVar('user_id'));
}
/**
* Send e-mail after new spam report was created
*
* @param kEvent $event
* @return void
* @access protected
*/
- protected function OnAfterItemCreate(kEvent &$event)
+ protected function OnAfterItemCreate(kEvent $event)
{
parent::OnAfterItemCreate($event);
$object =& $event->getObject();
/* @var $object kDBItem */
$item_prefix = $object->GetDBField('ItemPrefix');
if ( preg_match('/rev$/', $item_prefix) ) {
$item =& $this->Application->recallObject($item_prefix);
/* @var $item kDBItem */
$object->SetDBField('ItemName', $item->GetDBField('ReviewText'));
}
$this->Application->EmailEventAdmin('SPAM.REPORT');
}
/**
* Sends new spam report
*
* @param kEvent $event
*/
- function OnNewReport(&$event)
+ function OnNewReport($event)
{
$ajax_form_helper =& $this->Application->recallObject('AjaxFormHelper');
/* @var $ajax_form_helper AjaxFormHelper */
$ajax_form_helper->transitEvent($event, 'OnCreate');
}
/**
* Deletes item, associated with given spam report
*
* @param kEvent $event
*/
- function OnDeleteAssocItem(&$event)
+ function OnDeleteAssocItem($event)
{
$temp_handlers = Array ();
$ids = $this->StoreSelectedIDs($event);
$object =& $event->getObject( Array ('skip_autoload' => true) );
/* @var $object kDBItem */
foreach ($ids as $id) {
$object->Load($id);
$item_prefix = $object->GetDBField('ItemPrefix');
if ( !isset($temp_handlers[$item_prefix]) ) {
$temp_handlers[$item_prefix] =& $this->Application->recallObject($item_prefix . '_TempHandler', 'kTempTablesHandler');
}
$temp_handlers[$item_prefix]->DeleteItems($item_prefix, '', Array ($object->GetDBField('ItemId')));
}
$this->clearSelectedIDs($event);
$event->SetRedirectParam('opener', 'u');
}
}
\ No newline at end of file
Index: branches/5.2.x/core/install/step_templates/sys_requirements.tpl
===================================================================
--- branches/5.2.x/core/install/step_templates/sys_requirements.tpl (revision 15129)
+++ branches/5.2.x/core/install/step_templates/sys_requirements.tpl (revision 15130)
@@ -1,74 +1,75 @@
<?php
$heading_tpl = '
<tr class="subsectiontitle">
<td class="text" colspan="2" style="border-top: 1px solid #000000; border-bottom: 1px solid #000000;">%s</td>
</tr>';
$error_tpl = '
<tr class="table-color2">
<td class="text">%s</td>
<td align="center" width="30">%s</td>
</tr>';
$check_titles = Array (
- 'php_version' => 'PHP version: 5.2+ (required)',
+ 'php_version' => 'PHP version: 5.3.2+ (required)',
'url_rewriting' => 'URL Rewriting Support (optional)',
'java' => 'Java (optional)',
'sep1' => '<strong>PHP extensions:</strong>',
'memcache' => '- Memcache (optional)',
'curl' => '- Curl (required)',
+ 'simplexml' => '- SimpleXML (required)',
'freetype' => '- Freetype (required)',
'gd_version' => '- GD 1.8+ (required)',
'jpeg' => '- jpeg (required)',
'mysql' => '- MySQL (required)',
- 'json' => '- JSON (optional)',
+ 'json' => '- JSON (required)',
'sep2' => '<strong>PHP settings:</strong>',
'memory_limit' => "- ini_set('memory_limit', ...) works (optional)",
'date.timezone' => "- ini_get('date.timezone') - timezone set (required)",
'variables_order' => "- ini_get('variables_order') - contains \"GPC\" string",
'output_buffering' => "- ini_get('output_buffering') > 0 - buffering works (required)",
);
$output = sprintf($heading_tpl, '<strong>Server-side requirements</strong>');
$check_results = $this->toolkit->CallPrerequisitesMethod('core/', 'CheckSystemRequirements');
/*$required_checks = Array (
- 'php_version', 'curl', 'freetype', 'gd_version',
+ 'php_version', 'simplexml', 'curl', 'freetype', 'gd_version',
'jpeg', 'mysql', 'date.timezone', 'output_buffering',
);
$required_checks = array_diff($required_checks, array_keys( array_filter($check_results) ));*/
foreach ($check_titles AS $key => $title) {
if ( substr($key, 0, 3) == 'sep' ) {
$check_result = '';
}
else {
$check_result = $check_results[$key] ? '[<span style="color:green;">PASSED</span>]' : '[<span class="error">FAILED</span>]';
}
$output .= sprintf($error_tpl, $title, $check_result);
}
$output .= sprintf($heading_tpl, '<strong>Client-side requirements</strong>', 'text');
$output .= sprintf($error_tpl, 'Cookies enabled', '[<span class="error" id="cookies_enabled_mark">FAILED</span>]');
$output .= sprintf($error_tpl, 'JavaScript enabled', '[<span class="error" id="js_enabled_mark">FAILED</span>]');
$output .= '<input type="hidden" name="js_enabled" id="js_enabled" value="0"/>';
$output .= '<input type="hidden" name="cookies_enabled" id="cookies_enabled" value="0"/>';
$output .= "<script type='text/javascript'>
\$('#js_enabled').val(1);
\$('#js_enabled_mark').removeClass('error').css('color', 'green').html('PASSED');
document.cookie = 'install_cookie_test=1';
var \$cookies_enabled = document.cookie.indexOf('install_cookie_test') != -1;
if ( \$cookies_enabled ) {
\$('#cookies_enabled').val(1);
\$('#cookies_enabled_mark').removeClass('error').css('color', 'green').html('PASSED');
}
</script>";
echo $output;
?>
Index: branches/5.2.x/core/install/prerequisites.php
===================================================================
--- branches/5.2.x/core/install/prerequisites.php (revision 15129)
+++ branches/5.2.x/core/install/prerequisites.php (revision 15130)
@@ -1,181 +1,181 @@
<?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!');
$prerequisite_class = 'InPortalPrerequisites';
/**
* Class, that holds all prerequisite scripts for "In-Portal" module
*
*/
class InPortalPrerequisites {
/**
* Install toolkit instance
*
* @var kInstallToolkit
*/
var $_toolkit = null;
/**
* Connection to database
*
* @var kDBConnection
* @access protected
*/
protected $Conn = null;
/**
* Sets common instance of installator toolkit
*
* @param kInstallToolkit $instance
*/
function setToolkit(&$instance)
{
$this->_toolkit =& $instance;
}
/**
* Checks minimal version, that could be upgradeable
*
* @return kDBConnection
*/
function &getConnection()
{
return $this->_toolkit->Conn;
}
/**
* Checks minimal version, that could be upgradeable
*
* @param Array $versions
* @param string $mode when called mode {install, upgrade, standalone)
* @return Array
*/
function CheckPrerequisites($versions, $mode)
{
$errors = Array ();
if ($mode == 'upgrade') {
$sql = 'SELECT Version
FROM ' . TABLE_PREFIX . 'Modules
WHERE Name = "In-Portal"';
$conn =& $this->getConnection();
$inportal_version = $conn->GetOne($sql);
if ($inportal_version === false) {
// only, when In-Portal was installed
return $errors;
}
$min_version = '4.3.1';
$current_version = $this->_toolkit->ConvertModuleVersion($inportal_version);
$needed_version = $this->_toolkit->ConvertModuleVersion($min_version);
if ($current_version < $needed_version) {
$errors[] = 'Please upgrade "In-Portal" to version ' . $min_version;
}
}
return $errors;
}
/**
* Returns information about system requirements
*
* @return array
*/
function CheckSystemRequirements()
{
$ret = Array ();
- $ret['php_version'] = version_compare(PHP_VERSION, '5.2.0', '>=');
-
+ $ret['php_version'] = version_compare(PHP_VERSION, '5.3.2', '>=');
$ret['url_rewriting'] = function_exists('apache_get_modules') && in_array('mod_rewrite', apache_get_modules());
$ret['memcache'] = class_exists('Memcache');
$ret['curl'] = function_exists('curl_init');
+ $ret['simplexml'] = function_exists('simplexml_load_string');
$ret['freetype'] = function_exists('imagettfbbox');
$ret['gd_version'] = $ret['jpeg'] = false;
if ( function_exists('gd_info') ) {
$gd_info = gd_info();
$gd_version = preg_replace('/[^\d.]/', '', $gd_info['GD Version']);
$ret['gd_version'] = version_compare($gd_version, '1.8', '>=');
$ret['jpeg'] = isset($gd_info['JPEG Support']) && $gd_info['JPEG Support'];
}
$ret['mysql'] = function_exists('mysql_connect');
$ret['json'] = function_exists('json_encode');
$output = shell_exec('java -version 2>&1');
$ret['java'] = stripos($output, 'java version') !== false;
$ret['memory_limit'] = $this->isPhpSettingChangeable('memory_limit', '33M');
$ret['date.timezone'] = ini_get('date.timezone') != '';
$ret['variables_order'] = strpos(ini_get('variables_order'), 'GPC') !== false;
$ret['output_buffering'] = ini_get('output_buffering') > 0;
return $ret;
}
/**
* Detects if setting of php.ini can be changed
*
* @param string $setting_name
* @param string $new_value
* @return bool
*/
protected function isPhpSettingChangeable($setting_name, $new_value)
{
$backup_value = ini_get($setting_name);
ini_set($setting_name, $new_value);
if ( ini_get($setting_name) != $backup_value ) {
ini_set($setting_name, $backup_value);
return true;
}
return false;
}
/**
* Returns information about DB requirements
*
* @return array
*/
function CheckDBRequirements()
{
// check PHP version 5.2+
$ret = Array();
$sql = 'SELECT VERSION()';
$conn =& $this->getConnection();
$db_version = preg_replace('/[^\d.]/', '', $conn->GetOne($sql));
$ret['version'] = version_compare($db_version, '5.0', '>=');
$sql = 'SHOW VARIABLES LIKE "max_allowed_packet"';
$db_variables = $conn->Query($sql, 'Variable_name');
$ret['packet_size'] = $db_variables['max_allowed_packet']['Value'] >= 1048576;
return $ret;
}
}
\ No newline at end of file
Index: branches/5.2.x/core/install/install_toolkit.php
===================================================================
--- branches/5.2.x/core/install/install_toolkit.php (revision 15129)
+++ branches/5.2.x/core/install/install_toolkit.php (revision 15130)
@@ -1,1182 +1,1182 @@
<?php
/**
* @version $Id$
* @package In-Portal
* @copyright Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
* @license GNU/GPL
* In-Portal is Open Source software.
* This means that this software may have been modified pursuant
* the GNU General Public License, and as distributed it includes
* or is derivative of works licensed under the GNU General Public License
* or other free or open source software licenses.
* See http://www.in-portal.org/license for copyright notices and details.
*/
defined('FULL_PATH') or die('restricted access!');
/**
* Upgrade sqls are located using this mask
*
*/
define('UPGRADES_FILE', FULL_PATH.'/%sinstall/upgrades.%s');
/**
* Prerequisit check classes are located using this mask
*
*/
define('PREREQUISITE_FILE', FULL_PATH.'/%sinstall/prerequisites.php');
/**
* Format of version identificator in upgrade files (normal, beta, release candidate)
*
*/
define('VERSION_MARK', '# ===== v ([\d]+\.[\d]+\.[\d]+|[\d]+\.[\d]+\.[\d]+-B[\d]+|[\d]+\.[\d]+\.[\d]+-RC[\d]+) =====');
if (!defined('GET_LICENSE_URL')) {
/**
* Url used for retrieving user licenses from Intechnic licensing server
*
*/
define('GET_LICENSE_URL', 'http://www.in-portal.com/license.php');
}
/**
* Misc functions, that are required during installation, when
*
*/
class kInstallToolkit {
/**
* Reference to kApplication class object
*
* @var kApplication
*/
var $Application = null;
/**
* Connection to database
*
* @var kDBConnection
*/
var $Conn = null;
/**
* Path to config.php
*
* @var string
*/
var $INIFile = '';
/**
* Parsed data from config.php
*
* @var Array
*/
var $systemConfig = Array ();
/**
* Tells, that system config was changed
*
* @var bool
* @access public
*/
public $systemConfigChanged = false;
/**
* Path, used by system to store data on filesystem
*
* @var string
*/
var $defaultWritablePath = '';
/**
* Installator instance
*
* @var kInstallator
*/
var $_installator = null;
function kInstallToolkit()
{
$this->defaultWritablePath = DIRECTORY_SEPARATOR . 'system';
if ( class_exists('kApplication') ) {
// auto-setup in case of separate module install
$this->Application =& kApplication::Instance();
$this->Application->Init(); // needed for standalone module install
$this->Conn =& $this->Application->GetADODBConnection();
}
$this->INIFile = FULL_PATH . $this->defaultWritablePath . DIRECTORY_SEPARATOR . 'config.php';
$this->systemConfig = $this->ParseConfig(true);
}
/**
* Sets installator
*
* @param kInstallator $instance
*/
function setInstallator(&$instance)
{
$this->_installator =& $instance;
}
/**
* Checks prerequisities before module install or upgrade
*
* @param string $module_path
* @param string $versions
* @param string $mode upgrade mode = {install, standalone, upgrade}
* @return bool
*/
function CheckPrerequisites($module_path, $versions, $mode)
{
if ( !$versions ) {
return Array ();
}
$prerequisite_object =& $this->getPrerequisiteObject($module_path);
/* @var $prerequisite_object InPortalPrerequisites */
// some errors possible
return is_object($prerequisite_object) ? $prerequisite_object->CheckPrerequisites($versions, $mode) : Array ();
}
/**
* Call prerequisites method
*
* @param string $module_path
* @param string $method
* @return array
*/
function CallPrerequisitesMethod($module_path, $method)
{
$prerequisite_object =& $this->getPrerequisiteObject($module_path);
/* @var $prerequisite_object InPortalPrerequisites */
return is_object($prerequisite_object) ? $prerequisite_object->$method() : false;
}
/**
* Returns prerequisite object to be used for checks
*
* @param string $module_path
* @return kHelper
* @access protected
*/
protected function &getPrerequisiteObject($module_path)
{
static $prerequisite_classes = Array ();
$prerequisites_file = sprintf(PREREQUISITE_FILE, $module_path);
if ( !file_exists($prerequisites_file) ) {
$false = false;
return $false;
}
if ( !isset($prerequisite_classes[$module_path]) ) {
// save class name, because 2nd time
// (in after call $prerequisite_class variable will not be present)
include_once $prerequisites_file;
$prerequisite_classes[$module_path] = $prerequisite_class;
}
$prerequisite_object = new $prerequisite_classes[$module_path]();
/* @var $prerequisite_object InPortalPrerequisites */
if ( method_exists($prerequisite_object, 'setToolkit') ) {
$prerequisite_object->setToolkit($this);
}
return $prerequisite_object;
}
/**
* Processes one license, received from server
*
* @param string $file_data
*/
function processLicense($file_data)
{
$modules_helper =& $this->Application->recallObject('ModulesHelper');
/* @var $modules_helper kModulesHelper */
$file_data = explode('Code==:', $file_data);
$file_data[0] = str_replace('In-Portal License File - do not edit!' . "\n", '', $file_data[0]);
$file_data = array_map('trim', $file_data);
if ($modules_helper->verifyLicense($file_data[0])) {
$this->setSystemConfig('Intechnic', 'License', $file_data[0]);
if (array_key_exists(1, $file_data)) {
$this->setSystemConfig('Intechnic', 'LicenseCode', $file_data[1]);
}
else {
$this->setSystemConfig('Intechnic', 'LicenseCode');
}
$this->SaveConfig();
}
else {
// invalid license received from licensing server
$this->_installator->errorMessage = 'Invalid License File';
}
}
/**
* Saves given configuration values to database
*
* @param Array $config
*/
function saveConfigValues($config)
{
foreach ($config as $config_var => $value) {
$sql = 'UPDATE ' . TABLE_PREFIX . 'SystemSettings
SET VariableValue = ' . $this->Conn->qstr($value) . '
WHERE VariableName = ' . $this->Conn->qstr($config_var);
$this->Conn->Query($sql);
}
}
/**
* Sets module version to passed
*
* @param string $module_name
* @param string|bool $module_path
* @param string|bool $version
*/
function SetModuleVersion($module_name, $module_path = false, $version = false)
{
if ($version === false) {
if (!$module_path) {
throw new Exception('Module path must be given to "SetModuleVersion" method to auto-detect version');
return ;
}
$version = $this->GetMaxModuleVersion($module_path);
}
// get table prefix from config, because application may not be available here
$table_prefix = $this->getSystemConfig('Database', 'TablePrefix');
if ($module_name == 'kernel') {
$module_name = 'in-portal';
}
// don't use "adodb_mktime" here, because it's not yet included
$sql = 'UPDATE ' . $table_prefix . 'Modules
SET Version = "' . $version . '", BuildDate = ' . time() . '
WHERE LOWER(Name) = "' . strtolower($module_name) . '"';
$this->Conn->Query($sql);
}
/**
* Sets module root category to passed
*
* @param string $module_name
* @param int $category_id
*/
function SetModuleRootCategory($module_name, $category_id = 0)
{
// get table prefix from config, because application may not be available here
$table_prefix = $this->getSystemConfig('Database', 'TablePrefix');
if ($module_name == 'kernel') {
$module_name = 'in-portal';
}
$sql = 'UPDATE ' . $table_prefix . 'Modules
SET RootCat = ' . $category_id . '
WHERE LOWER(Name) = "' . strtolower($module_name) . '"';
$this->Conn->Query($sql);
}
/**
* Returns maximal version of given module by scanning it's upgrade scripts
*
* @param string $module_path
* @return string
*/
function GetMaxModuleVersion($module_path)
{
$module_path = rtrim(mb_strtolower($module_path), '/');
$upgrades_file = sprintf(UPGRADES_FILE, $module_path . '/', 'sql');
if (!file_exists($upgrades_file)) {
// no upgrade file
return '5.0.0';
}
$sqls = file_get_contents($upgrades_file);
$versions_found = preg_match_all('/'.VERSION_MARK.'/s', $sqls, $regs);
if (!$versions_found) {
// upgrades file doesn't contain version definitions
return '5.0.0';
}
return end($regs[1]);
}
/**
* Runs SQLs from file
*
* @param string $filename
* @param mixed $replace_from
* @param mixed $replace_to
*/
function RunSQL($filename, $replace_from = null, $replace_to = null)
{
if (!file_exists(FULL_PATH.$filename)) {
return ;
}
$sqls = file_get_contents(FULL_PATH.$filename);
if (!$this->RunSQLText($sqls, $replace_from, $replace_to)) {
if (is_object($this->_installator)) {
$this->_installator->Done();
}
else {
if (isset($this->Application)) {
$this->Application->Done();
}
exit;
}
}
}
/**
* Runs SQLs from string
*
* @param string $sqls
* @param mixed $replace_from
* @param mixed $replace_to
* @param int $start_from
* @return bool
*/
function RunSQLText(&$sqls, $replace_from = null, $replace_to = null, $start_from = 0)
{
$table_prefix = $this->getSystemConfig('Database', 'TablePrefix');
// add prefix to all tables
if (strlen($table_prefix) > 0) {
$replacements = Array ('INSERT INTO ', 'UPDATE ', 'ALTER TABLE ', 'DELETE FROM ', 'REPLACE INTO ');
foreach ($replacements as $replacement) {
$sqls = str_replace($replacement, $replacement . $table_prefix, $sqls);
}
}
$sqls = str_replace('CREATE TABLE ', 'CREATE TABLE IF NOT EXISTS ' . $table_prefix, $sqls);
$sqls = str_replace('DROP TABLE ', 'DROP TABLE IF EXISTS ' . $table_prefix, $sqls);
$sqls = str_replace('<%TABLE_PREFIX%>', $table_prefix, $sqls);
$primary_language = is_object($this->Application) ? $this->Application->GetDefaultLanguageId() : 1;
$sqls = str_replace('<%PRIMARY_LANGUAGE%>', $primary_language, $sqls);
if (isset($replace_from) && isset($replace_to)) {
// replace something additionally, e.g. module root category
$sqls = str_replace($replace_from, $replace_to, $sqls);
}
$sqls = str_replace("\r\n", "\n", $sqls); // convert to linux line endings
$no_comment_sqls = preg_replace("/#\s([^;]*?)\n/is", '', $sqls); // remove all comments "#" on new lines
if ($no_comment_sqls === null) {
// "ini.pcre.backtrack-limit" reached and error happened
$sqls = explode(";\n", $sqls . "\n"); // ensures that last sql won't have ";" in it
$sqls = array_map('trim', $sqls);
// remove all comments "#" on new lines (takes about 2 seconds for 53000 sqls)
$sqls = preg_replace("/#\s([^;]*?)/", '', $sqls);
}
else {
$sqls = explode(";\n", $no_comment_sqls . "\n"); // ensures that last sql won't have ";" in it
$sqls = array_map('trim', $sqls);
}
$sql_count = count($sqls);
$db_collation = $this->getSystemConfig('Database', 'DBCollation');
for ($i = $start_from; $i < $sql_count; $i++) {
$sql = $sqls[$i];
if (!$sql || (substr($sql, 0, 1) == '#')) {
continue; // usually last line
}
if (substr($sql, 0, 13) == 'CREATE TABLE ' && $db_collation) {
// it is CREATE TABLE statement -> add collation
$sql .= ' COLLATE \'' . $db_collation . '\'';
}
$this->Conn->Query($sql);
if ($this->Conn->getErrorCode() != 0) {
if (is_object($this->_installator)) {
$this->_installator->errorMessage = 'Error: ('.$this->Conn->getErrorCode().') '.$this->Conn->getErrorMsg().'<br /><br />Last Database Query:<br /><textarea cols="70" rows="10" readonly>'.htmlspecialchars($sql).'</textarea>';
$this->_installator->LastQueryNum = $i + 1;
}
return false;
}
}
return true;
}
/**
* Performs clean language import from given xml file
*
* @param string $lang_file
* @param bool $upgrade
* @todo Import for "core/install/english.lang" (322KB) takes 18 seconds to work on Windows
*/
function ImportLanguage($lang_file, $upgrade = false)
{
$lang_file = FULL_PATH.$lang_file.'.lang';
if (!file_exists($lang_file)) {
return ;
}
$language_import_helper =& $this->Application->recallObject('LanguageImportHelper');
/* @var $language_import_helper LanguageImportHelper */
$language_import_helper->performImport($lang_file, '|0|1|2|', '', $upgrade ? LANG_SKIP_EXISTING : LANG_OVERWRITE_EXISTING);
}
/**
* Converts module version in format X.Y.Z[-BN/-RCM] to signle integer
*
* @param string $version
* @return int
*/
function ConvertModuleVersion($version)
{
if (preg_match('/(.*)-(B|RC)([\d]+)/', $version, $regs)) {
// -B<M> or RC-<N>
$parts = explode('.', $regs[1]);
$parts[] = $regs[2] == 'B' ? 1 : 2; // B reliases goes before RC releases
$parts[] = $regs[3];
}
else {
// releases without B/RC marks go after any B/RC releases
$parts = explode('.', $version . '.3.100');
}
$bin = '';
foreach ($parts as $part_index => $part) {
if ($part_index == 3) {
// version type only can be 1/2/3 (11 in binary form), so don't use padding at all
$pad_count = 2;
}
else {
$pad_count = 8;
}
$bin .= str_pad(decbin($part), $pad_count, '0', STR_PAD_LEFT);
}
return bindec($bin);
}
/**
* Returns themes, found in system
*
* @param bool $rebuild
* @return int
*/
function getThemes($rebuild = false)
{
if ($rebuild) {
$this->rebuildThemes();
}
$id_field = $this->Application->getUnitOption('theme', 'IDField');
$table_name = $this->Application->getUnitOption('theme', 'TableName');
$sql = 'SELECT Name, ' . $id_field . '
FROM ' . $table_name . '
ORDER BY Name ASC';
return $this->Conn->GetCol($sql, $id_field);
}
function ParseConfig($parse_section = false)
{
if (!file_exists($this->INIFile)) {
return Array ();
}
if (file_exists($this->INIFile) && !is_readable($this->INIFile)) {
die('Could Not Open Ini File');
}
$contents = file($this->INIFile);
if ($contents && $contents[0] == '<' . '?' . 'php die() ?' . ">\n") {
// format of "config.php" file before 5.1.0 version
array_shift($contents);
return $this->parseIniString(implode('', $contents), $parse_section);
}
$_CONFIG = Array ();
require($this->INIFile);
if ($parse_section) {
return $_CONFIG;
}
$ret = Array ();
foreach ($_CONFIG as $section => $section_variables) {
$ret = array_merge($ret, $section_variables);
}
return $ret;
}
/**
* Equivalent for "parse_ini_string" function available since PHP 5.3.0
*
* @param string $ini
* @param bool $process_sections
* @param int $scanner_mode
* @return Array
*/
function parseIniString($ini, $process_sections = false, $scanner_mode = null)
{
# Generate a temporary file.
$tempname = tempnam('/tmp', 'ini');
$fp = fopen($tempname, 'w');
fwrite($fp, $ini);
$ini = parse_ini_file($tempname, !empty($process_sections));
fclose($fp);
@unlink($tempname);
return $ini;
}
function SaveConfig($silent = false)
{
if (!is_writable($this->INIFile) && !is_writable(dirname($this->INIFile))) {
$error_msg = 'Cannot write to "' . $this->INIFile . '" file';
if ($silent) {
trigger_error($error_msg, E_USER_WARNING);
}
else {
throw new Exception($error_msg);
}
return ;
}
$fp = fopen($this->INIFile, 'w');
fwrite($fp, '<' . '?' . 'php' . "\n\n");
foreach ($this->systemConfig as $section_name => $section_data) {
foreach ($section_data as $key => $value) {
fwrite($fp, '$_CONFIG[\'' . $section_name . '\'][\'' . $key . '\'] = \'' . addslashes($value) . '\';' . "\n");
}
fwrite($fp, "\n");
}
fclose($fp);
$this->systemConfigChanged = false;
}
/**
* Sets value to system config (yet SaveConfig must be called to write it to file)
*
* @param string $section
* @param string $key
* @param string $value
*/
function setSystemConfig($section, $key, $value = null)
{
$this->systemConfigChanged = true;
if (isset($value)) {
if (!array_key_exists($section, $this->systemConfig)) {
// create section, when missing
$this->systemConfig[$section] = Array ();
}
// create key in section
$this->systemConfig[$section][$key] = $value;
return ;
}
unset($this->systemConfig[$section][$key]);
}
/**
* Returns information from system config
*
* @param string $section
* @param string $key
* @param mixed $default
* @return string|bool
*/
function getSystemConfig($section, $key, $default = false)
{
if ( !array_key_exists($section, $this->systemConfig) ) {
return $default;
}
if ( !array_key_exists($key, $this->systemConfig[$section]) ) {
return $default;
}
return $this->systemConfig[$section][$key] ? $this->systemConfig[$section][$key] : $default;
}
/**
* Checks if system config is present and is not empty
*
* @return bool
*/
function systemConfigFound()
{
return file_exists($this->INIFile) && $this->systemConfig;
}
/**
* Checks if given section is present in config
*
* @param string $section
* @return bool
*/
function sectionFound($section)
{
return array_key_exists($section, $this->systemConfig);
}
/**
* Returns formatted module name based on it's root folder
*
* @param string $module_folder
* @return string
*/
function getModuleName($module_folder)
{
return implode('-', array_map('ucfirst', explode('-', $module_folder)));
}
/**
* Returns information about module (based on "install/module_info.xml" file)
*
* @param string $module_name
* @return Array
*/
function getModuleInfo($module_name)
{
if ($module_name == 'core') {
$info_file = FULL_PATH . '/' . $module_name . '/install/module_info.xml';
}
else {
$info_file = MODULES_PATH . '/' . $module_name . '/install/module_info.xml';
}
if (!file_exists($info_file)) {
return Array ();
}
$xml_helper =& $this->Application->recallObject('kXMLHelper');
/* @var $xml_helper kXMLHelper */
$root_node =& $xml_helper->Parse( file_get_contents($info_file) );
if (!is_object($root_node) || !preg_match('/^kxmlnode/i', get_class($root_node)) || ($root_node->Name == 'ERROR')) {
// non-valid xml file
return Array ();
}
$ret = Array ();
$current_node =& $root_node->firstChild;
do {
$ret[ strtolower($current_node->Name) ] = trim($current_node->Data);
} while (($current_node =& $current_node->NextSibling()));
return $ret;
}
/**
* Returns nice module string to be used on install/upgrade screens
*
* @param string $module_name
* @param string $version_string
* @return string
*/
function getModuleString($module_name, $version_string)
{
// image (if exists) <description> (<name> <version>)
$ret = Array ();
$module_info = $this->getModuleInfo($module_name);
if (array_key_exists('name', $module_info) && $module_info['name']) {
$module_name = $module_info['name'];
}
else {
$module_name = $this->getModuleName($module_name);
}
if (array_key_exists('image', $module_info) && $module_info['image']) {
$image_src = $module_info['image'];
if (!preg_match('/^(http|https):\/\//', $image_src)) {
// local image -> make absolute url
$image_src = $this->Application->BaseURL() . $image_src;
}
$ret[] = '<img src="' . $image_src . '" alt="' . htmlspecialchars($module_name) . '" title="' . htmlspecialchars($module_name) . '" style="vertical-align:middle; margin: 3px 0 3px 5px"/>';
}
if (array_key_exists('description', $module_info) && $module_info['description']) {
$ret[] = $module_info['description'];
}
else {
$ret[] = $module_name;
}
$ret[] = '(' . $module_name . ' ' . $version_string . ')';
return implode(' ', $ret);
}
/**
* Creates module root category in "Home" category using given data and returns it
*
* @param string $name
* @param string $description
* @param string $category_template
* @param string $category_icon
* @return kDBItem
*/
function &createModuleCategory($name, $description, $category_template = null, $category_icon = null)
{
static $fields = null;
if ( !isset($fields) ) {
$ml_formatter =& $this->Application->recallObject('kMultiLanguage');
/* @var $ml_formatter kMultiLanguage */
$fields['name'] = $ml_formatter->LangFieldName('Name');
$fields['description'] = $ml_formatter->LangFieldName('Description');
}
$category =& $this->Application->recallObject('c', null, Array ('skip_autoload' => true));
/* @var $category kDBItem */
$category_fields = Array (
$fields['name'] => $name, 'Filename' => $name, 'AutomaticFilename' => 1,
$fields['description'] => $description, 'Status' => STATUS_ACTIVE, 'Priority' => -9999,
// prevents empty link to module category on spearate module install
'NamedParentPath' => 'Content/' . $name,
);
$category_fields['ParentId'] = $this->Application->getBaseCategory();
if ( isset($category_template) ) {
$category_fields['Template'] = $category_template;
$category_fields['CachedTemplate'] = $category_template;
}
if ( isset($category_icon) ) {
$category_fields['UseMenuIconUrl'] = 1;
$category_fields['MenuIconUrl'] = $category_icon;
}
$category->Clear();
$category->SetDBFieldsFromHash($category_fields);
$category->Create();
$priority_helper =& $this->Application->recallObject('PriorityHelper');
/* @var $priority_helper kPriorityHelper */
$event = new kEvent('c:OnListBuild');
// ensure, that newly created category has proper value in Priority field
$priority_helper->recalculatePriorities($event, 'ParentId = ' . $category_fields['ParentId']);
// update Priority field in object, becase "CategoriesItem::Update" method will be called
// from "kInstallToolkit::setModuleItemTemplate" and otherwise will set 0 to Priority field
$sql = 'SELECT Priority
FROM ' . $category->TableName . '
WHERE ' . $category->IDField . ' = ' . $category->GetID();
$category->SetDBField('Priority', $this->Conn->GetOne($sql));
return $category;
}
/**
* Sets category item template into custom field for given prefix
*
* @param kDBItem $category
* @param string $prefix
* @param string $item_template
*/
function setModuleItemTemplate(&$category, $prefix, $item_template)
{
$this->Application->removeObject('c-cdata');
// recreate all fields, because custom fields are added during install script
$category->Configure();
$category->SetDBField('cust_' . $prefix .'_ItemTemplate', $item_template);
$category->Update();
}
/**
* Link custom field records with search config records + create custom field columns
*
* @param string $module_folder
* @param string $prefix
* @param int $item_type
*/
function linkCustomFields($module_folder, $prefix, $item_type)
{
$module_folder = strtolower($module_folder);
$module_name = $module_folder;
if ( $module_folder == 'kernel' ) {
$module_name = 'in-portal';
$module_folder = 'core';
}
$db =& $this->Application->GetADODBConnection();
$sql = 'SELECT FieldName, CustomFieldId
FROM ' . TABLE_PREFIX . 'CustomFields
WHERE Type = ' . $item_type . ' AND IsSystem = 0'; // config is not read here yet :( $this->Application->getUnitOption('p', 'ItemType');
$custom_fields = $db->GetCol($sql, 'CustomFieldId');
foreach ($custom_fields as $cf_id => $cf_name) {
$sql = 'UPDATE ' . TABLE_PREFIX . 'SearchConfig
SET CustomFieldId = ' . $cf_id . '
WHERE (TableName = "CustomFields") AND (LOWER(ModuleName) = "' . $module_name . '") AND (FieldName = ' . $db->qstr($cf_name) . ')';
$db->Query($sql);
}
$this->Application->refreshModuleInfo(); // this module configs are now processed
// because of configs was read only from installed before modules (in-portal), then reread configs
$this->Application->UnitConfigReader->scanModules(MODULES_PATH . DIRECTORY_SEPARATOR . $module_folder);
// create correct columns in CustomData table
$ml_helper =& $this->Application->recallObject('kMultiLanguageHelper');
/* @var $ml_helper kMultiLanguageHelper */
$ml_helper->createFields($prefix . '-cdata', true);
}
/**
* Deletes cache, useful after separate module install and installator last step
*
* @param bool $refresh_permissions
* @return void
*/
function deleteCache($refresh_permissions = false)
{
- $this->Application->HandleEvent($event, 'adm:OnResetConfigsCache');
- $this->Application->HandleEvent($event, 'adm:OnResetSections');
- $this->Application->HandleEvent($event, 'c:OnResetCMSMenuCache');
+ $this->Application->HandleEvent(new kEvent('adm:OnResetConfigsCache'));
+ $this->Application->HandleEvent(new kEvent('adm:OnResetSections'));
+ $this->Application->HandleEvent(new kEvent('c:OnResetCMSMenuCache'));
$this->Conn->Query('DELETE FROM ' . TABLE_PREFIX . 'CachedUrls');
- if ($refresh_permissions) {
- if ($this->Application->ConfigValue('QuickCategoryPermissionRebuild')) {
+ if ( $refresh_permissions ) {
+ if ( $this->Application->ConfigValue('QuickCategoryPermissionRebuild') ) {
// refresh permission without progress bar
$updater =& $this->Application->makeClass('kPermCacheUpdater');
/* @var $updater kPermCacheUpdater */
$updater->OneStepRun();
}
else {
// refresh permissions with ajax progress bar (when available)
$this->Application->setDBCache('ForcePermCacheUpdate', 1);
}
}
}
/**
* Deletes all temp tables (from active sessions too)
*
*/
function deleteEditTables()
{
$table_prefix = $this->getSystemConfig('Database', 'TablePrefix');
$tables = $this->Conn->GetCol('SHOW TABLES');
$mask_edit_table = '/' . $table_prefix . 'ses_(.*)_edit_(.*)/';
$mask_search_table = '/' . $table_prefix . 'ses_(.*?)_(.*)/';
foreach ($tables as $table) {
if ( preg_match($mask_edit_table, $table, $rets) || preg_match($mask_search_table, $table, $rets) ) {
$this->Conn->Query('DROP TABLE IF EXISTS ' . $table);
}
}
}
/**
* Perform redirect after separate module install
*
* @param string $module_folder
* @param bool $refresh_permissions
*/
function finalizeModuleInstall($module_folder, $refresh_permissions = false)
{
$this->SetModuleVersion(basename($module_folder), $module_folder);
if (!$this->Application->GetVar('redirect')) {
return ;
}
$themes_helper =& $this->Application->recallObject('ThemesHelper');
/* @var $themes_helper kThemesHelper */
// use direct query, since module isn't yet in kApplication::ModuleInfo array
$sql = 'SELECT Name
FROM ' . TABLE_PREFIX . 'Modules
WHERE Path = ' . $this->Conn->qstr(rtrim($module_folder, '/') . '/');
$module_name = $this->Conn->GetOne($sql);
$themes_helper->synchronizeModule($module_name);
$ml_helper =& $this->Application->recallObject('kMultiLanguageHelper');
/* @var $ml_helper kMultiLanguageHelper */
$ml_helper->massCreateFields();
$this->deleteCache($refresh_permissions);
$url_params = Array (
'pass' => 'm', 'admin' => 1,
'RefreshTree' => 1, 'index_file' => 'index.php',
);
$this->Application->Redirect('modules/modules_list', $url_params);
}
/**
* Performs rebuild of themes
*
*/
function rebuildThemes()
{
- $this->Application->HandleEvent($themes_event, 'adm:OnRebuildThemes');
+ $this->Application->HandleEvent(new kEvent('adm:OnRebuildThemes'));
}
/**
* Checks that file is writable by group or others
*
* @param string $file
* @return boolean
*/
function checkWritePermissions($file)
{
if (DIRECTORY_SEPARATOR == '\\') {
// windows doen't allow to check permissions (always returns null)
return null;
}
$permissions = fileperms($file);
return $permissions & 0x0010 || $permissions & 0x0002;
}
/**
* Upgrades primary skin to the latest version
*
* @param Array $module_info
* @return string|bool
*/
function upgradeSkin($module_info)
{
$upgrades_file = sprintf(UPGRADES_FILE, $module_info['Path'], 'css');
$data = file_get_contents($upgrades_file);
// get all versions with their positions in file
$versions = Array ();
preg_match_all('/(' . VERSION_MARK . ')/s', $data, $matches, PREG_SET_ORDER + PREG_OFFSET_CAPTURE);
$from_version_int = $this->ConvertModuleVersion($module_info['FromVersion']);
foreach ($matches as $index => $match) {
$version_int = $this->ConvertModuleVersion($match[2][0]);
if ( $version_int < $from_version_int ) {
// only process versions, that were released after currently used version
continue;
}
$start_pos = $match[0][1] + strlen($match[0][0]);
$end_pos = array_key_exists($index + 1, $matches) ? $matches[$index + 1][0][1] : mb_strlen($data);
$patch_data = str_replace("\r\n", "\n", substr($data, $start_pos, $end_pos - $start_pos));
$versions[] = Array (
'Version' => $match[2][0],
// fixes trimmed leading spaces by modern text editor
'Data' => ltrim( str_replace("\n\n", "\n \n", $patch_data) ),
);
}
if ( !$versions ) {
// not skin changes -> quit
return true;
}
$primary_skin =& $this->Application->recallObject('skin.primary', null, Array ('skip_autoload' => true));
/* @var $primary_skin kDBItem */
$primary_skin->Load(1, 'IsPrimary');
if ( !$primary_skin->isLoaded() ) {
// we always got primary skin, but just in case
return false;
}
$temp_handler =& $this->Application->recallObject('skin_TempHandler', 'kTempTablesHandler');
/* @var $temp_handler kTempTablesHandler */
// clone current skin
$cloned_ids = $temp_handler->CloneItems('skin', '', Array ($primary_skin->GetID()));
if ( !$cloned_ids ) {
// can't clone
return false;
}
$skin =& $this->Application->recallObject('skin.tmp', null, Array ('skip_autoload' => true));
/* @var $skin kDBItem */
$skin->Load($cloned_ids[0]);
// save css to temp file (for patching)
$skin_file = tempnam('/tmp', 'skin_css_');
$fp = fopen($skin_file, 'w');
fwrite($fp, str_replace("\r\n", "\n", $skin->GetDBField('CSS')));
fclose($fp);
$output = Array ();
$patch_file = tempnam('/tmp', 'skin_patch_');
foreach ($versions as $version_info) {
// for each left version get it's patch and apply to temp file
$fp = fopen($patch_file, 'w');
fwrite($fp, $version_info['Data']);
fclose($fp);
$output[ $version_info['Version'] ] = shell_exec('patch ' . $skin_file . ' ' . $patch_file . ' 2>&1') . "\n";
}
// place temp file content into cloned skin
$skin->SetDBField('Name', 'Upgraded to ' . $module_info['ToVersion']);
$skin->SetDBField('CSS', file_get_contents($skin_file));
$skin->Update();
unlink($skin_file);
unlink($patch_file);
$has_errors = false;
foreach ($output as $version => $version_output) {
$version_errors = trim(preg_replace("/(^|\n)(patching file .*?|Hunk #.*?\.)(\n|$)/m", '', $version_output));
if ( $version_errors ) {
$has_errors = true;
$output[$version] = trim(preg_replace("/(^|\n)(patching file .*?)(\n|$)/m", '', $output[$version]));
}
else {
unset($output[$version]);
}
}
if ( !$has_errors ) {
// copy patched css back to primary skin
$primary_skin->SetDBField('CSS', $skin->GetDBField('CSS'));
$primary_skin->Update();
// delete temporary skin record
$temp_handler->DeleteItems('skin', '', Array ($skin->GetID()));
return true;
}
// put clean skin from new version
$skin->SetDBField('CSS', file_get_contents(FULL_PATH . '/core/admin_templates/incs/style_template.css'));
$skin->Update();
// return output in case of errors
return $output;
}
/**
* Returns cache handlers, that are working
*
* @param string $current
* @return Array
*/
public function getWorkingCacheHandlers($current = null)
{
if ( !isset($current) ) {
$current = $this->getSystemConfig('Misc', 'CacheHandler');
}
$cache_handlers = Array (
'Fake' => 'None', 'Memcache' => 'Memcached', 'XCache' => 'XCache', 'Apc' => 'Alternative PHP Cache'
);
foreach ($cache_handlers AS $class_prefix => $title) {
$handler_class = $class_prefix . 'CacheHandler';
if ( !class_exists($handler_class) ) {
unset($cache_handlers[$class_prefix]);
}
else {
$handler = new $handler_class('localhost:11211');
/* @var $handler FakeCacheHandler */
if ( !$handler->isWorking() ) {
if ( $current == $class_prefix ) {
$cache_handlers[$class_prefix] .= ' (offline)';
}
else {
unset($cache_handlers[$class_prefix]);
}
}
}
}
return $cache_handlers;
}
/**
* Returns compression engines, that are working
*
* @param string $current
* @return Array
*/
public function getWorkingCompressionEngines($current = null)
{
if ( !isset($current) ) {
$current = $this->getSystemConfig('Misc', 'CompressionEngine');
}
$output = shell_exec('java -version 2>&1');
$compression_engines = Array ('' => 'None', 'yui' => 'YUICompressor (Java)', 'php' => 'PHP-based');
if ( stripos($output, 'java version') === false ) {
if ( $current == 'yui' ) {
$compression_engines['yui'] .= ' (offline)';
}
else {
unset($compression_engines['yui']);
}
}
return $compression_engines;
}
}
\ No newline at end of file
Index: branches/5.2.x/core/install.php
===================================================================
--- branches/5.2.x/core/install.php (revision 15129)
+++ branches/5.2.x/core/install.php (revision 15130)
@@ -1,1773 +1,1773 @@
<?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.
*/
ini_set('display_errors', 1);
error_reporting(E_ALL);
define('IS_INSTALL', 1);
define('ADMIN', 1);
define('FULL_PATH', realpath(dirname(__FILE__).'/..') );
define('REL_PATH', '/core');
// run installator
$install_engine = new kInstallator();
$install_engine->Init();
$install_engine->Run();
$install_engine->Done();
class kInstallator {
/**
* Reference to kApplication class object
*
* @var kApplication
*/
var $Application = null;
/**
* Connection to database
*
* @var kDBConnection
*/
var $Conn = null;
/**
* XML file containing steps information
*
* @var string
*/
var $StepDBFile = '';
/**
* Step name, that currently being processed
*
* @var string
*/
var $currentStep = '';
/**
* Steps list (preset) to use for current installation
*
* @var string
*/
var $stepsPreset = '';
/**
* Installation steps to be done
*
* @var Array
*/
var $steps = Array (
'fresh_install' => Array ('sys_requirements', 'check_paths', 'db_config', 'select_license', /*'download_license',*/ 'select_domain', 'root_password', 'choose_modules', 'post_config', 'sys_config', 'select_theme', 'security', 'finish'),
'clean_reinstall' => Array ('install_setup', 'sys_requirements', 'check_paths', 'clean_db', 'db_config', 'select_license', /*'download_license',*/ 'select_domain', 'root_password', 'choose_modules', 'post_config', 'sys_config', 'select_theme', 'security', 'finish'),
'already_installed' => Array ('check_paths', 'install_setup'),
'upgrade' => Array ('check_paths', 'install_setup', 'upgrade_modules', 'skin_upgrade', 'security', 'finish'),
'update_license' => Array ('check_paths', 'install_setup', 'select_license', /*'download_license',*/ 'select_domain', 'security', 'finish'),
'update_config' => Array ('check_paths', 'install_setup', 'sys_config', 'security', 'finish'),
'db_reconfig' => Array ('check_paths', 'install_setup', 'db_reconfig', 'security', 'finish'),
'sys_requirements' => Array ('check_paths', 'install_setup', 'sys_requirements', 'security', 'finish')
);
/**
* Steps, that doesn't required admin to be logged-in to proceed
*
* @var Array
*/
var $skipLoginSteps = Array ('sys_requirements', 'check_paths', 'select_license', /*'download_license',*/ 'select_domain', 'root_password', 'choose_modules', 'post_config', 'select_theme', 'security', 'finish', -1);
/**
* Steps, on which kApplication should not be initialized, because of missing correct db table structure
*
* @var Array
*/
var $skipApplicationSteps = Array ('sys_requirements', 'check_paths', 'clean_db', 'db_config', 'db_reconfig' /*, 'install_setup'*/); // remove install_setup when application will work separately from install
/**
* Folders that should be writeable to continue installation. $1 - main writeable folder from config.php ("/system" by default)
*
* @var Array
*/
var $writeableFolders = Array (
'$1',
'$1/.restricted',
'$1/images',
'$1/images/pending',
'$1/images/emoticons', // for "In-Bulletin"
'$1/user_files',
'$1/cache',
);
/**
* Contains last error message text
*
* @var string
*/
var $errorMessage = '';
/**
* Base path for includes in templates
*
* @var string
*/
var $baseURL = '';
/**
* Holds number of last executed query in the SQL
*
* @var int
*/
var $LastQueryNum = 0;
/**
* Dependencies, that should be used in upgrade process
*
* @var Array
*/
var $upgradeDepencies = Array ();
/**
* Log of upgrade - list of upgraded modules and their versions
*
* @var Array
*/
var $upgradeLog = Array ();
/**
* Common tools required for installation process
*
* @var kInstallToolkit
*/
var $toolkit = null;
function Init()
{
include_once(FULL_PATH . REL_PATH . '/kernel/kbase.php'); // required by kDBConnection class
include_once(FULL_PATH . REL_PATH . '/kernel/utility/multibyte.php'); // emulating multi-byte php extension
require_once(FULL_PATH . REL_PATH . '/install/install_toolkit.php'); // toolkit required for module installations to installator
$this->toolkit = new kInstallToolkit();
$this->toolkit->setInstallator($this);
$this->StepDBFile = FULL_PATH.'/'.REL_PATH.'/install/steps_db.xml';
$base_path = rtrim(preg_replace('/'.preg_quote(rtrim(REL_PATH, '/'), '/').'$/', '', str_replace('\\', '/', dirname($_SERVER['PHP_SELF']))), '/');
$this->baseURL = 'http://'.$_SERVER['HTTP_HOST'].$base_path.'/core/install/';
set_error_handler( Array(&$this, 'ErrorHandler') );
if (file_exists($this->toolkit->INIFile)) {
// if config.php found, then check his write permission too
$this->writeableFolders[] = $this->toolkit->defaultWritablePath . '/config.php';
}
if ( !$this->toolkit->getSystemConfig('Misc', 'WriteablePath') ) {
$this->toolkit->setSystemConfig('Misc', 'WriteablePath', $this->toolkit->defaultWritablePath);
}
if ( !$this->toolkit->getSystemConfig('Misc', 'RestrictedPath') ) {
$this->toolkit->setSystemConfig('Misc', 'RestrictedPath', $this->toolkit->getSystemConfig('Misc', 'WriteablePath') . DIRECTORY_SEPARATOR . '.restricted');
}
if ( !$this->toolkit->getSystemConfig('Misc', 'WebsitePath') ) {
$this->toolkit->setSystemConfig('Misc', 'WebsitePath', $base_path);
}
if ( $this->toolkit->systemConfigChanged ) {
// immediately save, because this paths will be used in kApplication class later
$this->toolkit->SaveConfig(true);
}
$this->currentStep = $this->GetVar('step');
// can't check login on steps where no application present anyways :)
$this->skipLoginSteps = array_unique(array_merge($this->skipLoginSteps, $this->skipApplicationSteps));
$this->SelectPreset();
if (!$this->currentStep) {
$this->SetFirstStep(); // sets first step of current preset
}
$this->InitStep();
}
function SetFirstStep()
{
reset($this->steps[$this->stepsPreset]);
$this->currentStep = current($this->steps[$this->stepsPreset]);
}
/**
* Selects preset to proceed based on various criteria
*
*/
function SelectPreset()
{
$preset = $this->GetVar('preset');
if ($this->toolkit->systemConfigFound()) {
// only at installation first step
$status = $this->CheckDatabase(false);
if ($status && $this->AlreadyInstalled()) {
// if already installed, then all future actions need login to work
$this->skipLoginSteps = Array ('check_paths', -1);
if (!$preset) {
$preset = 'already_installed';
$this->currentStep = '';
}
}
}
if ($preset === false) {
$preset = 'fresh_install'; // default preset
}
$this->stepsPreset = $preset;
}
/**
* Returns variable from request
*
* @param string $name
* @param mixed $default
* @return string|bool
* @access private
*/
private function GetVar($name, $default = false)
{
return array_key_exists($name, $_REQUEST) ? $_REQUEST[$name] : $default;
}
/**
* Sets new value for request variable
*
* @param string $name
* @param mixed $value
* @return void
* @access private
*/
private function SetVar($name, $value)
{
$_REQUEST[$name] = $value;
}
/**
* Performs needed intialization of data, that step requires
*
*/
function InitStep()
{
$require_login = !in_array($this->currentStep, $this->skipLoginSteps);
$this->InitApplication($require_login);
if ($require_login) {
// step require login to proceed
if (!$this->Application->LoggedIn()) {
$this->stepsPreset = 'already_installed';
$this->currentStep = 'install_setup'; // manually set 2nd step, because 'check_paths' step doesn't contain login form
// $this->SetFirstStep();
}
}
switch ($this->currentStep) {
case 'sys_requirements':
$required_checks = Array (
- 'php_version', 'curl', 'freetype', 'gd_version',
- 'jpeg', 'mysql', 'date.timezone', 'output_buffering',
+ 'php_version', 'curl', 'simplexml', 'freetype', 'gd_version',
+ 'jpeg', 'mysql', 'json', 'date.timezone', 'output_buffering',
);
$check_results = $this->toolkit->CallPrerequisitesMethod('core/', 'CheckSystemRequirements');
$required_checks = array_diff($required_checks, array_keys( array_filter($check_results) ));
if ( $required_checks ) {
// php-based checks failed - show error
$this->errorMessage = '<br/>Installation can not continue until all required environment parameters are set correctly';
}
elseif ( $this->GetVar('js_enabled') === false ) {
// can't check JS without form submit - set some fake error, so user stays on this step
$this->errorMessage = '&nbsp;';
}
elseif ( !$this->GetVar('js_enabled') || !$this->GetVar('cookies_enabled') ) {
// js/cookies disabled
$this->errorMessage = '<br/>Installation can not continue until all required environment parameters are set correctly';
}
break;
case 'check_paths':
$writeable_base = $this->toolkit->getSystemConfig('Misc', 'WriteablePath');
foreach ($this->writeableFolders as $folder_path) {
$file_path = FULL_PATH . str_replace('$1', $writeable_base, $folder_path);
if (file_exists($file_path) && !is_writable($file_path)) {
$this->errorMessage = '<br/>Installation can not continue until all required permissions are set correctly';
break;
}
}
break;
case 'clean_db':
// don't use Application, because all tables will be erased and it will crash
$sql = 'SELECT Path
FROM ' . TABLE_PREFIX . 'Modules';
$modules = $this->Conn->GetCol($sql);
foreach ($modules as $module_folder) {
$remove_file = '/' . $module_folder . 'install/remove_schema.sql';
if (file_exists(FULL_PATH . $remove_file)) {
$this->toolkit->RunSQL($remove_file);
}
}
$this->toolkit->deleteEditTables();
$this->currentStep = $this->GetNextStep();
break;
case 'db_config':
case 'db_reconfig':
$fields = Array (
'DBType', 'DBHost', 'DBName', 'DBUser',
'DBUserPassword', 'DBCollation', 'TablePrefix'
);
// set fields
foreach ($fields as $field_name) {
$submit_value = $this->GetVar($field_name);
if ($submit_value !== false) {
$this->toolkit->setSystemConfig('Database', $field_name, $submit_value);
}
/*else {
$this->toolkit->setSystemConfig('Database', $field_name, '');
}*/
}
break;
case 'download_license':
$license_source = $this->GetVar('license_source');
if ($license_source !== false && $license_source != 1) {
// previous step was "Select License" and not "Download from Intechnic" option was selected
$this->currentStep = $this->GetNextStep();
}
break;
case 'choose_modules':
// if no modules found, then proceed to next step
$modules = $this->ScanModules();
if (!$modules) {
$this->currentStep = $this->GetNextStep();
}
break;
case 'select_theme':
// put available theme list in database
$this->toolkit->rebuildThemes();
break;
case 'upgrade_modules':
// get installed modules from db and compare their versions to upgrade script
$modules = $this->GetUpgradableModules();
if (!$modules) {
$this->currentStep = $this->GetNextStep();
}
break;
case 'skin_upgrade':
if ($this->Application->RecallVar('SkinUpgradeLog') === false) {
// no errors during skin upgrade -> skip this step
$this->currentStep = $this->GetNextStep();
}
break;
case 'install_setup':
if ( $this->Application->TableFound(TABLE_PREFIX . 'UserSession', true) ) {
// update to 5.2.0 -> rename session table before using it
// don't rename any other table here, since their names could be used in upgrade script
$this->Conn->Query('RENAME TABLE ' . TABLE_PREFIX . 'UserSession TO ' . TABLE_PREFIX . 'UserSessions');
$this->Conn->Query('RENAME TABLE ' . TABLE_PREFIX . 'SessionData TO ' . TABLE_PREFIX . 'UserSessionData');
}
$next_preset = $this->Application->GetVar('next_preset');
if ($next_preset !== false) {
$user_helper =& $this->Application->recallObject('UserHelper');
/* @var $user_helper UserHelper */
$username = $this->Application->GetVar('login');
$password = $this->Application->GetVar('password');
if ($username == 'root') {
// verify "root" user using configuration settings
$login_result = $user_helper->loginUser($username, $password);
if ($login_result != LoginResult::OK) {
$error_phrase = $login_result == LoginResult::NO_PERMISSION ? 'la_no_permissions' : 'la_invalid_password';
$this->errorMessage = $this->Application->Phrase($error_phrase) . '. If you don\'t know your username or password, contact Intechnic Support';
}
}
else {
// non "root" user -> verify using licensing server
$url_params = Array (
'login' => md5($username),
'password' => md5($password),
'action' => 'check',
'license_code' => base64_encode( $this->toolkit->getSystemConfig('Intechnic', 'LicenseCode') ),
'version' => '4.3.0',//$this->toolkit->GetMaxModuleVersion('core/'),
'domain' => base64_encode($_SERVER['HTTP_HOST']),
);
$curl_helper =& $this->Application->recallObject('CurlHelper');
/* @var $curl_helper kCurlHelper */
$curl_helper->SetRequestData($url_params);
$file_data = $curl_helper->Send(GET_LICENSE_URL);
if ( !$curl_helper->isGoodResponseCode() ) {
$this->errorMessage = 'In-Portal servers temporarily unavailable. Please contact <a href="mailto:support@in-portal.com">In-Portal support</a> personnel directly.';
}
elseif (substr($file_data, 0, 5) == 'Error') {
$this->errorMessage = substr($file_data, 6) . ' If you don\'t know your username or password, contact Intechnic Support';
}
if ($this->errorMessage == '') {
$user_helper->loginUserById(USER_ROOT);
}
}
if ($this->errorMessage == '') {
// processed with redirect to selected step preset
if (!isset($this->steps[$next_preset])) {
$this->errorMessage = 'Preset "'.$next_preset.'" not yet implemented';
}
else {
$this->stepsPreset = $next_preset;
}
}
}
else {
// if preset was not choosen, then raise error
$this->errorMessage = 'Please select action to perform';
}
break;
case 'security':
// perform write check
if ($this->Application->GetVar('skip_security_check')) {
// administrator intensionally skips security checks
break;
}
$write_check = true;
$check_paths = Array ('/', '/index.php', $this->toolkit->defaultWritablePath . '/config.php', ADMIN_DIRECTORY . '/index.php');
foreach ($check_paths as $check_path) {
$path_check_status = $this->toolkit->checkWritePermissions(FULL_PATH . $check_path);
if (is_bool($path_check_status) && $path_check_status) {
$write_check = false;
break;
}
}
// script execute check
if (file_exists(WRITEABLE . '/install_check.php')) {
unlink(WRITEABLE . '/install_check.php');
}
$fp = fopen(WRITEABLE . '/install_check.php', 'w');
fwrite($fp, "<?php\n\techo 'OK';\n");
fclose($fp);
$curl_helper =& $this->Application->recallObject('CurlHelper');
/* @var $curl_helper kCurlHelper */
$output = $curl_helper->Send($this->Application->BaseURL(WRITEBALE_BASE) . 'install_check.php');
unlink(WRITEABLE . '/install_check.php');
$execute_check = ($output !== 'OK');
$directive_check = true;
$ini_vars = Array ('register_globals' => false, 'open_basedir' => true, 'allow_url_fopen' => false);
foreach ($ini_vars as $var_name => $var_value) {
$current_value = ini_get($var_name);
if (($var_value && !$current_value) || (!$var_value && $current_value)) {
$directive_check = false;
break;
}
}
if (!$write_check || !$execute_check || !$directive_check) {
$this->errorMessage = true;
}
/*else {
$this->currentStep = $this->GetNextStep();
}*/
break;
}
$this->PerformValidation(); // returns validation status (just in case)
}
/**
* Validates data entered by user
*
* @return bool
*/
function PerformValidation()
{
if ($this->GetVar('step') != $this->currentStep) {
// just redirect from previous step, don't validate
return true;
}
$status = true;
switch ($this->currentStep) {
case 'db_config':
case 'db_reconfig':
// 1. check if required fields are filled
$section_name = 'Database';
$required_fields = Array ('DBType', 'DBHost', 'DBName', 'DBUser', 'DBCollation');
foreach ($required_fields as $required_field) {
if (!$this->toolkit->getSystemConfig($section_name, $required_field)) {
$status = false;
$this->errorMessage = 'Please fill all required fields';
break;
}
}
if ( !$status ) {
break;
}
// 2. check permissions, that use have in this database
$status = $this->CheckDatabase(($this->currentStep == 'db_config') && !$this->GetVar('UseExistingSetup'));
break;
case 'select_license':
$license_source = $this->GetVar('license_source');
if ($license_source == 2) {
// license from file -> file must be uploaded
$upload_error = $_FILES['license_file']['error'];
if ($upload_error != UPLOAD_ERR_OK) {
$this->errorMessage = 'Missing License File';
}
}
elseif (!is_numeric($license_source)) {
$this->errorMessage = 'Please select license';
}
$status = $this->errorMessage == '';
break;
case 'root_password':
// check, that password & verify password match
$password = $this->Application->GetVar('root_password');
$password_verify = $this->Application->GetVar('root_password_verify');
if ($password != $password_verify) {
$this->errorMessage = 'Passwords does not match';
}
elseif (mb_strlen($password) < 4) {
$this->errorMessage = 'Root Password must be at least 4 characters';
}
$status = $this->errorMessage == '';
break;
case 'choose_modules':
break;
case 'upgrade_modules':
$modules = $this->Application->GetVar('modules');
if (!$modules) {
$modules = Array ();
$this->errorMessage = 'Please select module(-s) to ' . ($this->currentStep == 'choose_modules' ? 'install' : 'upgrade');
}
// check interface module
$upgrade_data = $this->GetUpgradableModules();
if (array_key_exists('core', $upgrade_data) && !in_array('core', $modules)) {
// core can be upgraded, but isn't selected
$this->errorMessage = 'Please select "Core" as interface module';
}
$status = $this->errorMessage == '';
break;
}
return $status;
}
/**
* Perform installation step actions
*
*/
function Run()
{
if ($this->errorMessage) {
// was error during data validation stage
return ;
}
switch ($this->currentStep) {
case 'db_config':
case 'db_reconfig':
// store db configuration
$sql = 'SHOW COLLATION
LIKE \''.$this->toolkit->getSystemConfig('Database', 'DBCollation').'\'';
$collation_info = $this->Conn->Query($sql);
if ($collation_info) {
$this->toolkit->setSystemConfig('Database', 'DBCharset', $collation_info[0]['Charset']);
// database is already connected, that's why set collation on the fly
$this->Conn->Query('SET NAMES \''.$this->toolkit->getSystemConfig('Database', 'DBCharset').'\' COLLATE \''.$this->toolkit->getSystemConfig('Database', 'DBCollation').'\'');
}
$this->toolkit->SaveConfig();
if ($this->currentStep == 'db_config') {
if ($this->GetVar('UseExistingSetup')) {
// abort clean install and redirect to already_installed
$this->stepsPreset = 'already_installed';
break;
}
// import base data into new database, not for db_reconfig
$this->toolkit->RunSQL('/core/install/install_schema.sql');
$this->toolkit->RunSQL('/core/install/install_data.sql');
// create category using sql, because Application is not available here
$table_name = $this->toolkit->getSystemConfig('Database', 'TablePrefix') . 'IdGenerator';
$this->Conn->Query('UPDATE ' . $table_name . ' SET lastid = lastid + 1');
$resource_id = $this->Conn->GetOne('SELECT lastid FROM ' . $table_name);
if ($resource_id === false) {
$this->Conn->Query('INSERT INTO '.$table_name.' (lastid) VALUES (2)');
$resource_id = 2;
}
// can't use USER_ROOT constant, since Application isn't available here
$fields_hash = Array (
'l1_Name' => 'Content', 'Filename' => 'Content', 'AutomaticFilename' => 0,
'CreatedById' => -1, 'CreatedOn' => time(), 'ResourceId' => $resource_id - 1,
'l1_Description' => 'Content', 'Status' => 4,
);
$this->Conn->doInsert($fields_hash, $this->toolkit->getSystemConfig('Database', 'TablePrefix') . 'Categories');
$this->toolkit->SetModuleRootCategory('Core', $this->Conn->getInsertID());
// set module "Core" version after install (based on upgrade scripts)
$this->toolkit->SetModuleVersion('Core', 'core/');
// for now we set "In-Portal" module version to "Core" module version (during clean install)
$this->toolkit->SetModuleVersion('In-Portal', 'core/');
}
break;
case 'select_license':
// reset memory cache, when application is first available (on fresh install and clean reinstall steps)
- $this->Application->HandleEvent($event, 'adm:OnResetMemcache');
+ $this->Application->HandleEvent(new kEvent('adm:OnResetMemcache'));
$license_source = $this->GetVar('license_source');
switch ($license_source) {
case 1: // Download from Intechnic
break;
case 2: // Upload License File
$file_data = array_map('trim', file($_FILES['license_file']['tmp_name']));
if ((count($file_data) == 3) && $file_data[1]) {
$modules_helper =& $this->Application->recallObject('ModulesHelper');
/* @var $modules_helper kModulesHelper */
if ($modules_helper->verifyLicense($file_data[1])) {
$this->toolkit->setSystemConfig('Intechnic', 'License', $file_data[1]);
$this->toolkit->setSystemConfig('Intechnic', 'LicenseCode', $file_data[2]);
$this->toolkit->SaveConfig();
}
else {
$this->errorMessage = 'Invalid License File';
}
}
else {
$this->errorMessage = 'Invalid License File';
}
break;
case 3: // Use Existing License
$license_hash = $this->toolkit->getSystemConfig('Intechnic', 'License');
if ($license_hash) {
$modules_helper =& $this->Application->recallObject('ModulesHelper');
/* @var $modules_helper kModulesHelper */
if (!$modules_helper->verifyLicense($license_hash)) {
$this->errorMessage = 'Invalid or corrupt license detected';
}
}
else {
// happens, when browser's "Back" button is used
$this->errorMessage = 'Missing License File';
}
break;
case 4: // Skip License (Local Domain Installation)
if ($this->toolkit->sectionFound('Intechnic')) {
// remove any previous license information
$this->toolkit->setSystemConfig('Intechnic', 'License');
$this->toolkit->setSystemConfig('Intechnic', 'LicenseCode');
$this->toolkit->SaveConfig();
}
break;
}
break;
case 'download_license':
$license_login = $this->GetVar('login');
$license_password = $this->GetVar('password');
$license_id = $this->GetVar('licenses');
$curl_helper =& $this->Application->recallObject('CurlHelper');
/* @var $curl_helper kCurlHelper */
if (strlen($license_login) && strlen($license_password) && !$license_id) {
// Here we determine weather login is ok & check available licenses
$url_params = Array (
'login' => md5($license_login),
'password' => md5($license_password),
'version' => $this->toolkit->GetMaxModuleVersion('core/'),
'domain' => base64_encode($_SERVER['HTTP_HOST']),
);
$curl_helper->SetRequestData($url_params);
$file_data = $curl_helper->Send(GET_LICENSE_URL);
if (!$file_data) {
// error connecting to licensing server
$this->errorMessage = 'Unable to connect to the Intechnic server! Please try again later!';
}
else {
if (substr($file_data, 0, 5) == 'Error') {
// after processing data server returned error
$this->errorMessage = substr($file_data, 6);
}
else {
// license received
if (substr($file_data, 0, 3) == 'SEL') {
// we have more, then one license -> let user choose
$this->SetVar('license_selection', base64_encode( substr($file_data, 4) )); // we received html with radio buttons with names "licenses"
$this->errorMessage = 'Please select which license to use';
}
else {
// we have one license
$this->toolkit->processLicense($file_data);
}
}
}
}
else if (!$license_id) {
// licenses were not queried AND user/password missing
$this->errorMessage = 'Incorrect Username or Password. If you don\'t know your username or password, contact Intechnic Support';
}
else {
// Here we download license
$url_params = Array (
'license_id' => md5($license_id),
'dlog' => md5($license_login),
'dpass' => md5($license_password),
'version' => $this->toolkit->GetMaxModuleVersion('core/'),
'domain' => base64_encode($_SERVER['HTTP_HOST']),
);
$curl_helper->SetRequestData($url_params);
$file_data = $curl_helper->Send(GET_LICENSE_URL);
if (!$file_data) {
// error connecting to licensing server
$this->errorMessage = 'Unable to connect to the Intechnic server! Please try again later!';
}
else {
if (substr($file_data, 0, 5) == 'Error') {
// after processing data server returned error
$this->errorMessage = substr($file_data, 6);
}
else {
$this->toolkit->processLicense($file_data);
}
}
}
break;
case 'select_domain':
$modules_helper =& $this->Application->recallObject('ModulesHelper');
/* @var $modules_helper kModulesHelper */
// get domain name as entered by user on the form
$domain = $this->GetVar('domain') == 1 ? $_SERVER['HTTP_HOST'] : str_replace(' ', '', $this->GetVar('other'));
$license_hash = $this->toolkit->getSystemConfig('Intechnic', 'License');
if ($license_hash) {
// when license present, then extract domain from it
$license_hash = base64_decode($license_hash);
list ( , , $license_keys) = $modules_helper->_ParseLicense($license_hash);
$license_domain = $license_keys[0]['domain'];
}
else {
// when license missing, then use current domain or domain entered by user
$license_domain = $domain;
}
if ($domain != '') {
if (strstr($domain, $license_domain) || $modules_helper->_IsLocalSite($domain)) {
$this->toolkit->setSystemConfig('Misc', 'Domain', $domain);
$this->toolkit->SaveConfig();
}
else {
$this->errorMessage = 'Domain name entered does not match domain name in the license!';
}
}
else {
$this->errorMessage = 'Please enter valid domain!';
}
break;
case 'sys_config':
$config_data = $this->GetVar('system_config');
foreach ($config_data as $section => $section_vars) {
foreach ($section_vars as $var_name => $var_value) {
$this->toolkit->setSystemConfig($section, $var_name, $var_value);
}
}
$this->toolkit->SaveConfig();
break;
case 'root_password':
// update root password in database
$password = md5( md5($this->Application->GetVar('root_password')) . 'b38');
$config_values = Array (
'RootPass' => $password,
'Backup_Path' => FULL_PATH . $this->toolkit->getSystemConfig('Misc', 'WriteablePath') . DIRECTORY_SEPARATOR . 'backupdata',
'DefaultEmailSender' => 'portal@' . $this->toolkit->getSystemConfig('Misc', 'Domain')
);
$site_timezone = ini_get('date.timezone') ? ini_get('date.timezone') : getenv('TZ');
if ($site_timezone) {
$config_values['Config_Site_Time'] = $site_timezone;
}
$this->toolkit->saveConfigValues($config_values);
$user_helper =& $this->Application->recallObject('UserHelper');
/* @var $user_helper UserHelper */
// login as "root", when no errors on password screen
$user_helper->loginUser('root', $this->Application->GetVar('root_password'));
// import base language for core (english)
$this->toolkit->ImportLanguage('/core/install/english');
// make sure imported language is set as active in session, created during installation
$this->Application->Session->SetField('Language', 1);
// set imported language as primary
$lang =& $this->Application->recallObject('lang.-item', null, Array('skip_autoload' => true));
/* @var $lang LanguagesItem */
$lang->Load(1); // fresh install => ID=1
$lang->setPrimary(true); // for Front-End
break;
case 'choose_modules':
// run module install scripts
$modules = $this->Application->GetVar('modules');
if ($modules) {
foreach ($modules as $module) {
$install_file = MODULES_PATH.'/'.$module.'/install.php';
if (file_exists($install_file)) {
include_once($install_file);
}
}
}
// update category cache
$updater =& $this->Application->makeClass('kPermCacheUpdater');
/* @var $updater kPermCacheUpdater */
$updater->OneStepRun();
break;
case 'post_config':
$this->toolkit->saveConfigValues( $this->GetVar('config') );
break;
case 'select_theme':
// 1. mark theme, that user is selected
$theme_id = $this->GetVar('theme');
$theme_table = $this->Application->getUnitOption('theme', 'TableName');
$theme_idfield = $this->Application->getUnitOption('theme', 'IDField');
$sql = 'UPDATE ' . $theme_table . '
SET Enabled = 1, PrimaryTheme = 1
WHERE ' . $theme_idfield . ' = ' . $theme_id;
$this->Conn->Query($sql);
$this->toolkit->rebuildThemes(); // rescan theme to create structure after theme is enabled !!!
// install theme dependent demo data
if ($this->Application->GetVar('install_demo_data')) {
$sql = 'SELECT Name
FROM ' . $theme_table . '
WHERE ' . $theme_idfield . ' = ' . $theme_id;
$theme_name = $this->Conn->GetOne($sql);
$site_path = $this->toolkit->getSystemConfig('Misc', 'WebsitePath') . '/';
$file_helper =& $this->Application->recallObject('FileHelper');
/* @var $file_helper FileHelper */
foreach ($this->Application->ModuleInfo as $module_name => $module_info) {
if ($module_name == 'In-Portal') {
continue;
}
$template_path = '/themes' . '/' . $theme_name . '/' . $module_info['TemplatePath'];
$this->toolkit->RunSQL( $template_path . '_install/install_data.sql', Array('{ThemeId}', '{SitePath}'), Array($theme_id, $site_path) );
if ( file_exists(FULL_PATH . $template_path . '_install/images') ) {
// copy theme demo images into writable path accessible by FCKEditor
$file_helper->copyFolderRecursive(FULL_PATH . $template_path . '_install/images' . DIRECTORY_SEPARATOR, WRITEABLE . '/user_files/Images');
}
}
}
break;
case 'upgrade_modules':
// get installed modules from db and compare their versions to upgrade script
$modules = $this->Application->GetVar('modules');
if ($modules) {
$upgrade_data = $this->GetUpgradableModules();
$start_from_query = $this->Application->GetVar('start_from_query');
$this->upgradeDepencies = $this->getUpgradeDependencies($modules, $upgrade_data);
if ($start_from_query !== false) {
$this->upgradeLog = unserialize( $this->Application->RecallVar('UpgradeLog') );
}
else {
$start_from_query = 0;
$this->upgradeLog = Array ('ModuleVersions' => Array ());
// remember each module version, before upgrade scripts are executed
foreach ($modules as $module_name) {
$module_info = $upgrade_data[$module_name];
$this->upgradeLog['ModuleVersions'][$module_name] = $module_info['FromVersion'];
}
$this->Application->RemoveVar('UpgradeLog');
}
// 1. perform "php before", "sql", "php after" upgrades
foreach ($modules as $module_name) {
$module_info = $upgrade_data[$module_name];
/*echo '<h2>Upgrading "' . $module_info['Name'] . '" to "' . $module_info['ToVersion'] . '"</h2>' . "\n";
flush();*/
if (!$this->RunUpgrade($module_info['Name'], $module_info['ToVersion'], $upgrade_data, $start_from_query)) {
$this->Application->StoreVar('UpgradeLog', serialize($this->upgradeLog));
$this->Done();
}
// restore upgradable module version (makes sense after sql error processing)
$upgrade_data[$module_name]['FromVersion'] = $this->upgradeLog['ModuleVersions'][$module_name];
}
// 2. import language pack, perform "languagepack" upgrade for all upgraded versions
foreach ($modules as $module_name) {
$module_info = $upgrade_data[$module_name];
$sqls =& $this->getUpgradeQueriesFromVersion($module_info['Path'], $module_info['FromVersion']);
preg_match_all('/' . VERSION_MARK . '/s', $sqls, $regs);
// import module language pack
$this->toolkit->ImportLanguage('/' . $module_info['Path'] . 'install/english', true);
// perform advanced language pack upgrade
foreach ($regs[1] as $version) {
$this->RunUpgradeScript($module_info['Path'], $version, 'languagepack');
}
}
// 3. update all theme language packs
$themes_helper =& $this->Application->recallObject('ThemesHelper');
/* @var $themes_helper kThemesHelper */
$themes_helper->synchronizeModule(false);
// 4. upgrade admin skin
if (in_array('core', $modules)) {
$skin_upgrade_log = $this->toolkit->upgradeSkin($upgrade_data['core']);
if ($skin_upgrade_log === true) {
$this->Application->RemoveVar('SkinUpgradeLog');
}
else {
$this->Application->StoreVar('SkinUpgradeLog', serialize($skin_upgrade_log));
}
// for now we set "In-Portal" module version to "Core" module version (during upgrade)
$this->toolkit->SetModuleVersion('In-Portal', false, $upgrade_data['core']['ToVersion']);
}
}
break;
case 'finish':
// delete cache
$this->toolkit->deleteCache();
$this->toolkit->rebuildThemes();
// compile admin skin, so it will be available in 3 frames at once
$skin_helper =& $this->Application->recallObject('SkinHelper');
/* @var $skin_helper SkinHelper */
$skin =& $this->Application->recallObject('skin', null, Array ('skip_autoload' => true));
/* @var $skin kDBItem */
$skin->Load(1, 'IsPrimary');
$skin_helper->compile($skin);
// set installation finished mark
if ($this->Application->ConfigValue('InstallFinished') === false) {
$fields_hash = Array (
'VariableName' => 'InstallFinished',
'VariableValue' => 1,
);
$this->Conn->doInsert($fields_hash, TABLE_PREFIX.'SystemSettings');
}
break;
}
if ($this->errorMessage) {
// was error during run stage
return ;
}
$this->currentStep = $this->GetNextStep();
$this->InitStep(); // init next step (that will be shown now)
$this->InitApplication();
if ($this->currentStep == -1) {
// step after last step -> redirect to admin
$user_helper =& $this->Application->recallObject('UserHelper');
/* @var $user_helper UserHelper */
$user_helper->logoutUser();
$this->Application->Redirect($user_helper->event->redirect, $user_helper->event->getRedirectParams(), '', 'index.php');
}
}
function getUpgradeDependencies($modules, &$upgrade_data)
{
$dependencies = Array ();
foreach ($modules as $module_name) {
$module_info = $upgrade_data[$module_name];
$upgrade_object =& $this->getUpgradeObject($module_info['Path']);
if (!is_object($upgrade_object)) {
continue;
}
foreach ($upgrade_object->dependencies as $dependent_version => $version_dependencies) {
if (!$version_dependencies) {
// module is independent -> skip
continue;
}
list ($parent_name, $parent_version) = each($version_dependencies);
if (!array_key_exists($parent_name, $dependencies)) {
// parent module
$dependencies[$parent_name] = Array ();
}
if (!array_key_exists($parent_version, $dependencies[$parent_name])) {
// parent module versions, that are required by other module versions
$dependencies[$parent_name][$parent_version] = Array ();
}
$dependencies[$parent_name][$parent_version][] = Array ($module_info['Name'] => $dependent_version);
}
}
return $dependencies;
}
/**
* Returns database queries, that should be executed to perform upgrade from given to lastest version of given module path
*
* @param string $module_path
* @param string $from_version
* @return string
*/
function &getUpgradeQueriesFromVersion($module_path, $from_version)
{
$upgrades_file = sprintf(UPGRADES_FILE, $module_path, 'sql');
$sqls = file_get_contents($upgrades_file);
$version_mark = preg_replace('/(\(.*?\))/', $from_version, VERSION_MARK);
// get only sqls from next (relative to current) version to end of file
$start_pos = strpos($sqls, $version_mark);
$sqls = substr($sqls, $start_pos);
return $sqls;
}
function RunUpgrade($module_name, $to_version, &$upgrade_data, &$start_from_query)
{
$module_info = $upgrade_data[ strtolower($module_name) ];
$sqls =& $this->getUpgradeQueriesFromVersion($module_info['Path'], $module_info['FromVersion']);
preg_match_all('/(' . VERSION_MARK . ')/s', $sqls, $matches, PREG_SET_ORDER + PREG_OFFSET_CAPTURE);
foreach ($matches as $index => $match) {
// upgrade version
$version = $match[2][0];
if ($this->toolkit->ConvertModuleVersion($version) > $this->toolkit->ConvertModuleVersion($to_version)) {
// only upgrade to $to_version, not further
break;
}
if (!in_array($module_name . ':' . $version, $this->upgradeLog)) {
if ($this->Application->isDebugMode()) {
$this->Application->Debugger->appendHTML('Upgrading "' . $module_name . '" to "' . $version . '" version: BEGIN.');
}
/*echo 'Upgrading "' . $module_name . '" to "' . $version . '".<br/>' . "\n";
flush();*/
// don't upgrade same version twice
$start_pos = $match[0][1] + strlen($match[0][0]);
$end_pos = array_key_exists($index + 1, $matches) ? $matches[$index + 1][0][1] : strlen($sqls);
$version_sqls = substr($sqls, $start_pos, $end_pos - $start_pos);
if ($start_from_query == 0) {
$this->RunUpgradeScript($module_info['Path'], $version, 'before');
}
if (!$this->toolkit->RunSQLText($version_sqls, null, null, $start_from_query)) {
$this->errorMessage .= '<input type="hidden" name="start_from_query" value="' . $this->LastQueryNum . '">';
$this->errorMessage .= '<br/>Module "' . $module_name . '" upgrade to "' . $version . '" failed.';
$this->errorMessage .= '<br/>Click Continue button below to skip this query and go further<br/>';
return false;
}
else {
// reset query counter, when all queries were processed
$start_from_query = 0;
}
$this->RunUpgradeScript($module_info['Path'], $version, 'after');
if ($this->Application->isDebugMode()) {
$this->Application->Debugger->appendHTML('Upgrading "' . $module_name . '" to "' . $version . '" version: END.');
}
// remember, that we've already upgraded given version
$this->upgradeLog[] = $module_name . ':' . $version;
}
if (array_key_exists($module_name, $this->upgradeDepencies) && array_key_exists($version, $this->upgradeDepencies[$module_name])) {
foreach ($this->upgradeDepencies[$module_name][$version] as $dependency_info) {
list ($dependent_module, $dependent_version) = each($dependency_info);
if (!$this->RunUpgrade($dependent_module, $dependent_version, $upgrade_data, $start_from_query)) {
return false;
}
}
}
// only mark module as updated, when all it's dependent modules are upgraded
$this->toolkit->SetModuleVersion($module_name, false, $version);
}
return true;
}
/**
* Run upgrade PHP scripts for module with specified path
*
* @param string $module_path
* @param Array $version
* @param string $mode upgrade mode = {before,after,languagepack}
*/
function RunUpgradeScript($module_path, $version, $mode)
{
$upgrade_object =& $this->getUpgradeObject($module_path);
if (!is_object($upgrade_object)) {
return ;
}
$upgrade_method = 'Upgrade_' . str_replace(Array ('.', '-'), '_', $version);
if (method_exists($upgrade_object, $upgrade_method)) {
$upgrade_object->$upgrade_method($mode);
}
}
/**
* Returns upgrade class for given module path
*
* @param string $module_path
* @return kUpgradeHelper
*/
function &getUpgradeObject($module_path)
{
static $upgrade_classes = Array ();
$upgrades_file = sprintf(UPGRADES_FILE, $module_path, 'php');
if (!file_exists($upgrades_file)) {
$false = false;
return $false;
}
if (!isset($upgrade_classes[$module_path])) {
require_once(FULL_PATH . REL_PATH . '/install/upgrade_helper.php');
// save class name, because 2nd time (in after call)
// $upgrade_class variable will not be present
include_once $upgrades_file;
$upgrade_classes[$module_path] = $upgrade_class;
}
$upgrade_object = new $upgrade_classes[$module_path]();
/* @var $upgrade_object CoreUpgrades */
$upgrade_object->setToolkit($this->toolkit);
return $upgrade_object;
}
/**
* Initialize kApplication
*
* @param bool $force initialize in any case
*/
function InitApplication($force = false)
{
if (($force || !in_array($this->currentStep, $this->skipApplicationSteps)) && !isset($this->Application)) {
// step is allowed for application usage & it was not initialized in previous step
global $start, $debugger, $dbg_options;
include_once(FULL_PATH.'/core/kernel/startup.php');
$this->Application =& kApplication::Instance();
$this->toolkit->Application =& kApplication::Instance();
$this->includeModuleConstants();
$this->Application->Init();
$this->Conn =& $this->Application->GetADODBConnection();
$this->toolkit->Conn =& $this->Application->GetADODBConnection();
}
}
/**
* When no modules installed, then pre-include all modules contants, since they are used in unit configs
*
*/
function includeModuleConstants()
{
$modules = $this->ScanModules();
foreach ($modules as $module_path) {
$constants_file = MODULES_PATH . '/' . $module_path . '/constants.php';
if ( file_exists($constants_file) ) {
kUtil::includeOnce($constants_file);
}
}
}
/**
* Show next step screen
*
* @param string $error_message
* @return void
*/
function Done($error_message = null)
{
if ( isset($error_message) ) {
$this->errorMessage = $error_message;
}
include_once (FULL_PATH . '/' . REL_PATH . '/install/incs/install.tpl');
if ( isset($this->Application) ) {
$this->Application->Done();
}
exit;
}
function ConnectToDatabase()
{
include_once FULL_PATH . '/core/kernel/db/db_connection.php';
$required_keys = Array ('DBType', 'DBUser', 'DBName');
foreach ($required_keys as $required_key) {
if (!$this->toolkit->getSystemConfig('Database', $required_key)) {
// one of required db connection settings missing -> abort connection
return false;
}
}
$this->Conn = new kDBConnection($this->toolkit->getSystemConfig('Database', 'DBType'), Array(&$this, 'DBErrorHandler'));
$this->Conn->setup( $this->toolkit->systemConfig );
// setup toolkit too
$this->toolkit->Conn =& $this->Conn;
return !$this->Conn->hasError();
}
/**
* Checks if core is already installed
*
* @return bool
*/
function AlreadyInstalled()
{
$table_prefix = $this->toolkit->getSystemConfig('Database', 'TablePrefix');
$settings_table = $this->TableExists('ConfigurationValues') ? 'ConfigurationValues' : 'SystemSettings';
$sql = 'SELECT VariableValue
FROM ' . $table_prefix . $settings_table . '
WHERE VariableName = "InstallFinished"';
return $this->TableExists($settings_table) && $this->Conn->GetOne($sql);
}
function CheckDatabase($check_installed = true)
{
// perform various check type to database specified
// 1. user is allowed to connect to database
// 2. user has all types of permissions in database
// 3. database environment settings met minimum requirements
if (mb_strlen($this->toolkit->getSystemConfig('Database', 'TablePrefix')) > 7) {
$this->errorMessage = 'Table prefix should not be longer than 7 characters';
return false;
}
// connect to database
$status = $this->ConnectToDatabase();
if ($status) {
// if connected, then check if all sql statements work
$sql_tests[] = 'DROP TABLE IF EXISTS test_table';
$sql_tests[] = 'CREATE TABLE test_table(test_col mediumint(6))';
$sql_tests[] = 'LOCK TABLES test_table WRITE';
$sql_tests[] = 'INSERT INTO test_table(test_col) VALUES (5)';
$sql_tests[] = 'UPDATE test_table SET test_col = 12';
$sql_tests[] = 'UNLOCK TABLES';
$sql_tests[] = 'ALTER TABLE test_table ADD COLUMN new_col varchar(10)';
$sql_tests[] = 'SELECT * FROM test_table';
$sql_tests[] = 'DELETE FROM test_table';
$sql_tests[] = 'DROP TABLE IF EXISTS test_table';
foreach ($sql_tests as $sql_test) {
$this->Conn->Query($sql_test);
if ($this->Conn->getErrorCode() != 0) {
$status = false;
break;
}
}
if ($status) {
// if statements work & connection made, then check table existance
if ($check_installed && $this->AlreadyInstalled()) {
$this->errorMessage = 'An In-Portal Database already exists at this location';
return false;
}
$requirements_error = Array ();
$db_check_results = $this->toolkit->CallPrerequisitesMethod('core/', 'CheckDBRequirements');
if ( !$db_check_results['version'] ) {
$requirements_error[] = '- MySQL Version is below 5.0';
}
if ( !$db_check_results['packet_size'] ) {
$requirements_error[] = '- MySQL Packet Size is below 1 MB';
}
if ( $requirements_error ) {
$this->errorMessage = 'Connection successful, but following system requirements were not met:<br/>' . implode('<br/>', $requirements_error);
return false;
}
}
else {
// user has insufficient permissions in database specified
$this->errorMessage = 'Permission Error: ('.$this->Conn->getErrorCode().') '.$this->Conn->getErrorMsg();
return false;
}
}
else {
// was error while connecting
if (!$this->Conn) return false;
$this->errorMessage = 'Connection Error: ('.$this->Conn->getErrorCode().') '.$this->Conn->getErrorMsg();
return false;
}
return true;
}
/**
* Checks if all passed tables exists
*
* @param string $tables comma separated tables list
* @return bool
*/
function TableExists($tables)
{
$prefix = $this->toolkit->getSystemConfig('Database', 'TablePrefix');
$all_found = true;
$tables = explode(',', $tables);
foreach ($tables as $table_name) {
$sql = 'SHOW TABLES LIKE "'.$prefix.$table_name.'"';
if (count($this->Conn->Query($sql)) == 0) {
$all_found = false;
break;
}
}
return $all_found;
}
/**
* Returns modules list found in modules folder
*
* @return Array
*/
function ScanModules()
{
static $modules = null;
if ( !isset($modules) ) {
// use direct include, because it's called before kApplication::Init, that creates class factory
kUtil::includeOnce( KERNEL_PATH . kApplication::MODULE_HELPER_PATH );
$modules_helper = new kModulesHelper();
$modules = $modules_helper->getModules();
}
return $modules;
}
/**
* Virtually place module under "modules" folder or it won't be recognized during upgrade to 5.1.0 version
*
* @param string $name
* @param string $path
* @param string $version
* @return string
*/
function getModulePath($name, $path, $version)
{
if ($name == 'Core') {
// don't transform path for Core module
return $path;
}
if (!preg_match('/^modules\//', $path)) {
// upgrade from 5.0.x/1.0.x to 5.1.x/1.1.x
return 'modules/' . $path;
}
return $path;
}
/**
* Returns list of modules, that can be upgraded
*
*/
function GetUpgradableModules()
{
$ret = Array ();
foreach ($this->Application->ModuleInfo as $module_name => $module_info) {
if ($module_name == 'In-Portal') {
// don't show In-Portal, because it shares upgrade scripts with Core module
continue;
}
$module_info['Path'] = $this->getModulePath($module_name, $module_info['Path'], $module_info['Version']);
$upgrades_file = sprintf(UPGRADES_FILE, $module_info['Path'], 'sql');
if (!file_exists($upgrades_file)) {
// no upgrade file
continue;
}
$sqls = file_get_contents($upgrades_file);
$versions_found = preg_match_all('/'.VERSION_MARK.'/s', $sqls, $regs);
if (!$versions_found) {
// upgrades file doesn't contain version definitions
continue;
}
$to_version = end($regs[1]);
$this_version = $this->toolkit->ConvertModuleVersion($module_info['Version']);
if ($this->toolkit->ConvertModuleVersion($to_version) > $this_version) {
// destination version is greather then current
foreach ($regs[1] as $version) {
if ($this->toolkit->ConvertModuleVersion($version) > $this_version) {
$from_version = $version;
break;
}
}
$version_info = Array (
'FromVersion' => $from_version,
'ToVersion' => $to_version,
);
$ret[ strtolower($module_name) ] = array_merge($module_info, $version_info);
}
}
return $ret;
}
/**
* Returns content to show for current step
*
* @return string
*/
function GetStepBody()
{
$step_template = FULL_PATH.'/core/install/step_templates/'.$this->currentStep.'.tpl';
if (file_exists($step_template)) {
ob_start();
include_once ($step_template);
return ob_get_clean();
}
return '{step template "'.$this->currentStep.'" missing}';
}
/**
* Parses step information file, cache result for current step ONLY & return it
*
* @return Array
*/
function &_getStepInfo()
{
static $info = Array('help_title' => null, 'step_title' => null, 'help_body' => null, 'queried' => false);
if (!$info['queried']) {
$fdata = file_get_contents($this->StepDBFile);
$parser = xml_parser_create();
xml_parse_into_struct($parser, $fdata, $values, $index);
xml_parser_free($parser);
foreach ($index['STEP'] as $section_index) {
$step_data =& $values[$section_index];
if ($step_data['attributes']['NAME'] == $this->currentStep) {
$info['step_title'] = $step_data['attributes']['TITLE'];
if (isset($step_data['attributes']['HELP_TITLE'])) {
$info['help_title'] = $step_data['attributes']['HELP_TITLE'];
}
else {
// if help title not set, then use step title
$info['help_title'] = $step_data['attributes']['TITLE'];
}
$info['help_body'] = trim($step_data['value']);
break;
}
}
$info['queried'] = true;
}
return $info;
}
/**
* Returns particular information abou current step
*
* @param string $info_type
* @return string
*/
function GetStepInfo($info_type)
{
$step_info =& $this->_getStepInfo();
if (isset($step_info[$info_type])) {
return $step_info[$info_type];
}
return '{step "'.$this->currentStep.'"; param "'.$info_type.'" missing}';
}
/**
* Returns passed steps titles
*
* @param Array $steps
* @return Array
* @see kInstaller:PrintSteps
*/
function _getStepTitles($steps)
{
$fdata = file_get_contents($this->StepDBFile);
$parser = xml_parser_create();
xml_parse_into_struct($parser, $fdata, $values, $index);
xml_parser_free($parser);
$ret = Array ();
foreach ($index['STEP'] as $section_index) {
$step_data =& $values[$section_index];
if (in_array($step_data['attributes']['NAME'], $steps)) {
$ret[ $step_data['attributes']['NAME'] ] = $step_data['attributes']['TITLE'];
}
}
return $ret;
}
/**
* Returns current step number in active steps_preset.
* Value can't be cached, because same step can have different number in different presets
*
* @return int
*/
function GetStepNumber()
{
return array_search($this->currentStep, $this->steps[$this->stepsPreset]) + 1;
}
/**
* Returns step name to process next
*
* @return string
*/
function GetNextStep()
{
$next_index = $this->GetStepNumber();
if ($next_index > count($this->steps[$this->stepsPreset]) - 1) {
return -1;
}
return $this->steps[$this->stepsPreset][$next_index];
}
/**
* Returns step name, that was processed before this step
*
* @return string
*/
function GetPreviousStep()
{
$next_index = $this->GetStepNumber() - 1;
if ($next_index < 0) {
$next_index = 0;
}
return $this->steps[$this->stepsPreset][$next_index];
}
/**
* Prints all steps from active steps preset and highlights current step
*
* @param string $active_tpl
* @param string $passive_tpl
* @return string
*/
function PrintSteps($active_tpl, $passive_tpl)
{
$ret = '';
$step_titles = $this->_getStepTitles($this->steps[$this->stepsPreset]);
foreach ($this->steps[$this->stepsPreset] as $step_name) {
$template = $step_name == $this->currentStep ? $active_tpl : $passive_tpl;
$ret .= sprintf($template, $step_titles[$step_name]);
}
return $ret;
}
/**
* Installation error handler for sql errors
*
* @param int $code
* @param string $msg
* @param string $sql
* @return bool
* @access private
*/
function DBErrorHandler($code, $msg, $sql)
{
$this->errorMessage = 'Query: <br />'.htmlspecialchars($sql).'<br />execution result is error:<br />['.$code.'] '.$msg;
return true;
}
/**
* Installation error handler
*
* @param int $errno
* @param string $errstr
* @param string $errfile
* @param int $errline
* @param Array|string $errcontext
*/
function ErrorHandler($errno, $errstr, $errfile = '', $errline = 0, $errcontext = '')
{
if ($errno == E_USER_ERROR) {
// only react on user fatal errors
$this->Done($errstr);
}
}
/**
* Checks, that given button should be visible on current installation step
*
* @param string $name
* @return bool
*/
function buttonVisible($name)
{
$button_visibility = Array (
'continue' => $this->GetNextStep() != -1 || ($this->stepsPreset == 'already_installed'),
'refresh' => in_array($this->currentStep, Array ('sys_requirements', 'check_paths', 'security')),
'back' => in_array($this->currentStep, Array (/*'select_license',*/ 'download_license', 'select_domain')),
);
if ($name == 'any') {
foreach ($button_visibility as $button_name => $button_visible) {
if ($button_visible) {
return true;
}
}
return false;
}
return array_key_exists($name, $button_visibility) ? $button_visibility[$name] : true;
}
}
Index: branches/5.2.x/tools/run_event.php
===================================================================
--- branches/5.2.x/tools/run_event.php (revision 15129)
+++ branches/5.2.x/tools/run_event.php (revision 15130)
@@ -1,43 +1,43 @@
<?php
/**
* @version $Id$
* @package In-Portal
* @copyright Copyright (C) 1997 - 2011 Intechnic. All rights reserved.
* @license GNU/GPL
* In-Portal is Open Source software.
* This means that this software may have been modified pursuant
* the GNU General Public License, and as distributed it includes
* or is derivative of works licensed under the GNU General Public License
* or other free or open source software licenses.
* See http://www.in-portal.org/license for copyright notices and details.
*/
die('Restrictred use!');
$start = microtime(true);
define('CRON', 1);
define('ADMIN', 1);
define('FULL_PATH', realpath(dirname(__FILE__) . '/..'));
define('DBG_SKIP_REPORTING', 1);
$_SERVER['HTTP_USER_AGENT'] = 'gecko';
// in command line, then 2nd argument is password
$password = isset($argv) && isset($argv[2]) ? $argv[2] : '';
if ($password != 'b674006f3edb1d9cd4d838c150b0567d') {
die('Bad key' . PHP_EOL);
}
include_once(FULL_PATH . '/core/kernel/startup.php');
$application =& kApplication::Instance();
$application->Init();
$application->StoreVar('user_id', USER_ROOT, true);
-$application->HandleEvent($ev, $argv[1]); // event name in form "prefix[.special]:event_name"
+$application->HandleEvent(new kEvent($argv[1])); // event name in form "prefix[.special]:event_name"
$application->Done();
$end = microtime(true);
\ No newline at end of file

Event Timeline