*/
// must be run within Dokuwiki
if(!defined('DOKU_INC')) die();
require_once(DOKU_PLUGIN.'syntax.php');
class syntax_plugin_data_related extends DokuWiki_Syntax_Plugin {
/**
* will hold the data helper plugin
*/
var $dthlp = null;
/**
* Constructor. Load helper plugin
*/
function syntax_plugin_data_related(){
$this->dthlp =& plugin_load('helper', 'data');
if(!$this->dthlp) msg('Loading the data helper failed. Make sure the data plugin is installed.',-1);
}
/**
* Return some info
*/
function getInfo(){
return $this->dthlp->getInfo();
}
/**
* What kind of syntax are we?
*/
function getType(){
return 'substition';
}
/**
* What about paragraphs?
*/
function getPType(){
return 'block';
}
/**
* Where to sort in?
*/
function getSort(){
return 155;
}
/**
* Connect pattern to lexer
*/
function connectTo($mode) {
$this->Lexer->addSpecialPattern('----+ *datarelated(?: [ a-zA-Z0-9_]*)?-+\n.*?\n----+',$mode,'plugin_data_related');
}
/**
* Handle the match - parse the data
*/
function handle($match, $state, $pos, &$handler){
// get lines and additional class
$lines = explode("\n",$match);
array_pop($lines);
$class = array_shift($lines);
$class = str_replace('datatable','',$class);
$class = trim($class,'- ');
$data = array();
$data['classes'] = $class;
$data['title'] = $this->getLang('related');
// parse info
foreach ( $lines as $line ) {
// ignore comments
$line = preg_replace('/(?dthlp->_column($col);
$data['cols'][$key] = $type;
}
break;
case 'limit':
case 'max':
$data['limit'] = abs((int) $line[1]);
break;
case 'order':
case 'sort':
list($sort) = $this->dthlp->_column($line[1]);
if(substr($sort,0,1) == '^'){
$data['sort'] = array(substr($sort,1),'DESC');
}else{
$data['sort'] = array($sort,'ASC');
}
break;
case 'where':
case 'filter':
case 'filterand':
case 'and':
$logic = 'AND';
case 'filteror':
case 'or':
if(preg_match('/^(.*?)(=|<|>|<=|>=|<>|!=|=~|~)(.*)$/',$line[1],$matches)){
list($key) = $this->dthlp->_column(trim($matches[1]));
$val = trim($matches[3]);
$val = sqlite_escape_string($val); //pre escape
$com = $matches[2];
if($com == '<>'){
$com = '!=';
}elseif($com == '=~' || $com == '~'){
$com = 'LIKE';
$val = str_replace('*','%',$val);
}
$data['filter'][] = array('key' => $key,
'value' => $val,
'compare' => $com,
'logic' => $logic
);
}
break;
default:
msg("data plugin: unknown option '".hsc($line[0])."'",-1);
}
}
return $data;
}
/**
* Create output
*/
function render($format, &$renderer, $data) {
global $ID;
if($format != 'xhtml') return false;
if(!$this->dthlp->_dbconnect()) return false;
$sql = $this->_buildSQL($data,$ID);
if(!$sql) return true; // sql build
$res = sqlite_query($this->dthlp->db,$sql);
if(!sqlite_num_rows($res)) return true; // no rows matched
$renderer->doc .= '
';
$renderer->doc .= '- '.htmlspecialchars($data['title']).'
';
$renderer->doc .= '- ';
$renderer->listu_open();
while ($row = sqlite_fetch_array($res, SQLITE_ASSOC)) {
$renderer->listitem_open(1);
$renderer->internallink($row['page']);
$renderer->listitem_close();
}
$renderer->listu_close();
$renderer->doc .= '
';
$renderer->doc .= '
';
return true;
}
/**
* Builds the SQL query from the given data
*/
function _buildSQL(&$data,$id){
$cnt = 1;
$tables = array();
$cond = array();
$from = '';
$where = '';
$order = '';
// prepare the columns to match against
$found = false;
foreach (array_keys($data['cols']) as $col){
// get values for current page:
$values = array();
$sql = "SELECT A.value
FROM data A, pages B
WHERE key = '".sqlite_escape_string($col)."'
AND A.pid = B.pid
AND B.page = '".sqlite_escape_string($id)."'";
$res = sqlite_query($this->dthlp->db,$sql);
while ($row = sqlite_fetch_array($res, SQLITE_NUM)) {
if($row[0]) $values[] = $row[0];
}
if(!count($values)) continue; // no values? ignore the column.
$found = true;
$values = array_map('sqlite_escape_string',$values);
$cond[] = " ( T1.key = '".sqlite_escape_string($col)."'".
" AND T1.value IN ('".join("','",$values)."') )\n";
}
$where .= ' AND ('.join(' OR ',$cond).') ';
// any tags to compare?
if(!$found) return false;
// prepare sorting
if($data['sort'][0]){
$col = $data['sort'][0];
if($col == '%pageid%'){
$order = ', pages.page '.$data['sort'][1];
}elseif($col == '%title%'){
$order = ', pages.title '.$data['sort'][1];
}else{
// sort by hidden column?
if(!$tables[$col]){
$tables[$col] = 'T'.(++$cnt);
$from .= ' LEFT JOIN data AS '.$tables[$col].' ON '.$tables[$col].'.pid = pages.pid';
$from .= ' AND '.$tables[$col].".key = '".sqlite_escape_string($col)."'";
}
$order = ', '.$tables[$col].'.value '.$data['sort'][1];
}
}else{
$order = ', pages.page';
}
// add filters
if(is_array($data['filter']) && count($data['filter'])){
$where .= ' AND ( 1=1 ';
foreach($data['filter'] as $filter){
$col = $filter['key'];
if($col == '%pageid%'){
$where .= " ".$filter['logic']." pages.page ".$filter['compare']." '".$filter['value']."'";
}elseif($col == '%title%'){
$where .= " ".$filter['logic']." pages.title ".$filter['compare']." '".$filter['value']."'";
}else{
// filter by hidden column?
if(!$tables[$col]){
$tables[$col] = 'T'.(++$cnt);
$from .= ' LEFT JOIN data AS '.$tables[$col].' ON '.$tables[$col].'.pid = pages.pid';
$from .= ' AND '.$tables[$col].".key = '".sqlite_escape_string($col)."'";
}
$where .= ' '.$filter['logic'].' '.$tables[$col].'.value '.$filter['compare'].
" '".$filter['value']."'"; //value is already escaped
}
}
$where .= ' ) ';
}
// build the query
$sql = "SELECT pages.pid, pages.page as page, pages.title as title, COUNT(*) as rel
FROM pages, data as T1 $from
WHERE pages.pid = T1.pid
AND pages.page != '".sqlite_escape_string($id)."'
$where
GROUP BY pages.pid
ORDER BY rel DESC$order";
// limit
if($data['limit']){
$sql .= ' LIMIT '.($data['limit']);
}
return $sql;
}
}