Created
June 30, 2012 06:17
-
-
Save ahwayakchih/3022618 to your computer and use it in GitHub Desktop.
Symphony-cms: IPR vs RPP timing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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