Index: branches/5.0.x/core/kernel/db/dblist.php =================================================================== diff -u -r12264 -r12294 --- branches/5.0.x/core/kernel/db/dblist.php (.../dblist.php) (revision 12264) +++ branches/5.0.x/core/kernel/db/dblist.php (.../dblist.php) (revision 12294) @@ -1,6 +1,6 @@ Application->getUnitOption($this->Prefix, 'ParentPrefix'); - if($parent_prefix) - { + 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'); Index: branches/5.0.x/core/kernel/constants.php =================================================================== diff -u -r12244 -r12294 --- branches/5.0.x/core/kernel/constants.php (.../constants.php) (revision 12244) +++ branches/5.0.x/core/kernel/constants.php (.../constants.php) (revision 12294) @@ -1,6 +1,6 @@ +* This class is a Facade for any other class which needs to deal with Kernel4 framework.
* The class incapsulates the main run-cycle of the script, provide access to all other objects in the framework.
*
-* The class is a singleton, which means that there could be only one instance of KernelApplication in the script.
-* This could be guranteed by NOT calling the class constuctor directly, but rather calling KernelApplication::Instance() method, +* The class is a singleton, which means that there could be only one instance of kApplication in the script.
+* This could be guranteed by NOT calling the class constuctor directly, but rather calling kApplication::Instance() method, * which returns an instance of the application. The method gurantees that it will return exactly the same instance for any call.
* See singleton pattern by GOF. * @package kernel4 @@ -98,6 +98,13 @@ var $ReplacementTemplates = Array (); /** + * Mod-Rewrite listeners used during url building and parsing + * + * @var Array + */ + var $RewriteListeners = Array (); + + /** * Reference to debugger * * @var Debugger @@ -1466,15 +1473,28 @@ // $params = array_merge_recursive2($this->getPassThroughVariables($params), $params); $params = array_merge($this->getPassThroughVariables($params), $params); - if ($force_rewrite || ($this->RewriteURLs($ssl) && !$no_rewrite)) - { + if ($force_rewrite || ($this->RewriteURLs($ssl) && !$no_rewrite)) { + static $rewrite_listeners_done = false; + + if (!$rewrite_listeners_done) { + $mod_rewrite_helper =& $this->recallObject('ModRewriteHelper'); + /* @var $mod_rewrite_helper kModRewriteHelper */ + + $mod_rewrite_helper->initRewriteListeners(); + + $rewrite_listeners_done = true; + } + $session =& $this->recallObject('Session'); - if( $session->NeedQueryString() && !$force_no_sid ) $params['sid'] = $this->GetSID(); + + if ($session->NeedQueryString() && !$force_no_sid) { + $params['sid'] = $this->GetSID(); + } + $url = $this->BuildEnv_NEW($t, $params, $pass, $pass_events); $ret = $this->BaseURL($prefix, $ssl).$url.$map_link; } - else - { + else { unset($params['pass_category']); // we don't need to pass it when mod_rewrite is off $env = $this->BuildEnv($t, $params, $pass, $pass_events); $ret = $this->BaseURL($prefix, $ssl).$index_file.'?'.$env.$map_link; @@ -1547,7 +1567,7 @@ foreach ($pass_info as $prefix) { list($prefix_only) = explode('.', $prefix, 1); - $sorted[$prefix] = $this->getUnitOption($prefix_only, 'PassPriority', 0); + $sorted[$prefix] = $this->getUnitOption($prefix_only, 'RewritePriority', 0); } arsort($sorted); @@ -1573,8 +1593,8 @@ $env = ''; $encode = false; - if (isset($params['__URLENCODE__'])) - { + + if (isset($params['__URLENCODE__'])) { $encode = $params['__URLENCODE__']; unset($params['__URLENCODE__']); } @@ -1583,59 +1603,104 @@ unset($params['__SSL__']); } - $m_only = true; + $catalog_item_found = false; $pass_info = $this->getPassInfo($pass); + if ($pass_info) { - if ($pass_info[0] == 'm') array_shift($pass_info); - $params['t'] = $t; - foreach($pass_info as $pass_index => $pass_element) - { - list($prefix) = explode('.', $pass_element); - $require_rewrite = $this->findModule('Var', $prefix) && $this->getUnitOption($prefix, 'CatalogItem'); - if ($require_rewrite) { + if ($pass_info[0] == 'm') { + array_shift($pass_info); + } + + $inject_parts = Array (); // url parts for beginning of url + $params['t'] = $t; // make template available for rewrite listeners + $params['pass_template'] = true; // by default we keep given template in resulting url + + if (!array_key_exists('pass_category', $params)) { + $params['pass_category'] = false; // by default we don't keep categories in url + } + + foreach ($pass_info as $pass_index => $pass_element) { + list ($prefix) = explode('.', $pass_element); + $catalog_item = $this->findModule('Var', $prefix) && $this->getUnitOption($prefix, 'CatalogItem'); + + if (array_key_exists($prefix, $this->RewriteListeners)) { // if next prefix is same as current, but with special => exclude current prefix from url - $next_prefix = getArrayValue($pass_info, $pass_index + 1); + $next_prefix = array_key_exists($pass_index + 1, $pass_info) ? $pass_info[$pass_index + 1] : false; if ($next_prefix) { $next_prefix = substr($next_prefix, 0, strlen($prefix) + 1); - if ($prefix.'.' == $next_prefix) continue; + if ($prefix . '.' == $next_prefix) { + continue; + } } - $a = $this->BuildModuleEnv_NEW($pass_element, $params, $pass_events); - if ($a) { - $ret .= '/'.$a; - $m_only = false; + + // rewrited url part + $url_part = $this->BuildModuleEnv_NEW($pass_element, $params, $pass_events); + + if (is_string($url_part) && $url_part) { + $ret .= $url_part . '/'; + + if ($catalog_item) { + // pass category later only for catalog items + $catalog_item_found = true; + } } + elseif (is_array($url_part)) { + // rewrite listener want to insert something at the beginning of url too + if ($url_part[0]) { + $inject_parts[] = $url_part[0]; + } + + if ($url_part[1]) { + $ret .= $url_part[1] . '/'; + } + + if ($catalog_item) { + // pass category later only for catalog items + $catalog_item_found = true; + } + } elseif ($url_part === false) { + // rewrite listener decided not to rewrite given $pass_element + $env .= ':' . $this->BuildModuleEnv($pass_element, $params, $pass_events); + } } - else - { - $env .= ':'.$this->BuildModuleEnv($pass_element, $params, $pass_events); + else { + $env .= ':' . $this->BuildModuleEnv($pass_element, $params, $pass_events); } } - if (!$m_only || preg_match('/c\.[-\d]*/', implode(',', $pass_info))) { - $params['pass_category'] = 1; + if ($catalog_item_found || preg_match('/c\.[-\d]*/', implode(',', $pass_info))) { + // "c" prefix is present -> keep category + $params['pass_category'] = true; } - $ret = $this->BuildModuleEnv_NEW('m', $params, $pass_events).$ret; - $cat_processed = isset($params['category_processed']) && $params['category_processed']; - if ($cat_processed) { - unset($params['category_processed']); - } - if (!$m_only || !$cat_processed || !defined('EXP_DIR_URLS')) { - $ret = trim($ret, '/').'.html'; + $params['inject_parts'] = $inject_parts; + + $ret = $this->BuildModuleEnv_NEW('m', $params, $pass_events) . '/' . $ret; + $cat_processed = array_key_exists('category_processed', $params) && $params['category_processed']; + + // remove tempporary parameters used by listeners + unset($params['t'], $params['inject_parts'], $params['pass_template'], $params['pass_category'], $params['category_processed']); + + if ($catalog_item_found || !$cat_processed || !defined('EXP_DIR_URLS')) { + // this catalog item detail page OR there is no category given + $ret = trim($ret, '/') . '.html'; } else { - $ret .= '/'; + // url ends with "/" and not with ".html" + $ret = trim($ret, '/') . '/'; } -// $ret = trim($ret, '/').'/'; - if($env) $params[ENV_VAR_NAME] = ltrim($env, ':'); + if ($env) { + $params[ENV_VAR_NAME] = ltrim($env, ':'); + } } unset($params['pass'], $params['opener'], $params['m_event']); - if ($force_admin) $params['admin'] = 1; + if ($force_admin) { + $params['admin'] = 1; + } - if( getArrayValue($params,'escape') ) - { + if (array_key_exists('escape', $params) && $params['escape']) { $ret = addslashes($ret); unset($params['escape']); } @@ -1644,30 +1709,31 @@ $params_str = ''; $join_string = $encode ? '&' : '&'; - foreach ($params as $param => $value) - { - $params_str .= $join_string.$param.'='.$value; + + foreach ($params as $param => $value) { + $params_str .= $join_string . $param . '=' . $value; } - $ret .= preg_replace('/^'.$join_string.'(.*)/', '?\\1', $params_str); + if ($params_str) { + $ret .= '?' . substr($params_str, strlen($join_string)); + } + if ($encode) { $ret = str_replace('\\', '%5C', $ret); } + return $ret; } - - function BuildModuleEnv_NEW($prefix_special, &$params, $pass_events = false) + function BuildModuleEnv_NEW($prefix_special, &$params, $keep_events = false) { - $event_params = Array('pass_events' => $pass_events, 'url_params' => $params); - $event = new kEvent($prefix_special.':BuildEnv', $event_params); - $this->HandleEvent($event); - $params = $event->getEventParam('url_params'); // save back unprocessed parameters + list ($prefix) = explode('.', $prefix_special); - $ret = ''; - if ($event->getEventParam('env_string')) { - $ret = trim( $event->getEventParam('env_string'), '/'); - } + $url_parts = Array (); + $listener = $this->RewriteListeners[$prefix]; + + $ret = $listener[0]->$listener[1](REWRITE_MODE_BUILD, $prefix_special, $params, $url_parts, $keep_events); + return $ret; } Index: branches/5.0.x/core/units/general/helpers/mod_rewrite_helper.php =================================================================== diff -u -r12151 -r12294 --- branches/5.0.x/core/units/general/helpers/mod_rewrite_helper.php (.../mod_rewrite_helper.php) (revision 12151) +++ branches/5.0.x/core/units/general/helpers/mod_rewrite_helper.php (.../mod_rewrite_helper.php) (revision 12294) @@ -1,6 +1,6 @@ HTTPQuery =& $this->Application->recallObject('HTTPQuery'); } - function SetDefaultValues(&$vars) + function processRewriteURL() { - $defaults = Array ('m_cat_id' => 0, 'm_cat_page' => 1, 'm_opener' => 's', 't' => 'index'); - foreach ($defaults as $default_key => $default_value) { - // bug: null is never returned - if ($this->HTTPQuery->Get($default_key) == null) { - $vars[$default_key] = $default_value; + $passed = Array (); + $url = $this->HTTPQuery->Get('_mod_rw_url_'); + if (substr($url, -5) == '.html') { + $url = substr($url, 0, strlen($url) - 5); + } + + $restored = false; + $sql = 'SELECT Data, Cached + FROM ' . TABLE_PREFIX . 'Cache + WHERE VarName = "mod_rw_' . md5($url) . '"'; + $cache = $this->Conn->GetRow($sql); + + if (false && $cache && $cache['Cached'] > 0) { + // not used for now + $cache = unserialize($cache['Data']); + $vars = $cache['vars']; + $passed = $cache['passed']; + $restored = true; + } + else { + $vars = $this->parseRewriteURL($url); + $passed = $vars['pass']; // also used in bottom of this method + unset($vars['pass']); + + $cache = Array ('vars' => $vars, 'passed' => $passed); + + $fields_hash = Array ( + 'VarName' => 'mod_rw_' . md5($url), + 'Data' => serialize($cache), + 'Cached' => adodb_mktime(), + ); + $this->Conn->doInsert($fields_hash, TABLE_PREFIX . 'Cache', 'REPLACE'); + + if (array_key_exists('t', $this->HTTPQuery->Post) && $this->HTTPQuery->Post['t']) { + // template from POST overrides template from URL. + $vars['t'] = $this->HTTPQuery->Post['t']; + if (isset($vars['is_virtual']) && $vars['is_virtual']) { + $vars['m_cat_id'] = 0; // this is virtual template category (for Proj-CMS) + } } + + unset($vars['is_virtual']); } + + foreach ($vars as $name => $value) { + $this->HTTPQuery->Set($name,$value); + } + +// if ($restored) { + $this->InitAll(); +// } + + $this->HTTPQuery->finalizeParsing($passed); } + function parseRewriteURL($url) + { + $sql = 'SELECT Data, Cached + FROM ' . TABLE_PREFIX . 'Cache + WHERE VarName = "mod_rw_' . md5($url) . '"'; + $vars = $this->Conn->GetRow($sql); + + if (false && $vars && $vars['Cached'] > 0) { + // not used for now + $vars = unserialize($menu['Data']); + return $vars; + } + + $vars = Array ('pass' => Array ('m')); + $url_parts = $url ? explode('/', trim($url, '/')) : Array (); + + if (($this->HTTPQuery->Get('rewrite') == 'on') || !$url_parts) { + $this->_setDefaultValues($vars); + } + + if (!$url_parts) { + $this->InitAll(); + $vars['t'] = $this->HTTPQuery->getDefaultTemplate(''); + + return $vars; + } + else { + $vars['t'] = ''; + } + + $this->_parseLanguage($url_parts, $vars); + $this->_parseTheme($url_parts, $vars); + $this->_setDefaultPages($vars); + + if ($this->_parsePage($url_parts, $vars)) { + $this->_partsFound[] = 'parsePage'; + } + + // http://site-url///[_]/