1
0
Fork 0
cl-mod-rewrite/classes/class.modrewriteurlstack.php

319 Zeilen
11 KiB
PHP

<?php
/**
* AMR url stack class
*
* @package plugin
* @subpackage Mod Rewrite
* @version SVN Revision $Rev: 128 $
* @id $Id: class.modrewriteurlstack.php 128 2019-07-03 11:58:28Z oldperl $:
* @author Murat Purc <murat@purc.de>
* @copyright four for business AG <www.4fb.de>
* @license http://www.contenido.org/license/LIZENZ.txt
* @link http://www.4fb.de
* @link http://www.contenido.org
*/
if (!defined('CON_FRAMEWORK')) {
die('Illegal call');
}
/**
* Mod rewrite url stack class. Provides features to collect urls and to get the
* pretty path and names of categories/articles at one go.
*
* Main goal of this class is to collect urls and to get the urlpath and urlname
* of the related categories/articles at one go. This will reduce the queries
* against the database.
* Therefore the full advantage will be taken by rewriting the urls at codeoutput
* in front_content.php, where you will be able to collect all urls at once...
*
* Usage:
* <code>
* // get the instance
* $oMRUrlStack = ModRewriteUrlStack::getInstance();
*
* // add several urls to fill the stack
* $oMRUrlStack->add('front_content.php?idcat=123');
* $oMRUrlStack->add('front_content.php?idart=321');
* $oMRUrlStack->add('front_content.php?idcatart=213');
* $oMRUrlStack->add('front_content.php?idcatlang=213');
* $oMRUrlStack->add('front_content.php?idartlang=312');
*
* // now the first call will get the pretty path and names from database at one go
* $aPrettyParts = $oMRUrlStack->getPrettyUrlParts('front_content.php?idcat=123');
* echo $aPrettyParts['urlpath']; // something like 'Main-category-name/Category-name/Another-category-name/'
* echo $aPrettyParts['urlname']; // something like 'Name-of-an-article'
* </code>
*
* @author Murat Purc <murat@purc.de>
* @package plugin
* @subpackage Mod Rewrite
*/
class ModRewriteUrlStack {
/**
* Self instance
*
* @var ModRewriteUrlStack
*/
private static $_instance;
/**
* Database object
*
* @var DB_Contenido
*/
private $_oDb;
/**
* Array for urls
*
* @var array
*/
private $_aUrls = array();
/**
* Url stack array
*
* @var array
*/
private $_aStack = array();
/**
* CONTENIDO related parameter array
*
* @var array
*/
private $_aConParams = array(
'idcat' => 1, 'idart' => 1, 'lang' => 1, 'idcatlang' => 1, 'idcatart' => 1, 'idartlang' => 1
);
/**
* Database tables array
*
* @var array
*/
private $_aTab;
/**
* Language id
*
* @var int
*/
private $_idLang;
/**
* Constructor, sets some properties.
*/
private function __construct() {
global $cfg, $lang;
$this->_oDb = new DB_Contenido();
$this->_aTab = $cfg['tab'];
$this->_idLang = $lang;
}
/**
* Returns a instance of ModRewriteUrlStack (singleton implementation)
*
* @return ModRewriteUrlStack
*/
public static function getInstance() {
if (self::$_instance == null) {
self::$_instance = new ModRewriteUrlStack();
}
return self::$_instance;
}
/**
* Adds an url to the stack
*
* @param string Url, like front_content.php?idcat=123...
*/
public function add($url) {
$url = ModRewrite::urlPreClean($url);
if (isset($this->_aUrls[$url])) {
return;
}
$aUrl = $this->_extractUrl($url);
// cleanup parameter
foreach ($aUrl['params'] as $p => $v) {
if (!isset($this->_aConParams[$p])) {
unset($aUrl['params'][$p]);
} else {
$aUrl['params'][$p] = (int) $v;
}
}
// add language id, if not available
if ((int) mr_arrayValue($aUrl['params'], 'lang') == 0) {
$aUrl['params']['lang'] = $this->_idLang;
}
$sStackId = $this->_makeStackId($aUrl['params']);
$this->_aUrls[$url] = $sStackId;
$this->_aStack[$sStackId] = array('params' => $aUrl['params']);
}
/**
* Returns the pretty urlparts (only category path an article name) of the
* desired url.
*
* @param string Url, like front_content.php?idcat=123...
* @return array Assoziative array like
* <code>
* $arr['urlpath']
* $arr['urlname']
* </code>
*/
public function getPrettyUrlParts($url) {
$url = ModRewrite::urlPreClean($url);
if (!isset($this->_aUrls[$url])) {
$this->add($url);
}
$sStackId = $this->_aUrls[$url];
if (!isset($this->_aStack[$sStackId]['urlpath'])) {
$this->_chunkSetPrettyUrlParts($sStackId);
}
$aPretty = array(
'urlpath' => $this->_aStack[$sStackId]['urlpath'],
'urlname' => $this->_aStack[$sStackId]['urlname']
);
return $aPretty;
}
/**
* Extracts passed url using parse_urla and adds also the 'params' array to it
*
* @param string Url, like front_content.php?idcat=123...
* @return array Components containing result of parse_url with additional
* 'params' array
*/
private function _extractUrl($url) {
$aUrl = @parse_url($url);
if (isset($aUrl['query'])) {
$aUrl['query'] = str_replace('&amp;', '&', $aUrl['query']);
parse_str($aUrl['query'], $aUrl['params']);
}
if (!isset($aUrl['params']) && !is_array($aUrl['params'])) {
$aUrl['params'] = array();
}
return $aUrl;
}
/**
* Extracts article or category related parameter from passed params array
* and generates an identifier.
*
* @param array $aParams Parameter array
* @return string Composed stack id
*/
private function _makeStackId(array $aParams) {
# idcatart
if ((int) mr_arrayValue($aParams, 'idart') > 0) {
$sStackId = 'idart_' . $aParams['idart'] . '_lang_' . $aParams['lang'];
} elseif ((int) mr_arrayValue($aParams, 'idartlang') > 0) {
$sStackId = 'idartlang_' . $aParams['idartlang'];
} elseif ((int) mr_arrayValue($aParams, 'idcatart') > 0) {
$sStackId = 'idcatart_' . $aParams['idcatart'] . '_lang_' . $aParams['lang'];
} elseif ((int) mr_arrayValue($aParams, 'idcat') > 0) {
$sStackId = 'idcat_' . $aParams['idcat'] . '_lang_' . $aParams['lang'];
} elseif ((int) mr_arrayValue($aParams, 'idcatlang') > 0) {
$sStackId = 'idcatlang_' . $aParams['idcatlang'];
} else {
$sStackId = 'lang_' . $aParams['lang'];
}
return $sStackId;
}
/**
* Main function to get the urlparts of urls.
*
* Composes the query by looping thru stored but non processed urls, executes
* the query and adds the (urlpath and urlname) result to the stack.
*
* @param type $sStackId
* @return type
*/
private function _chunkSetPrettyUrlParts($sStackId) {
// collect stack parameter to get urlpath and urlname
$aStack = array();
foreach ($this->_aStack as $stackId => $item) {
if (!isset($item['urlpath'])) {
// pretty url is to create
$aStack[$stackId] = $item;
}
}
// now, it's time to compose the where clause of the query
$sWhere = '';
foreach ($aStack as $stackId => $item) {
if ($stackId == $sStackId) {
$aP = $item['params'];
if ((int) mr_arrayValue($aP, 'idart') > 0) {
$sWhere .= '(al.idart = ' . $aP['idart'] . ' AND al.idlang = ' . $aP['lang'] . ') OR ';
} elseif ((int) mr_arrayValue($aP, 'idartlang') > 0) {
$sWhere .= '(al.idartlang = ' . $aP['idartlang'] . ') OR ';
} elseif ((int) mr_arrayValue($aP, 'idcat') > 0) {
$sWhere .= '(cl.idcat = ' . $aP['idcat'] . ' AND cl.idlang = ' . $aP['lang'] . ' AND cl.startidartlang = al.idartlang) OR ';
} elseif ((int) mr_arrayValue($aP, 'idcatart') > 0) {
$sWhere .= '(ca.idcatart = ' . $aP['idcatart'] . ' AND ca.idart = al.idart AND al.idlang = ' . $aP['lang'] . ') OR ';
} elseif ((int) mr_arrayValue($aP, 'idcatlang') > 0) {
$sWhere .= '(cl.idcatlang = ' . $aP['idcatlang'] . ' AND cl.startidartlang = al.idartlang) OR ';
}
}
}
if ($sWhere == '') {
return;
}
$sWhere = cString::getPartOfString($sWhere, 0, -4);
$sWhere = str_replace(' OR ', " OR \n", $sWhere);
// compose query and execute it
$sql = <<<SQL
SELECT
al.idartlang, al.idart, al.idlang as lang, al.urlname, cl.idcatlang, cl.idcat,
cl.urlpath, ca.idcatart
FROM
{$this->_aTab['art_lang']} AS al, {$this->_aTab['cat_lang']} AS cl, {$this->_aTab['cat_art']} AS ca
WHERE
al.idart = ca.idart AND
ca.idcat = cl.idcat AND
al.idlang = cl.idlang AND
( $sWhere )
SQL;
ModRewriteDebugger::add($sql, 'ModRewriteUrlStack->_chunkSetPrettyUrlParts() $sql');
$aNewStack = array();
// create array of fields, which are to reduce step by step from record set below
$aFields = array('', 'idart', 'idartlang', 'idcatart', 'idcat');
$this->_oDb->query($sql);
while ($this->_oDb->next_record()) {
$aRS = $this->_oDb->Record;
// loop thru fields array
foreach ($aFields as $field) {
if (isset($aRS[$field])) {
// reduce existing field
unset($aRS[$field]);
}
$rsStackID = $this->_makeStackId($aRS);
if (isset($aStack[$rsStackID])) {
// matching stack entry found, add urlpath and urlname to the new stack
$aNewStack[$rsStackID]['urlpath'] = $aRS['urlpath'];
$aNewStack[$rsStackID]['urlname'] = $aRS['urlname'];
break;
}
}
}
ModRewriteDebugger::add($aNewStack, 'ModRewriteUrlStack->_chunkSetPrettyUrlParts() $aNewStack');
ModRewriteDebugger::add($this->_aStack, 'ModRewriteUrlStack->_chunkSetPrettyUrlParts() $this->_aStack');
$this->_aStack = array_merge($this->_aStack, $aNewStack);
}
}