You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

395 lines
12 KiB

<?php
// (c) Copyright by authors of the Tiki Wiki CMS Groupware Project
//
// All Rights Reserved. See copyright.txt for details and a complete list of authors.
// Licensed under the GNU LESSER GENERAL PUBLIC LICENSE. See license.txt for details.
// $Id$
class SemanticLib
{
private $knownTokens = false;
private $newTokens = false;
private function loadKnownTokens()
{
if (is_array($this->knownTokens)) {
return;
}
$tikilib = TikiLib::lib('tiki');
$this->knownTokens = [];
$result = $tikilib->query("SELECT token, label, invert_token FROM tiki_semantic_tokens");
while ($row = $result->fetchRow()) {
$token = $row['token'];
$this->knownTokens[$token] = $row;
}
ksort($this->knownTokens);
}
private function loadNewTokens()
{
if (is_array($this->newTokens)) {
return;
}
$db = TikiDb::get();
$result = $db->fetchAll("SELECT DISTINCT relation FROM tiki_object_relations WHERE relation LIKE 'tiki.link.%'");
$tokens = [];
foreach ($result as $row) {
$tokens[] = substr($row['relation'], strlen('tiki.link.'));
}
$this->loadKnownTokens();
$existing = array_keys($this->knownTokens);
$this->newTokens = array_diff($tokens, $existing);
}
public function getToken($name, $field = null)
{
$this->loadKnownTokens();
if (array_key_exists($name, $this->knownTokens)) {
$data = $this->knownTokens[$name];
if (is_null($field)) {
return $data;
}
if (array_key_exists($field, $data)) {
return $data[$field];
}
}
return false;
}
public function getInvert($name, $field = null)
{
if (false !== $invert = $this->getToken($name, 'invert_token')) {
if (empty($invert)) {
$invert = $name;
}
return $this->getToken($invert, $field);
}
return false;
}
public function getTokens()
{
$this->loadKnownTokens();
return $this->knownTokens;
}
public function getNewTokens()
{
$this->loadNewTokens();
return $this->newTokens;
}
public function getAllTokens()
{
$this->loadKnownTokens();
$this->loadNewTokens();
return array_merge(array_keys($this->knownTokens), $this->newTokens);
}
public function getLinksUsing($token, $conditions = [])
{
$db = TikiDb::get();
$token = (array) $token;
$bindvars = [];
// Multiple tokens can be fetched at the same time
$values = [];
foreach ($token as $name) {
$values[] = "tiki.link.$name";
}
$mid = [ $db->in('relation', $values, $bindvars) ];
// Filter on source and destination
foreach ($conditions as $field => $value) {
if ($field == 'fromPage') {
$field = 'source_itemId';
} elseif ($field == 'toPage') {
$field = 'target_itemId';
} else {
continue;
}
$mid[] = "`$field` = ?";
$bindvars[] = $value;
}
$mid = implode(' AND ', $mid);
$result = $db->query(
$q = "SELECT `source_itemId` `fromPage`, `target_itemId` `toPage`, GROUP_CONCAT(SUBSTR(`relation` FROM 11) SEPARATOR ',') `reltype` FROM tiki_object_relations WHERE $mid AND `source_type` = 'wiki page' AND `target_type` = 'wiki page' AND `relation` LIKE 'tiki.link.%' GROUP BY `fromPage`, `toPage` ORDER BY `fromPage`, `toPage`",
$bindvars
);
$links = [];
while ($row = $result->fetchRow()) {
$row['reltype'] = explode(',', $row['reltype']);
$links[] = $row;
}
return $links;
}
public function replaceToken($oldName, $newName, $label, $invert = null)
{
$exists = ( false !== $this->getToken($oldName) );
if ($oldName != $newName && false !== $this->getToken($newName)) {
return tra('Semantic token already exists') . ": $newName";
}
if (! $this->isValid($oldName)) {
return tra('Invalid semantic token name') . ": $oldName";
}
if (! $this->isValid($newName)) {
return tra('Invalid semantic token name') . ": $newName";
}
if (false === $this->getToken($invert) || $invert == $newName) {
$invert = null;
}
$tikilib = TikiLib::lib('tiki');
if ($exists) {
$tikilib->query("DELETE FROM tiki_semantic_tokens WHERE token = ?", [ $oldName ]);
}
if (is_null($invert)) {
$tikilib->query("INSERT INTO tiki_semantic_tokens (token, label) VALUES(?,?)", [ $newName, $label ]);
} else {
$tikilib->query("INSERT INTO tiki_semantic_tokens (token, label, invert_token) VALUES(?,?,?)", [ $newName, $label, $invert ]);
}
if ($oldName != '' && $newName != $oldName) {
$tikilib->query("UPDATE tiki_semantic_tokens SET invert_token = ? WHERE invert_token = ?", [ $newName, $oldName ]);
$this->replaceReferences($oldName, $newName);
}
unset($this->knownTokens[$oldName]);
$this->knownTokens[$newName] = [
'token' => $newName,
'label' => $label,
'invert_token' => $invert,
];
ksort($this->knownTokens);
return true;
}
private function replaceReferences($oldName, $newName = null)
{
$tikilib = TikiLib::lib('tiki');
if (! $this->isValid($oldName)) {
return tra('Invalid semantic token name') . ": $oldName";
}
if (! is_null($newName) && ! $this->isValid($newName)) {
return tra('Invalid semantic token name') . ": $newName";
}
$links = $this->getLinksUsing($oldName);
$pagesDone = [];
foreach ($links as $link) {
// Page body only needs to be replaced once
if (! array_key_exists($link['fromPage'], $pagesDone)) {
$info = $tikilib->get_page_info($link['fromPage']);
$data = $info['data'];
$data = str_replace("($oldName(", "($newName(", $data);
$query = "update `tiki_pages` set `data`=?,`page_size`=? where `pageName`=?";
$tikilib->query($query, [ $data,(int) strlen($data), $link['fromPage']]);
$pagesDone[ $link['fromPage'] ] = true;
}
}
if ($newName) {
$tikilib->query('UPDATE tiki_object_relations SET relation = ? WHERE relation = ? AND source_type = "wiki page" AND target_type = "wiki page"', [ "tiki.link.$newName", "tiki.link.$oldName" ]);
} else {
$tikilib->query('DELETE FROM tiki_object_relations WHERE relation = ? AND source_type = "wiki page" AND target_type = "wiki page"', [ "tiki.link.$oldName" ]);
}
return true;
}
public function cleanToken($token)
{
$this->replaceReferences($token);
$this->newTokens = array_diff($this->newTokens, [ $token ]);
}
public function removeToken($token, $removeReferences = false)
{
$tikilib = TikiLib::lib('tiki');
if (false === $this->getToken($token)) {
return tra("Semantic token not found") . ": $token";
}
$tikilib->query("DELETE FROM tiki_semantic_tokens WHERE token = ?", [ $token ]);
unset($this->knownTokens[$token]);
if ($removeReferences) {
$this->replaceReferences($token, '');
} elseif ($this->newTokens !== false) {
$this->newTokens[] = $token;
}
return true;
}
public function renameToken($oldName, $newName)
{
$this->replaceReferences($oldName, $newName);
$this->newTokens = array_diff($this->newTokens, [ $oldName ]);
if (false === $this->getToken($newName)) {
$this->newTokens[] = $newName;
}
}
public function isValid($token)
{
return preg_match("/^[a-z0-9-]{1,15}\\z/", $token);
}
public function getRelationList($page)
{
$wikilib = TikiLib::lib('wiki');
$tikilib = TikiLib::lib('tiki');
$relations = [];
$result = $tikilib->fetchAll("SELECT `target_itemId` `toPage`, SUBSTR(`relation` FROM 11) `reltype` FROM tiki_object_relations WHERE `source_itemId` = ? AND `source_type` = 'wiki page' AND `target_type` = 'wiki page' AND `relation` LIKE 'tiki.link.%'", [$page]);
foreach ($result as $row) {
if (false === $label = $this->getToken($row['reltype'], 'label')) {
continue;
}
$label = tra($label);
if (! array_key_exists($label, $relations)) {
$relations[$label] = [];
}
if (! array_key_exists($row['toPage'], $relations[$label])) {
$relations[$label][ $row['toPage'] ] = $wikilib->sefurl($row['toPage']);
}
}
$result = $tikilib->fetchAll("SELECT `source_itemId` `fromPage`, SUBSTR(`relation` FROM 11) `reltype` FROM tiki_object_relations WHERE `target_itemId` = ? AND `source_type` = 'wiki page' AND `target_type` = 'wiki page' AND `relation` LIKE 'tiki.link.%'", [$page]);
foreach ($result as $row) {
if (false === $label = $this->getInvert($row['reltype'], 'label')) {
continue;
}
$label = tra($label);
if (! array_key_exists($label, $relations)) {
$relations[$label] = [];
}
if (! array_key_exists($row['fromPage'], $relations[$label])) {
$relations[$label][ $row['fromPage'] ] = $wikilib->sefurl($row['fromPage']);
}
}
ksort($relations);
foreach ($relations as &$set) {
ksort($set);
}
return $relations;
}
public function getAliasContaining($query, $exact_match = false, $in_lang = null)
{
global $prefs;
$tikilib = TikiLib::lib('tiki');
$orig_query = $query;
if (! $exact_match) {
$query = "%$query%";
}
$mid = "((`target_type` = 'wiki page' AND `target_itemId` LIKE ?)";
$bindvars = [$query];
$prefixes = explode(',', $prefs["wiki_prefixalias_tokens"]);
$haveprefixes = false;
foreach ($prefixes as $p) {
$p = trim($p);
if (strlen($p) > 0 && TikiLib::strtolower(substr($query, 0, strlen($p))) == TikiLib::strtolower($p)) {
$mid .= " OR ( `target_type` = 'wiki page' AND `target_itemId` LIKE ?)";
$bindvars[] = "$p%";
$haveprefixes = true;
}
}
$mid .= ") AND ( `relation` = 'tiki.link.alias' ";
if ($haveprefixes) {
$mid .= " OR `relation` = 'tiki.link.prefixalias' ";
}
$mid .= ")";
$querystring = "SELECT `source_itemId` `fromPage`, `target_itemId` `toPage` FROM `tiki_object_relations` WHERE $mid";
$aliases = $tikilib->fetchAll($querystring, $bindvars);
$aliases = $this->onlyKeepAliasesFromPageInLanguage($in_lang, $aliases);
return $aliases;
}
public function onlyKeepAliasesFromPageInLanguage($language, $aliases)
{
$multilinguallib = TikiLib::lib('multilingual');
if (! $language) {
return $aliases;
}
$aliasesInCorrectLanguage = [];
foreach ($aliases as $index => $aliasInfo) {
$aliasLang = $multilinguallib->getLangOfPage($aliasInfo['fromPage']);
if ($aliasLang === $language) {
$aliasesInCorrectLanguage[] = $aliasInfo;
}
}
// echo "<pre>-- onlyKeepAliasesFromPageInLanguage: exiting</pre>\n";
return $aliasesInCorrectLanguage;
}
public function getItemsFromTracker($page, $suffix)
{
$t_links = $this->getLinksUsing('trackerid', [ 'fromPage' => $page ]);
$f_links = $this->getLinksUsing('titlefieldid', [ 'fromPage' => $page ]);
$ret = [];
if (count($t_links) && count($f_links) && ctype_digit($t_links[0]['toPage']) && ctype_digit($f_links[0]['toPage'])) {
$trklib = TikiLib::lib('trk');
$items = $trklib->list_items($t_links[0]['toPage'], 0, -1, '', '', $f_links[0]['toPage'], '', '', '', $suffix);
foreach ($items["data"] as $i) {
$ret[] = $i["itemId"];
}
}
return $ret;
}
}