Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@ahwayakchih
Created June 30, 2012 06:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ahwayakchih/3022618 to your computer and use it in GitHub Desktop.
Save ahwayakchih/3022618 to your computer and use it in GitHub Desktop.
Symphony-cms: IPR vs RPP timing
<?php
Class extension_improvedpageresolve extends Extension{
public function about() {
return array('name' => __('Improved Page Resolve'),
'version' => '1.2',
'release-date' => '2012-06-28',
'author' => array('name' => 'Marcin Konicki',
'website' => 'http://ahwayakchih.neoni.net',
'email' => 'ahwayakchih@neoni.net'),
'description' => __('Pass parameters to index if none of them selects a valid page.')
);
}
public function getSubscribedDelegates(){
return array(
array(
'page' => '/frontend/',
'delegate' => 'FrontendPrePageResolve',
'callback' => '__pagePreResolve'
),
array(
'page' => '/frontend/',
'delegate' => 'FrontendParamsResolve',
'callback' => '__pageParamsResolve'
),
);
}
function __getIndexPage(){
$row = Symphony::Database()->fetchRow(0, "SELECT `tbl_pages`.* FROM `tbl_pages`, `tbl_pages_types`
WHERE `tbl_pages_types`.page_id = `tbl_pages`.id
AND tbl_pages_types.`type` = 'index'
LIMIT 1");
return $row;
}
function _get_fallback(){
$default_fallback = '';
$val = Symphony::Configuration()->get('fallback', 'maptofront');
return (isset($val)) ? $val : $default_fallback;
}
public function __pagePreResolve($ctx) {
// context array contains: &$row, $page
if($this->alreadyRan) return;
/*
Test current RPP code.
*/
$start = microtime(true);
if(!$this->alreadyRan){
$this->alreadyRan = true;
//the only way to access the current (active) pages.
$front = FrontEnd::Page();
if(!$front->resolvePage($ctx['page'])){
//uses home page if no page is set in the config panel.
if($this->_get_fallback() == ''){
$indexPage = $this->__getIndexPage();
$indexHandle = $indexPage['handle'];
}
else{
$indexHandle = $this->_get_fallback();
}
//adds the home page to the handle, if the current page is not found.
//requires the home page to fallback to a 404 if the params do not match, otherwise no 404 error will ever be created.
$params = $ctx['page'];
if(Symphony::Configuration()->get('map_sub_to_front', 'maptofront') == 'no'){
$tmp = substr($indexHandle,0, strrpos($indexHandle, '/'));
if(strlen($tmp) > 0){
$params = substr($ctx['page'], strpos($ctx['page'], $tmp)+strlen($tmp));
}
else{
$params = '';
}
}
//$ctx['page'] = $indexHandle.$params;
}
}
$RPP = microtime(true) - $start;
var_dump('RPP: '.$RPP.'s');
/*
Test current IPR code.
*/
$start = microtime(true);
$page = trim($ctx['page'], '/');
if (!empty($ctx['row']) || empty($page)) return;
$nodeCount = substr_count($page, '/') + 1;
$row = Symphony::Database()->fetchRow(0, "SELECT p.*, t.type FROM `tbl_pages` p
LEFT JOIN `tbl_pages_types` t ON p.id = t.page_id AND t.type = 'index'
WHERE POSITION(CONCAT_WS('/', p.path, p.handle) IN '".Symphony::Database()->cleanValue($page)."') = 1 OR
(t.type = 'index' AND p.params IS NOT NULL AND (LENGTH(p.params)-LENGTH(REPLACE(COALESCE(p.params,''), '/', ''))+1) >= {$nodeCount})
ORDER BY t.type != 'index' ASC, (LENGTH(p.path)-LENGTH(REPLACE(COALESCE(p.path,''), '/', ''))+1) DESC, p.sortorder DESC
LIMIT 1");
if (!$row) $row = array();
$path = ($row['path'] ? $row['path'].'/'.$row['handle'] : $row['handle']);
$values = trim(preg_replace('/^'.preg_quote($path, '/').'/i', '', $page), '/');
if (!empty($values)) {
// Try to stay compatible with original by rejecting page if there are too many values passed to it
if (empty($row['params'])) $row = array();
else {
$values = preg_split('/\//', $values, -1, PREG_SPLIT_NO_EMPTY);
$params = preg_split('/\//', $row['params'], -1, PREG_SPLIT_NO_EMPTY);
if (count($params) < count($values)) $row = array();
else if (!empty($values)) {
// There is no way to tell Frontpage to set _env['url'] values
// (_env is private, and is overwritten with NULL values right after delegate returns).
// We also can't set Frontpage->_param directly, because it is recreated later (after FrontendPageResolved delegate).
// Nor we can store params localy, because extension seems to be recreated every time delegate is called.
// So we store params in global place (Frontend::instance() :) and inject them when FrontendParamsResolve delegate is called.
Frontend::instance()->__improvedpageresolve['params'] = array_combine($params, array_pad($values, count($params), NULL));
}
}
}
$IPR = microtime(true) - $start;
var_dump('IPR: '.$IPR.'s');
/*
Test using pre-calculated data, which could be saved with regular pages, whenever a page is saved.
CREATE TABLE `sym_pages_resolve` (`id` int(11) unsigned NOT NULL auto_increment,`parent` int(11) default NULL,`title` varchar(255) collate utf8_unicode_ci NOT NULL default '',`handle` varchar(255) collate utf8_unicode_ci default NULL,`path` varchar(255) collate utf8_unicode_ci default NULL,`params` varchar(255) collate utf8_unicode_ci default NULL,`data_sources` text collate utf8_unicode_ci,`events` text collate utf8_unicode_ci,`sortorder` int(11) NOT NULL default '0',`is_index` tinyint(1) NOT NULL default '0',`params_count` int(11) NOT NULL default '0',`fullpath` varchar(255) collate utf8_unicode_ci NOT NULL default '',PRIMARY KEY (`id`),KEY `parent` (`parent`),KEY `sorter` (`is_index`,`params_count`,`sortorder`)) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
INSERT INTO `sym_pages_resolve` SELECT p.id, p.parent, p.title, p.handle, p.path, p.params, p.data_sources, p.events, p.sortorder, (pt.id > 0), (LENGTH(p.params)-LENGTH(REPLACE(COALESCE(p.params,''), '/', ''))+1), CONCAT_WS('/', p.path, p.handle, '%') FROM `sym_pages` p LEFT JOIN `sym_pages_types` pt ON pt.page_id = p.id AND pt.type = 'index' GROUP BY p.id;
*/
Symphony::Database()->query("CREATE TABLE IF NOT EXISTS `tbl_pages_resolve` (`id` int(11) unsigned NOT NULL auto_increment,`parent` int(11) default NULL,`title` varchar(255) collate utf8_unicode_ci NOT NULL default '',`handle` varchar(255) collate utf8_unicode_ci default NULL,`path` varchar(255) collate utf8_unicode_ci default NULL,`params` varchar(255) collate utf8_unicode_ci default NULL,`data_sources` text collate utf8_unicode_ci,`events` text collate utf8_unicode_ci,`sortorder` int(11) NOT NULL default '0',`is_index` tinyint(1) NOT NULL default '0',`params_count` int(11) NOT NULL default '0',`fullpath` varchar(255) collate utf8_unicode_ci NOT NULL default '',PRIMARY KEY (`id`),KEY `parent` (`parent`),KEY `sorter` (`is_index`,`params_count`,`sortorder`)) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;");
if (Symphony::Database()->fetchVar('num', 0, "SELECT count(id) AS num FROM `tbl_pages_resolve`") < 1) {
Symphony::Database()->query("INSERT INTO `tbl_pages_resolve` SELECT p.id, p.parent, p.title, p.handle, p.path, p.params, p.data_sources, p.events, p.sortorder, (pt.id > 0), (LENGTH(p.params)-LENGTH(REPLACE(COALESCE(p.params,''), '/', ''))+1), CONCAT_WS('/', p.path, p.handle, '%') FROM `tbl_pages` p LEFT JOIN `tbl_pages_types` pt ON pt.page_id = p.id AND pt.type = 'index' GROUP BY p.id ON DUPLICATE KEY UPDATE id = VALUES(id);");
}
$start = microtime(true);
$page = trim($ctx['page'], '/');
if (!empty($ctx['row']) || empty($page)) return;
$nodeCount = substr_count($page, '/') + 1;
$row = Symphony::Database()->fetchRow(0, "SELECT p.* FROM tbl_pages_resolve p
WHERE '".Symphony::Database()->cleanValue($page)."' LIKE p.fullpath OR (p.is_index = 1 AND p.params_count >= {$nodeCount})
ORDER BY p.is_index ASC, p.params_count DESC, p.sortorder DESC LIMIT 1");
if (!$row) $row = array();
$path = ($row['path'] ? $row['path'].'/'.$row['handle'] : $row['handle']);
$values = trim(preg_replace('/^'.preg_quote($path, '/').'/i', '', $page), '/');
if (!empty($values)) {
// Try to stay compatible with original by rejecting page if there are too many values passed to it
if (empty($row['params'])) $row = array();
else {
$values = preg_split('/\//', $values, -1, PREG_SPLIT_NO_EMPTY);
$params = preg_split('/\//', $row['params'], -1, PREG_SPLIT_NO_EMPTY);
if (count($params) < count($values)) $row = array();
else if (!empty($values)) {
// There is no way to tell Frontpage to set _env['url'] values
// (_env is private, and is overwritten with NULL values right after delegate returns).
// We also can't set Frontpage->_param directly, because it is recreated later (after FrontendPageResolved delegate).
// Nor we can store params localy, because extension seems to be recreated every time delegate is called.
// So we store params in global place (Frontend::instance() :) and inject them when FrontendParamsResolve delegate is called.
Frontend::instance()->__improvedpageresolve['params'] = array_combine($params, array_pad($values, count($params), NULL));
}
}
}
$IPR = microtime(true) - $start;
var_dump('IPR2: '.$IPR.'s');
//Symphony::Database()->query('DROP TABLE `tbl_pages_resolve`');
$ctx['row'] = $row;
}
public function __pageParamsResolve($ctx) {
// context array contains: &$params
$Frontend = Frontend::instance();
if (!isset($Frontend->__improvedpageresolve)) return;
if (!empty($Frontend->__improvedpageresolve['params'])) {
$ctx['params'] = array_merge($ctx['params'], $Frontend->__improvedpageresolve['params']);
}
unset($Frontend->__improvedpageresolve);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment