Commit 5b6738686b28b64e036c06ff32c5f7c451b6ffba

Authored by Megan Watson
2 parents f2d9616a 574801c7

Merge branch 'master' of git@github.com:ktgit/knowledgetree

ktapi/ktapi.inc.php
... ... @@ -50,7 +50,7 @@ require_once(KT_LIB_DIR . '/foldermanagement/folderutil.inc.php');
50 50 require_once(KT_LIB_DIR . '/browse/DocumentCollection.inc.php');
51 51 require_once(KT_LIB_DIR . "/browse/columnregistry.inc.php");
52 52  
53   -define('KTAPI_DIR',KT_DIR . '/ktapi');
  53 +define('KTAPI_DIR', KT_DIR . '/ktapi');
54 54  
55 55 require_once(KTAPI_DIR .'/KTAPIConstants.inc.php');
56 56 require_once(KTAPI_DIR .'/KTAPISession.inc.php');
... ... @@ -2083,9 +2083,15 @@ class KTAPI
2083 2083 return $response;
2084 2084 }
2085 2085 $newfolder = $folder->add_folder($folder_name);
  2086 + if (PEAR::isError($newfolder))
  2087 + {
  2088 + $response['status_code'] = 1;
  2089 + $response['message']= $newfolder->getMessage();
  2090 + return $response;
  2091 + }
2086 2092 $response['status_code'] = 0;
2087 2093 $response['message'] = '';
2088   - $response['results'] = $newfolder->get_detail();
  2094 + $response['results'] = $newfolder->get_detail();
2089 2095 return $response;
2090 2096 }
2091 2097  
... ... @@ -3519,9 +3525,7 @@ class KTAPI
3519 3525 return $response;
3520 3526 }
3521 3527  
3522   -
3523 3528 return $this->get_document_detail($document_id);
3524   -
3525 3529 }
3526 3530  
3527 3531 /**
... ... @@ -4658,7 +4662,7 @@ class KTAPI
4658 4662 public function electronic_sig_enabled()
4659 4663 {
4660 4664 // Check that the wintools plugin is active and available, return false if not.
4661   - if (KTPluginUtil::pluginIsActive('ktdms.wintools')) {
  4665 + if (!KTPluginUtil::pluginIsActive('ktdms.wintools')) {
4662 4666 return false;
4663 4667 }
4664 4668  
... ... @@ -4676,11 +4680,11 @@ class KTAPI
4676 4680 *
4677 4681 * @author KnowledgeTree Team
4678 4682 * @access private
4679   - * @param string $username The users username.
4680   - * @param string $password The users password.
4681   - * @param string $comment A comment on the action performed.
4682   - * @param string $action The action performed.
4683   - * @param string $details Details about the action performed.
  4683 + * @param string $username The user's username
  4684 + * @param string $password The user's password
  4685 + * @param string $comment A comment on the action performed
  4686 + * @param string $action The action performed
  4687 + * @param string $details Details about the action performed
4684 4688 * @return bool True if authenticated | False if rejected
4685 4689 */
4686 4690 private function _authenticateSignature($username, $password, $comment, $action, $details)
... ... @@ -4696,6 +4700,16 @@ class KTAPI
4696 4700  
4697 4701 /**
4698 4702 * Method to execute electronic signature checks on action
  4703 + *
  4704 + * @author KnowledgeTree Team
  4705 + * @access private
  4706 + * @param string $item_id ID of document/folder which will be used as detail string in authentication records
  4707 + * @param string $username The user's username
  4708 + * @param string $password The user's password
  4709 + * @param string $comment A comment on the action performed
  4710 + * @param string $details Unused
  4711 + * @param string $action The action performed
  4712 + * @return array $response containing success/failure result and appropriate message
4699 4713 */
4700 4714 private function _check_electronic_signature($item_id, $username, $password, $comment, $details, $action)
4701 4715 {
... ...
search2/search/expr.inc.php
... ... @@ -40,7 +40,6 @@
40 40  
41 41 /**
42 42 * This is the ideal case, but more complex
43   - *
44 43 */
45 44  
46 45 // TODO: search expression evaluation needs some optimisation
... ... @@ -49,6 +48,14 @@ require_once('indexing/indexerCore.inc.php');
49 48 require_once('search/fieldRegistry.inc.php');
50 49 require_once('search/exprConstants.inc.php');
51 50  
  51 +/**
  52 + *
  53 + *
  54 + * This class handles the ranking of search results
  55 + *
  56 + * @author KnowledgeTree Team
  57 + * @package Search
  58 + */
52 59 class RankManager
53 60 {
54 61 /**
... ... @@ -76,6 +83,12 @@ class RankManager
76 83 */
77 84 private $text;
78 85  
  86 + /**
  87 + * Builds the RankManager object from the database
  88 + *
  89 + * @author KnowledgeTree Team
  90 + * @access private
  91 + */
79 92 private function __construct()
80 93 {
81 94 $this->dbfields=array();
... ... @@ -107,9 +120,11 @@ class RankManager
107 120 }
108 121  
109 122 /**
110   - * Enter description here...
  123 + * Gets the RankManager object
111 124 *
112   - * @return RankManager
  125 + * @author KnowledgeTree Team
  126 + * @access public
  127 + * @return object RankManager
113 128 */
114 129 public static function get()
115 130 {
... ... @@ -121,6 +136,15 @@ class RankManager
121 136 return $singleton;
122 137 }
123 138  
  139 + /**
  140 + * Applies the appropriate score to a matched field
  141 + *
  142 + * @author KnowledgeTree Team
  143 + * @access public
  144 + * @param string $groupname The group to which the field belongs
  145 + * @return int The score for this field or 0 if not matched with
  146 + * any score
  147 + */
124 148 public function scoreField($groupname, $type='T', $itemname='')
125 149 {
126 150 switch($type)
... ... @@ -145,7 +169,12 @@ class RankManager
145 169 }
146 170 }
147 171  
148   -
  172 +/**
  173 + * This is the base class for parsing search expressions
  174 + *
  175 + * @author KnowledgeTree Team
  176 + * @package Search
  177 + */
149 178 class Expr
150 179 {
151 180 /**
... ... @@ -317,6 +346,12 @@ class Expr
317 346 }
318 347 }
319 348  
  349 +/**
  350 + * This is the base class for Field expressions
  351 + *
  352 + * @author KnowledgeTree Team
  353 + * @package Search
  354 + */
320 355 class FieldExpr extends Expr
321 356 {
322 357 /**
... ... @@ -428,6 +463,12 @@ class FieldExpr extends Expr
428 463 }
429 464 }
430 465  
  466 +/**
  467 + * This class defines the contexts to which a search expression may apply
  468 + *
  469 + * @author KnowledgeTree Team
  470 + * @package Search
  471 + */
431 472 class ExprContext
432 473 {
433 474 const DOCUMENT = 1;
... ... @@ -435,7 +476,12 @@ class ExprContext
435 476 const DOCUMENT_AND_FOLDER = 3;
436 477 }
437 478  
438   -
  479 +/**
  480 + * This is the base class for Database Field Expressions
  481 + *
  482 + * @author KnowledgeTree Team
  483 + * @package Search
  484 + */
439 485 class DBFieldExpr extends FieldExpr
440 486 {
441 487 /**
... ... @@ -515,6 +561,12 @@ class DBFieldExpr extends FieldExpr
515 561 }
516 562 }
517 563  
  564 +/**
  565 + * This is the base class for Metadata Field Expressions
  566 + *
  567 + * @author KnowledgeTree Team
  568 + * @package Search
  569 + */
518 570 class MetadataField extends DBFieldExpr
519 571 {
520 572 protected $fieldset;
... ... @@ -561,6 +613,12 @@ class MetadataField extends DBFieldExpr
561 613  
562 614 }
563 615  
  616 +/**
  617 + * This is the base class for Text Expressions
  618 + *
  619 + * @author KnowledgeTree Team
  620 + * @package Search
  621 + */
564 622 class SearchableText extends FieldExpr
565 623 {
566 624 }
... ... @@ -782,8 +840,6 @@ class ValueListExpr extends Expr
782 840 }
783 841 }
784 842  
785   -
786   -
787 843 public function rewrite(&$left, &$op, &$right, &$not)
788 844 {
789 845 if (count($this->values) == 1)
... ... @@ -813,7 +869,6 @@ class ValueListExpr extends Expr
813 869  
814 870 }
815 871  
816   -
817 872 class BetweenValueExpr extends ValueExpr
818 873 {
819 874 protected $endvalue;
... ... @@ -893,6 +948,12 @@ interface QueryBuilder
893 948  
894 949 }
895 950  
  951 +/**
  952 + * This class builds queries for text content searches
  953 + *
  954 + * @author KnowledgeTree Team
  955 + * @package Search
  956 + */
896 957 class TextQueryBuilder implements QueryBuilder
897 958 {
898 959 private $text;
... ... @@ -984,6 +1045,12 @@ class TextQueryBuilder implements QueryBuilder
984 1045 }
985 1046 }
986 1047  
  1048 +/**
  1049 + * This class builds queries for database searches
  1050 + *
  1051 + * @author KnowledgeTree Team
  1052 + * @package Search
  1053 + */
987 1054 class SQLQueryBuilder implements QueryBuilder
988 1055 {
989 1056 private $used_tables;
... ... @@ -994,6 +1061,14 @@ class SQLQueryBuilder implements QueryBuilder
994 1061 private $context;
995 1062 private $incl_status = true;
996 1063  
  1064 + /**
  1065 + * Constructor for the SQL query builder
  1066 + * Sets the database tables to be used in the search query
  1067 + *
  1068 + * @author KnowledgeTree Team
  1069 + * @access public
  1070 + * @param string $context The context to which the search applies
  1071 + */
997 1072 public function __construct($context)
998 1073 {
999 1074 $this->context = $context;
... ... @@ -1016,7 +1091,7 @@ class SQLQueryBuilder implements QueryBuilder
1016 1091 'tag_words'=>'tw',
1017 1092 'document_fields_link'=>'pdfl'
1018 1093 );
1019   - break;
  1094 + break;
1020 1095 case ExprContext::FOLDER:
1021 1096 $this->used_tables = array(
1022 1097 'folders'=>1,
... ... @@ -1025,7 +1100,7 @@ class SQLQueryBuilder implements QueryBuilder
1025 1100 $this->aliases = array(
1026 1101 'folders'=>'f',
1027 1102 );
1028   - break;
  1103 + break;
1029 1104 default:
1030 1105 throw new Exception('This was not expected - Context = ' . $context);
1031 1106 }
... ... @@ -1035,6 +1110,14 @@ class SQLQueryBuilder implements QueryBuilder
1035 1110 $this->metadata = array();
1036 1111 }
1037 1112  
  1113 + /**
  1114 + * Sets the value which determines whether archived/deleted documents
  1115 + * are to be included in search results
  1116 + *
  1117 + * @author KnowledgeTree Team
  1118 + * @access public
  1119 + * @param bool $incl
  1120 + */
1038 1121 public function setIncludeStatus($incl)
1039 1122 {
1040 1123 $this->incl_status = $incl;
... ... @@ -1043,6 +1126,7 @@ class SQLQueryBuilder implements QueryBuilder
1043 1126 /**
1044 1127 * This looks up a table name to find the appropriate alias.
1045 1128 *
  1129 + * @access private
1046 1130 * @param string $tablename
1047 1131 * @return string
1048 1132 */
... ... @@ -1055,6 +1139,15 @@ class SQLQueryBuilder implements QueryBuilder
1055 1139 throw new Exception("Unknown tablename '$tablename'");
1056 1140 }
1057 1141  
  1142 + /**
  1143 + * This method parses an expression into simpler individual expressions
  1144 + * (if not already as simple as possible)
  1145 + * evaluates each individually to determine the query content and table usage
  1146 + *
  1147 + * @access private
  1148 + * @param object $expr
  1149 + * @param object $parent
  1150 + */
1058 1151 private function exploreExprs($expr, $parent=null)
1059 1152 {
1060 1153 if ($expr->isMetadataField())
... ... @@ -1091,6 +1184,11 @@ class SQLQueryBuilder implements QueryBuilder
1091 1184 }
1092 1185 }
1093 1186  
  1187 + /**
  1188 + * Determine table usage for a simple (metadata) query
  1189 + *
  1190 + * @param array $group
  1191 + */
1094 1192 private function exploreGroup($group)
1095 1193 {
1096 1194 // split up metadata and determine table usage
... ... @@ -1114,6 +1212,15 @@ class SQLQueryBuilder implements QueryBuilder
1114 1212 }
1115 1213 }
1116 1214  
  1215 + /**
  1216 + * Determines the field to be checked for an expression
  1217 + * If joins are defined for this expression the function will
  1218 + * modify the fieldname accordingly
  1219 + *
  1220 + * @access private
  1221 + * @param string $expr
  1222 + * @return string $fieldname
  1223 + */
1117 1224 private function getFieldnameFromExpr($expr)
1118 1225 {
1119 1226 $field = $expr->left();
... ... @@ -1133,9 +1240,15 @@ class SQLQueryBuilder implements QueryBuilder
1133 1240 return $fieldname;
1134 1241 }
1135 1242  
  1243 + /**
  1244 + * Builds the part of the SQL query used for a particular simple expression
  1245 + *
  1246 + * @access private
  1247 + * @param string $expr
  1248 + * @return string $query
  1249 + */
1136 1250 private function getSQLEvalExpr($expr)
1137 1251 {
1138   -
1139 1252 $left = $expr->left();
1140 1253 $right = $expr->right();
1141 1254 $isNot = $expr->not();
... ... @@ -1178,6 +1291,11 @@ class SQLQueryBuilder implements QueryBuilder
1178 1291 return $query;
1179 1292 }
1180 1293  
  1294 + /**
  1295 + * Builds the main SQL query
  1296 + *
  1297 + * @return string $sql
  1298 + */
1181 1299 private function buildCoreSQL()
1182 1300 {
1183 1301 if (count($this->metadata) + count($this->db) == 0)
... ... @@ -1186,8 +1304,7 @@ class SQLQueryBuilder implements QueryBuilder
1186 1304 return '';
1187 1305 }
1188 1306  
1189   - $sql =
1190   - 'SELECT ' . "\n";
  1307 + $sql = 'SELECT ' . "\n";
1191 1308  
1192 1309 if ($this->context == ExprContext::DOCUMENT)
1193 1310 {
... ... @@ -1197,16 +1314,19 @@ class SQLQueryBuilder implements QueryBuilder
1197 1314 $this->used_tables['document_metadata_version']++;
1198 1315 }
1199 1316  
1200   - $sql .=
1201   - ' DISTINCT d.id, dmv.name as title';
  1317 + $sql .= ' DISTINCT d.id, dmv.name as title';
1202 1318 }
1203 1319 else
1204 1320 {
1205   - $sql .=
1206   - ' DISTINCT f.id, f.name as title';
  1321 + $sql .= ' DISTINCT f.id, f.name as title';
1207 1322 }
1208 1323  
1209   -
  1324 + /*
  1325 + * This section of code builds the part of the query which is used to
  1326 + * determine ranking for db fields
  1327 + *
  1328 + * 0 = "does not match"
  1329 + */
1210 1330 $offset=0;
1211 1331 foreach($this->db as $expr)
1212 1332 {
... ... @@ -1214,14 +1334,19 @@ class SQLQueryBuilder implements QueryBuilder
1214 1334 $sql .= ", ifnull(" . $this->getSQLEvalExpr($expr) . ",0) as expr$offset ";
1215 1335 }
1216 1336  
  1337 + /*
  1338 + * This section of code builds the part of the query which is used to
  1339 + * determine ranking for metadata fields
  1340 + *
  1341 + * 0 = "does not match"
  1342 + */
1217 1343 foreach($this->metadata as $expr)
1218 1344 {
1219 1345 $offset++;
1220 1346 $sql .= ", ifnull(" . $this->getSQLEvalExpr($expr) . ",0) as expr$offset ";
1221 1347 }
1222 1348  
1223   - $sql .=
1224   - "\n" . 'FROM ' ."\n";
  1349 + $sql .= "\n" . 'FROM ' ."\n";
1225 1350  
1226 1351 if ($this->context == ExprContext::DOCUMENT)
1227 1352 {
... ... @@ -1243,10 +1368,6 @@ class SQLQueryBuilder implements QueryBuilder
1243 1368 // out below.
1244 1369 // if ($this->used_tables['document_fields_link'] > 0)
1245 1370 // {
1246   -// // NOTE this is a bit of a hack, maybe? or maybe it really is the best way?
1247   -// // ...what about using the loop below which checks the expression
1248   -// // for a join table rather than this up here? - otherwise this only
1249   -// // affects this particular query type - then again maybe that's what we want...
1250 1371 // for ($i = 0; $i < $this->used_tables['document_fields_link']; ++$i)
1251 1372 // {
1252 1373 // if ($i > 0) $counter = $i;
... ... @@ -1259,8 +1380,8 @@ class SQLQueryBuilder implements QueryBuilder
1259 1380  
1260 1381 if ($this->used_tables['tag_words'] > 0)
1261 1382 {
1262   - $sql .= ' LEFT OUTER JOIN document_tags dt ON dt.document_id=d.id ' . "\n" .
1263   - ' LEFT OUTER JOIN tag_words tw ON dt.tag_id = tw.id ' . "\n";
  1383 + $sql .= ' LEFT OUTER JOIN document_tags dt ON dt.document_id=d.id ' . "\n"
  1384 + . ' LEFT OUTER JOIN tag_words tw ON dt.tag_id = tw.id ' . "\n";
1264 1385 }
1265 1386 }
1266 1387 else
... ... @@ -1269,10 +1390,21 @@ class SQLQueryBuilder implements QueryBuilder
1269 1390 $sql .= ' folders f ' ."\n";
1270 1391 }
1271 1392  
  1393 + /*
  1394 + * This builds the JOINs required to correctly select on multiple tables.
  1395 + *
  1396 + * NOTE This is explicitly required for multi-selecting from the same table using multiple
  1397 + * joins with different offset naming.
  1398 + * This multi-selecting is necessary to avoid issues with complex queries
  1399 + * requiring different results from a single column within a database table.
  1400 + *
  1401 + * For an example of how the field classes need to be set up to take advantage of this code
  1402 + * look at the constructors for the AnyMetadataField class or the MimeTypeField class.
  1403 + */
1272 1404 $offset = 0;
1273 1405 foreach($this->db as $expr)
1274 1406 {
1275   - $field = $expr->left();
  1407 + $field = $expr->left();
1276 1408 $jointable=$field->getJoinTable();
1277 1409 if (!is_null($jointable))
1278 1410 {
... ... @@ -1360,6 +1492,13 @@ class SQLQueryBuilder implements QueryBuilder
1360 1492 throw new Exception('join field not found');
1361 1493 }
1362 1494  
  1495 + /**
  1496 + * Creates the core SQL expression for a search expression
  1497 + *
  1498 + * @access private
  1499 + * @param string $expr
  1500 + * @return string $query
  1501 + */
1363 1502 private function buildCoreSQLExpr($expr)
1364 1503 {
1365 1504 $left = $expr->left();
... ... @@ -1383,6 +1522,15 @@ class SQLQueryBuilder implements QueryBuilder
1383 1522 return $query;
1384 1523 }
1385 1524  
  1525 + /**
  1526 + * Creates the complex SQL query using the other query building functions
  1527 + * to create the individual parts of the query and combining into the final
  1528 + * query to be run on the database
  1529 + *
  1530 + * @access private
  1531 + * @param string $expr
  1532 + * @return string $sql
  1533 + */
1386 1534 public function buildComplexQuery($expr)
1387 1535 {
1388 1536 $this->exploreExprs($expr);
... ... @@ -1404,6 +1552,13 @@ class SQLQueryBuilder implements QueryBuilder
1404 1552 return $sql;
1405 1553 }
1406 1554  
  1555 + /**
  1556 + * Builds a simple database query
  1557 + *
  1558 + * @param string $op
  1559 + * @param array $group
  1560 + * @return string $sql
  1561 + */
1407 1562 public function buildSimpleQuery($op, $group)
1408 1563 {
1409 1564 $this->exploreGroup($group);
... ... @@ -1421,18 +1576,17 @@ class SQLQueryBuilder implements QueryBuilder
1421 1576 $field = $expr->left();
1422 1577  
1423 1578 if (is_null($field->getJoinTable()))
1424   - {
1425   - $alias = $this->resolveTableToAlias($field->getTable());
1426   - $fieldname = $alias . '.' . $field->getField();
1427   - }
1428   - else
1429   - {
1430   - $offset = $this->resolveJoinOffset($expr);
1431   - $matching = $field->getMatchingField();
1432   - $tablename = $field->getJoinTable();
1433   - $fieldname = "$tablename$offset.$matching";
1434   - }
1435   -
  1579 + {
  1580 + $alias = $this->resolveTableToAlias($field->getTable());
  1581 + $fieldname = $alias . '.' . $field->getField();
  1582 + }
  1583 + else
  1584 + {
  1585 + $offset = $this->resolveJoinOffset($expr);
  1586 + $matching = $field->getMatchingField();
  1587 + $tablename = $field->getJoinTable();
  1588 + $fieldname = "$tablename$offset.$matching";
  1589 + }
1436 1590  
1437 1591 $value = $expr->right();
1438 1592 $sql .= $value->getSQL($field, $left->modifyName($fieldname), $expr->op(), $expr->not());
... ... @@ -1464,6 +1618,16 @@ class SQLQueryBuilder implements QueryBuilder
1464 1618 return $sql;
1465 1619 }
1466 1620  
  1621 + /**
  1622 + * Utilises the RankManager object to determine rankings for each result
  1623 + * returned from the search query, based on the values returned by the
  1624 + * sub-parts of the query as built in buildCoreSQL()
  1625 + * (see comments in that function for the code sections responsible
  1626 + * for setting these values)
  1627 + *
  1628 + * @param array $result
  1629 + * @return int $score
  1630 + */
1467 1631 public function getRanking($result)
1468 1632 {
1469 1633 $ranker = RankManager::get();
... ... @@ -1527,8 +1691,6 @@ class SQLQueryBuilder implements QueryBuilder
1527 1691 }
1528 1692 }
1529 1693  
1530   -
1531   -
1532 1694 class OpExpr extends Expr
1533 1695 {
1534 1696 /**
... ... @@ -2164,6 +2326,15 @@ class OpExpr extends Expr
2164 2326 $this->exploreItem($right, $group, $interest);
2165 2327 }
2166 2328  
  2329 + /**
  2330 + * Executes a database query
  2331 + *
  2332 + * @access private
  2333 + * @global object $default Default config settings
  2334 + * @param string $op The operation to perform
  2335 + * @param array $group
  2336 + * @return array $results
  2337 + */
2167 2338 private function exec_db_query($op, $group)
2168 2339 {
2169 2340 if (empty($group)) { return array(); }
... ... @@ -2216,6 +2387,14 @@ class OpExpr extends Expr
2216 2387  
2217 2388 }
2218 2389  
  2390 + /**
  2391 + * Executes a text search query against the Lucene indexer
  2392 + *
  2393 + * @global object $default Default config settings
  2394 + * @param string $op The operation to perform
  2395 + * @param array $group
  2396 + * @return array $results
  2397 + */
2219 2398 private function exec_text_query($op, $group)
2220 2399 {
2221 2400 global $default;
... ... @@ -2262,6 +2441,12 @@ class OpExpr extends Expr
2262 2441 return $results;
2263 2442 }
2264 2443  
  2444 + /**
  2445 + * Evaluate a search query
  2446 + *
  2447 + * @param int $context The context to which the query applies (document/folder/both)
  2448 + * @return array $permResults
  2449 + */
2265 2450 public function evaluate($context = ExprContext::DOCUMENT_AND_FOLDER)
2266 2451 {
2267 2452 if ($context == ExprContext::DOCUMENT_AND_FOLDER)
... ...