Commit 986c300114cf13cf30faf1a17f330d6f1a2897f3
1 parent
80790675
KTS-3306
"Search should return folders" Implemented. KTS-3671 "Support for searching of symbolic links" Implemented. Committed By: Conrad Vermeulen Reviewed By: Megan Watson git-svn-id: https://kt-dms.svn.sourceforge.net/svnroot/kt-dms/trunk@9399 c91229c3-7414-0410-bfa2-8a42b809f60b
Showing
9 changed files
with
755 additions
and
293 deletions
search2.php
| ... | ... | @@ -35,15 +35,20 @@ |
| 35 | 35 | * Contributor( s): ______________________________________ |
| 36 | 36 | */ |
| 37 | 37 | |
| 38 | +// TODO: do we have to serialise/unserialise the results. this is not optimal!!! | |
| 39 | + | |
| 38 | 40 | session_start(); |
| 39 | 41 | require_once("config/dmsDefaults.php"); |
| 42 | +require_once(KT_DIR . '/search2/indexing/indexerCore.inc.php'); | |
| 43 | + | |
| 40 | 44 | require_once(KT_LIB_DIR . "/unitmanagement/Unit.inc"); |
| 41 | 45 | |
| 42 | 46 | require_once(KT_LIB_DIR . "/templating/templating.inc.php"); |
| 43 | 47 | require_once(KT_LIB_DIR . "/dispatcher.inc.php"); |
| 44 | 48 | require_once(KT_LIB_DIR . "/widgets/forms.inc.php"); |
| 45 | 49 | require_once(KT_LIB_DIR . "/actions/bulkaction.php"); |
| 46 | -require_once(KT_DIR . '/search2/search/search.inc.php'); | |
| 50 | + | |
| 51 | +require_once(KT_LIB_DIR . '/browse/DocumentCollection.inc.php'); | |
| 47 | 52 | require_once(KT_LIB_DIR . '/documentmanagement/Document.inc'); |
| 48 | 53 | require_once(KT_LIB_DIR . '/browse/PartialQuery.inc.php'); |
| 49 | 54 | |
| ... | ... | @@ -117,7 +122,6 @@ function search2QuerySort($sSortColumn, $sSortOrder) |
| 117 | 122 | return; |
| 118 | 123 | } |
| 119 | 124 | |
| 120 | - | |
| 121 | 125 | $results = unserialize($_SESSION['search2_results']); |
| 122 | 126 | |
| 123 | 127 | usort($results, 'search2queryCompare'); |
| ... | ... | @@ -132,38 +136,70 @@ function search2QuerySort($sSortColumn, $sSortOrder) |
| 132 | 136 | */ |
| 133 | 137 | class Search2Query extends PartialQuery |
| 134 | 138 | { |
| 135 | - function getFolderCount() { return 0; } | |
| 139 | + function _count($type) | |
| 140 | + { | |
| 141 | + $count = 0; | |
| 142 | + $results = unserialize($_SESSION['search2_results']); | |
| 143 | + | |
| 144 | + switch ($type) | |
| 145 | + { | |
| 146 | + case 'Document': | |
| 147 | + return count($results['docs']) + count($results['shortdocs']); | |
| 148 | + case 'Folder': | |
| 149 | + return count($results['folders']) + count($results['shortfolders']); | |
| 150 | + default: | |
| 151 | + return 0; | |
| 152 | + } | |
| 153 | + } | |
| 154 | + | |
| 155 | + function getFolderCount() | |
| 156 | + { | |
| 157 | + return $this->_count('Folder'); | |
| 158 | + } | |
| 136 | 159 | function getDocumentCount() |
| 137 | 160 | { |
| 138 | - $results = $_SESSION['search2_results']; | |
| 139 | - if(isset($results) && !empty($results)){ | |
| 140 | - return count(unserialize($results)); | |
| 161 | + return $this->_count('Document'); | |
| 162 | + } | |
| 163 | + | |
| 164 | + function getItems($type, $iStart, $iSize, $sSortColumn, $sSortOrder) | |
| 165 | + { | |
| 166 | + // TODO: quick hack. do this more optimally!!!! | |
| 167 | + $results = unserialize($_SESSION['search2_results']); | |
| 168 | + | |
| 169 | + switch ($type) | |
| 170 | + { | |
| 171 | + case 'Document': | |
| 172 | + $type = 'docs'; | |
| 173 | + break; | |
| 174 | + case 'Folder': | |
| 175 | + $type = 'folders'; | |
| 176 | + break; | |
| 141 | 177 | } |
| 142 | - return 0; | |
| 178 | + | |
| 179 | + $resultArray = $results[$type]; | |
| 180 | + foreach($results['short' . $type] as $rec) | |
| 181 | + { | |
| 182 | + $resultArray[] = $rec; | |
| 183 | + } | |
| 184 | + | |
| 185 | + $resultArray = array_slice($resultArray, $iStart, $iSize); | |
| 186 | + $results = array(); | |
| 187 | + foreach($resultArray as $rec) | |
| 188 | + { | |
| 189 | + $results[] = array('id'=>$rec->Id); | |
| 190 | + } | |
| 191 | + | |
| 192 | + return $results; | |
| 143 | 193 | } |
| 144 | 194 | |
| 145 | 195 | function getFolders($iBatchSize, $iBatchStart, $sSortColumn, $sSortOrder, $sJoinClause = null, $aJoinParams = null) |
| 146 | 196 | { |
| 147 | - return array(); | |
| 197 | + return $this->getItems('Folder', $iBatchStart, $iBatchSize, $sSortColumn, $sSortOrder); | |
| 148 | 198 | } |
| 149 | 199 | |
| 150 | 200 | function getDocuments($iBatchSize, $iBatchStart, $sSortColumn, $sSortOrder, $sJoinClause = null, $aJoinParams = null) |
| 151 | 201 | { |
| 152 | - search2QuerySort($_GET['sort_on'], $_GET['sort_order']); | |
| 153 | - $results = unserialize($_SESSION['search2_results']); | |
| 154 | - | |
| 155 | - $batch = array(); | |
| 156 | - | |
| 157 | - $no_results = count($results); | |
| 158 | - for($i=0;$i<$no_results;$i++) | |
| 159 | - { | |
| 160 | - if ($i < $iBatchStart) continue; | |
| 161 | - if ($i > $iBatchStart + $iBatchSize) continue; | |
| 162 | - | |
| 163 | - $batch[] = array('id'=>$results[$i]->DocumentID); | |
| 164 | - } | |
| 165 | - | |
| 166 | - return $batch; | |
| 202 | + return $this->getItems('Document', $iBatchStart, $iBatchSize, $sSortColumn, $sSortOrder); | |
| 167 | 203 | } |
| 168 | 204 | } |
| 169 | 205 | |
| ... | ... | @@ -208,10 +244,12 @@ class SearchDispatcher extends KTStandardDispatcher { |
| 208 | 244 | { |
| 209 | 245 | $expr = parseExpression($query); |
| 210 | 246 | |
| 211 | - $result = $expr->evaluate(); | |
| 212 | - usort($result, 'rank_compare'); | |
| 247 | + $results = $expr->evaluate(); | |
| 248 | + $results = resolveSearchShortcuts($results); | |
| 213 | 249 | |
| 214 | - $_SESSION['search2_results'] = serialize($result); | |
| 250 | + usort($result['docs'], 'rank_compare'); | |
| 251 | + | |
| 252 | + $_SESSION['search2_results'] = serialize($results); | |
| 215 | 253 | $_SESSION['search2_query'] = $query; |
| 216 | 254 | $_SESSION['search2_sort'] = 'rank'; |
| 217 | 255 | |
| ... | ... | @@ -410,6 +448,15 @@ class SearchDispatcher extends KTStandardDispatcher { |
| 410 | 448 | |
| 411 | 449 | $results = unserialize($_SESSION['search2_results']); |
| 412 | 450 | |
| 451 | + // NOTE: sorting results (when it is implemented) might have to be done per section, as it is done with the browse view | |
| 452 | + | |
| 453 | + $resultArray = $results['docs']; | |
| 454 | + foreach($results['folders'] as $f) $resultArray[] = $f; | |
| 455 | + foreach($results['shortdocs'] as $d) $resultArray[] = $d; | |
| 456 | + foreach($results['shortfolders'] as $f) $resultArray[] = $f; | |
| 457 | + | |
| 458 | + $results = $resultArray; | |
| 459 | + | |
| 413 | 460 | if (!is_array($results) || count($results) == 0) |
| 414 | 461 | { |
| 415 | 462 | $results=array(); | ... | ... |
search2/indexing/indexerCore.inc.php
| ... | ... | @@ -41,17 +41,142 @@ define('SEARCH2_INDEXER_DIR',realpath(dirname(__FILE__)) . '/'); |
| 41 | 41 | require_once('indexing/extractorCore.inc.php'); |
| 42 | 42 | require_once(KT_DIR . '/plugins/ktcore/scheduler/schedulerUtil.php'); |
| 43 | 43 | |
| 44 | - | |
| 45 | 44 | class IndexerInconsistencyException extends Exception {}; |
| 46 | 45 | |
| 46 | +// TODO: Query Result Items code should be moved into the Search section. It has less to do with indexing... | |
| 47 | + | |
| 47 | 48 | class QueryResultItem |
| 48 | 49 | { |
| 49 | - protected $document_id; | |
| 50 | + protected $id; | |
| 50 | 51 | protected $title; |
| 51 | 52 | protected $rank; |
| 52 | 53 | protected $text; |
| 53 | - protected $filesize; | |
| 54 | 54 | protected $fullpath; |
| 55 | + | |
| 56 | + public function __construct($id, $title, $rank, $text, $fullpath) | |
| 57 | + { | |
| 58 | + $this->id = $id; | |
| 59 | + $this->title = $title; | |
| 60 | + $this->rank = $rank; | |
| 61 | + $this->text = $text; | |
| 62 | + $this->fullpath = $fullpath; | |
| 63 | + } | |
| 64 | + | |
| 65 | + public function getId() { return $this->id; } | |
| 66 | + | |
| 67 | + public function getIsProxy() { return $this instanceof ProxyResultItem; } | |
| 68 | + public function getIsFolder() { return substr(get_class($this), 0, 6) == 'Folder' ; } | |
| 69 | + public function getIsDocument() { return substr(get_class($this), 0, 8) == 'Document' ; } | |
| 70 | + | |
| 71 | + public function setRank($value) | |
| 72 | + { | |
| 73 | + $this->rank = number_format($value,2,'.',','); | |
| 74 | + } | |
| 75 | + | |
| 76 | + public function getIsLive() | |
| 77 | + { | |
| 78 | + return true; | |
| 79 | + } | |
| 80 | + | |
| 81 | + public function setTitle($value) | |
| 82 | + { | |
| 83 | + $this->title = $value; | |
| 84 | + } | |
| 85 | + | |
| 86 | + public function setText($value) | |
| 87 | + { | |
| 88 | + $this->text = $value; | |
| 89 | + } | |
| 90 | + | |
| 91 | + public function getRelevance() { return (float) $this->rank; } | |
| 92 | + public function getRank() { return $this->getRelevance(); } | |
| 93 | + public function getText() { return (string) $this->text; } | |
| 94 | + public function getTitle() { return (string) $this->title; } | |
| 95 | + public function getFullPath() { return (string) $this->fullpath; } | |
| 96 | + | |
| 97 | + protected function __get($property) | |
| 98 | + { | |
| 99 | + if (empty($property)) | |
| 100 | + { | |
| 101 | + return ''; | |
| 102 | + } | |
| 103 | + | |
| 104 | + $method = 'get' . $property; | |
| 105 | + if (method_exists($this, $method)) | |
| 106 | + { | |
| 107 | + return $this->$method(); | |
| 108 | + } | |
| 109 | + return $this->getUnknown(); | |
| 110 | + } | |
| 111 | + | |
| 112 | + protected function getUnknown() | |
| 113 | + { | |
| 114 | + return _kt('n/a'); | |
| 115 | + } | |
| 116 | + | |
| 117 | + protected function __set($property, $value) | |
| 118 | + { | |
| 119 | + if (empty($property)) | |
| 120 | + { | |
| 121 | + return ''; | |
| 122 | + } | |
| 123 | + | |
| 124 | + $method = 'set' . $property; | |
| 125 | + if (method_exists($this, $method)) | |
| 126 | + { | |
| 127 | + return $this->$method($value); | |
| 128 | + } | |
| 129 | + throw new Exception("Unknown property '$property' to set on QueryResultItem"); | |
| 130 | + } | |
| 131 | +} | |
| 132 | + | |
| 133 | +class ProxyResultItem extends QueryResultItem | |
| 134 | +{ | |
| 135 | + protected $proxy; | |
| 136 | + protected $proxyId; | |
| 137 | + | |
| 138 | + public function __construct($proxyId, $proxy) | |
| 139 | + { | |
| 140 | + parent::__construct($proxyId, $proxy->getTitle, $proxy->getRank(), $proxy->getText(), $proxy->getFullPath()); | |
| 141 | + $this->proxyId = $proxyId; | |
| 142 | + $this->proxy = $proxy; | |
| 143 | + } | |
| 144 | + | |
| 145 | + public function getId() { return $this->proxyId; } | |
| 146 | + public function getTitle() { return $this->proxy->getTitle(); } | |
| 147 | + public function getRealId() { return $this->proxy->getId(); } | |
| 148 | + | |
| 149 | + protected function __get($property) | |
| 150 | + { | |
| 151 | + $method = 'get' . $property; | |
| 152 | + | |
| 153 | + if (method_exists($this, $method)) | |
| 154 | + { | |
| 155 | + return $this->$method(); | |
| 156 | + } | |
| 157 | + else | |
| 158 | + { | |
| 159 | + return $this->proxy->$method(); | |
| 160 | + } | |
| 161 | + } | |
| 162 | + | |
| 163 | + protected function __set($property, $value) | |
| 164 | + { | |
| 165 | + $method = 'set' . $property; | |
| 166 | + if (method_exists($this, $method)) | |
| 167 | + { | |
| 168 | + return $this->$method($value); | |
| 169 | + } | |
| 170 | + else | |
| 171 | + { | |
| 172 | + return $this->proxy->$method($value); | |
| 173 | + } | |
| 174 | + } | |
| 175 | +} | |
| 176 | + | |
| 177 | +class DocumentResultItem extends QueryResultItem | |
| 178 | +{ | |
| 179 | + protected $filesize; | |
| 55 | 180 | protected $live; |
| 56 | 181 | protected $version; |
| 57 | 182 | protected $mimeType; |
| ... | ... | @@ -78,17 +203,14 @@ class QueryResultItem |
| 78 | 203 | protected $mimeDisplay; |
| 79 | 204 | protected $oemDocumentNo; |
| 80 | 205 | |
| 81 | - public function __construct($document_id, $rank=null, $title=null, $text=null) | |
| 206 | + public function __construct($document_id, $rank=null, $title=null, $text=null, $fullpath = null) | |
| 82 | 207 | { |
| 83 | - $this->document_id=(int) $document_id; | |
| 84 | - $this->rank= $rank; | |
| 85 | - $this->title=$title; | |
| 86 | - $this->text = $text; | |
| 208 | + parent::__construct($document_id, $title, $rank, $text, $fullpath); | |
| 87 | 209 | $this->live = true; |
| 88 | 210 | $this->loadDocumentInfo(); |
| 89 | 211 | } |
| 90 | 212 | |
| 91 | - protected function __isset($property) | |
| 213 | + /*protected function __isset($property) | |
| 92 | 214 | { |
| 93 | 215 | switch($property) |
| 94 | 216 | { |
| ... | ... | @@ -101,8 +223,9 @@ class QueryResultItem |
| 101 | 223 | throw new Exception("Unknown property '$property' to get on QueryResultItem"); |
| 102 | 224 | } |
| 103 | 225 | return true; // should not be reached |
| 104 | - } | |
| 226 | + }*/ | |
| 105 | 227 | |
| 228 | + // TODO: this is bad. must refactor to do the query on the group of documents. | |
| 106 | 229 | public function loadDocumentInfo() |
| 107 | 230 | { |
| 108 | 231 | global $default; |
| ... | ... | @@ -127,7 +250,7 @@ class QueryResultItem |
| 127 | 250 | LEFT JOIN users cbu ON d.creator_id=cbu.id |
| 128 | 251 | LEFT JOIN users ou ON d.owner_id=ou.id |
| 129 | 252 | WHERE |
| 130 | - d.id=$this->document_id"; | |
| 253 | + d.id=$this->id"; | |
| 131 | 254 | |
| 132 | 255 | $result = DBUtil::getOneResult($sql); |
| 133 | 256 | |
| ... | ... | @@ -186,107 +309,116 @@ class QueryResultItem |
| 186 | 309 | |
| 187 | 310 | $this->mimeType = $result['mimetype']; |
| 188 | 311 | $this->mimeIconPath = $result['mime_icon_path']; |
| 312 | + if (empty($this->mimeIconPath)) | |
| 313 | + { | |
| 314 | + $this->mimeIconPath = 'unspecified_type'; | |
| 315 | + } | |
| 189 | 316 | $this->mimeDisplay = $result['mime_display']; |
| 190 | 317 | |
| 191 | 318 | $this->storagePath = $result['storage_path']; |
| 192 | 319 | $this->status = Document::getStatusString($result['status_id']); |
| 193 | 320 | } |
| 194 | 321 | |
| 195 | - protected function __get($property) | |
| 196 | - { | |
| 197 | - switch($property) | |
| 198 | - { | |
| 199 | - case null: return ''; | |
| 200 | - case 'DocumentID': return (int) $this->document_id; | |
| 201 | - case 'Relevance': | |
| 202 | - case 'Rank': return (float) $this->rank; | |
| 203 | - case 'Text': return (string) $this->text; | |
| 204 | - case 'Title': return (string) $this->title; | |
| 205 | - case 'FullPath': return (string) $this->fullpath; | |
| 206 | - case 'IsLive': return (bool) $this->live; | |
| 207 | - case 'Filesize': return $this->filesize; | |
| 208 | - case 'Version': return (string) $this->version; | |
| 209 | - case 'Filename': return (string)$this->filename; | |
| 210 | - case 'FolderId': return (int)$this->folderId; | |
| 211 | - case 'OemDocumentNo': return (string) $this->oemDocumentNo; | |
| 212 | - case 'Document': | |
| 213 | - if (is_null($this->document)) | |
| 322 | + public function getDocumentID() { return $this->getId(); } | |
| 323 | + public function getIsLive() { return (bool) $this->live; } | |
| 324 | + public function getFilesize() { return $this->filesize; } | |
| 325 | + public function getVersion() { return (string) $this->version; } | |
| 326 | + public function getFilename() { return (string)$this->filename; } | |
| 327 | + public function getFolderId() { return (int)$this->folderId; } | |
| 328 | + public function getOemDocumentNo() { return (string) $this->oemDocumentNo; } | |
| 329 | + public function getDocument() { if (is_null($this->document)) | |
| 214 | 330 | { |
| 215 | - $this->document = Document::get($this->document_id); | |
| 331 | + $this->document = Document::get($this->id); | |
| 216 | 332 | } |
| 217 | - return $this->document; | |
| 218 | - case 'IsAvailable': | |
| 219 | - return $this->Document->isLive(); | |
| 220 | - case 'CheckedOutUser': | |
| 221 | - case 'CheckedOutBy': | |
| 222 | - return (string) $this->checkedOutUser; | |
| 223 | - case 'WorkflowOnly': | |
| 224 | - case 'Workflow': | |
| 225 | - return (string)$this->workflow; | |
| 226 | - case 'WorkflowStateOnly': | |
| 227 | - case 'WorkflowState': | |
| 228 | - return (string)$this->workflowState; | |
| 229 | - case 'WorkflowAndState': | |
| 230 | - if (is_null($this->workflow)) | |
| 333 | + return $this->document; } | |
| 334 | + public function getIsAvailable() { return $this->Document->isLive(); } | |
| 335 | + public function getCheckedOutUser() { return (string) $this->checkedOutUser; } | |
| 336 | + public function getCheckedOutByr() { return $this->getCheckedOutUser(); } | |
| 337 | + public function getWorkflowOnly() { return (string)$this->workflow; } | |
| 338 | + public function getWorkflow() { return $this->getWorkflow(); } | |
| 339 | + public function getWorkflowStateOnly() { return (string)$this->workflowState; } | |
| 340 | + public function getWorkflowState() { return $this->getWorkflowStateOnly(); } | |
| 341 | + public function getWorkflowAndState() { if (is_null($this->workflow)) | |
| 231 | 342 | { |
| 232 | 343 | return ''; |
| 233 | 344 | } |
| 234 | - return "$this->workflow - $this->workflowState"; | |
| 235 | - case 'MimeType': | |
| 236 | - return (string) $this->mimeType; | |
| 237 | - case 'MimeIconPath': | |
| 238 | - return (string) $this->mimeIconPath; | |
| 239 | - case 'MimeDisplay': | |
| 240 | - return (string) $this->mimeDisplay; | |
| 241 | - case 'DateCheckedOut': | |
| 242 | - return (string) $this->dateCheckedout; | |
| 243 | - case 'ModifiedBy': | |
| 244 | - return (string) $this->modifiedBy; | |
| 245 | - case 'DateModified': | |
| 246 | - return (string) $this->dateModified; | |
| 247 | - case 'CreatedBy': | |
| 248 | - return (string) $this->createdBy; | |
| 249 | - case 'DateCreated': | |
| 250 | - return (string) $this->dateCreated; | |
| 251 | - case 'Owner': | |
| 252 | - case 'OwnedBy': | |
| 253 | - return (string) $this->owner; | |
| 254 | - case 'IsImmutable': | |
| 255 | - case 'Immutable': | |
| 256 | - return (bool) $this->immutable; | |
| 257 | - case 'Status': | |
| 258 | - return $this->status; | |
| 259 | - case 'StoragePath': | |
| 260 | - return $this->storagePath; | |
| 261 | - case 'DocumentType': | |
| 262 | - return $this->documentType; | |
| 263 | - case 'Permissions': | |
| 264 | - return 'not available'; | |
| 265 | - case 'CanBeReadByUser': | |
| 266 | - if (!$this->live) | |
| 345 | + return "$this->workflow - $this->workflowState"; } | |
| 346 | + public function getMimeType() { return (string) $this->mimeType; } | |
| 347 | + public function getMimeIconPath() { return (string) $this->mimeIconPath; } | |
| 348 | + public function getMimeDisplay() { return (string) $this->mimeDisplay; } | |
| 349 | + public function getDateCheckedOut() { return (string) $this->dateCheckedout; } | |
| 350 | + public function getModifiedBy() { return (string) $this->modifiedBy; } | |
| 351 | + public function getDateModified() { return (string) $this->dateModified; } | |
| 352 | + public function getCreatedBy() { return (string) $this->createdBy; } | |
| 353 | + public function getDateCreated() { return (string) $this->dateCreated; } | |
| 354 | + public function getOwner() { return (string) $this->owner; } | |
| 355 | + public function getOwnedBy() { return $this->getOwner(); } | |
| 356 | + public function getIsImmutable() { return (bool) $this->immutable; } | |
| 357 | + public function getImmutable() { return $this->getIsImmutable(); } | |
| 358 | + public function getStatus() { return $this->status; } | |
| 359 | + public function getStoragePath() { return $this->storagePath; } | |
| 360 | + public function getDocumentType() { return $this->documentType; } | |
| 361 | + public function getPermissions() { return 'not available'; } | |
| 362 | + public function getCanBeReadByUser() { if (!$this->live) | |
| 267 | 363 | return false; |
| 268 | 364 | if (Permission::userHasDocumentReadPermission($this->Document)) |
| 269 | 365 | return true; |
| 270 | 366 | if (Permission::adminIsInAdminMode()) |
| 271 | 367 | return true; |
| 272 | - return false; | |
| 273 | - default: | |
| 274 | - throw new Exception("Unknown property '$property' to get on QueryResultItem"); | |
| 275 | - } | |
| 276 | - return ''; // Should not be reached | |
| 368 | + return false; } | |
| 369 | + | |
| 370 | + | |
| 371 | +} | |
| 372 | + | |
| 373 | +class FolderResultItem extends QueryResultItem | |
| 374 | +{ | |
| 375 | + protected $folder; | |
| 376 | + protected $createdBy; | |
| 377 | + protected $parentId; | |
| 378 | + | |
| 379 | + public function __construct($folder_id, $rank=null, $title=null, $text=null, $fullpath = null) | |
| 380 | + { | |
| 381 | + parent::__construct($folder_id, $title, $rank, $text, $fullpath); | |
| 382 | + $this->loadDocumentInfo(); | |
| 277 | 383 | } |
| 278 | 384 | |
| 279 | - protected function __set($property, $value) | |
| 385 | + public function getFolderID() { return $this->getId(); } | |
| 386 | + public function getParentID() { return $this->parentId; } | |
| 387 | + public function getCreatedBy() { return $this->createdBy; } | |
| 388 | + public function getMimeIconPath() { return 'folder'; } | |
| 389 | + public function getFolder() { | |
| 390 | + return $this->folder; } | |
| 391 | + | |
| 392 | + public function loadDocumentInfo() | |
| 280 | 393 | { |
| 281 | - switch($property) | |
| 394 | + global $default; | |
| 395 | + $this->folder = $folder = Folder::get($this->getFolderID()); | |
| 396 | + if (PEAR::isError($folder)) | |
| 282 | 397 | { |
| 283 | - case 'Rank': $this->rank = number_format($value,2,'.',','); break; | |
| 284 | - case 'Title': $this->title = $value; break; | |
| 285 | - case 'Text': $this->text = $value; break; | |
| 286 | - default: | |
| 287 | - throw new Exception("Unknown property '$property' to set on QueryResultItem"); | |
| 398 | + throw new Exception('Database exception! There appears to be an error in the system: ' .$result->getMessage()); | |
| 288 | 399 | } |
| 400 | + $this->title = $folder->getName(); | |
| 401 | + $this->fullpath = '/' . $folder->getFullPath(); | |
| 402 | + $this->parentId = $folder->getParentId(); | |
| 403 | + | |
| 404 | + $user = User::get($folder->getCreatorID()); | |
| 405 | + $this->createdBy = (PEAR::isError($user))?_kt('Unknown'):$user->getName(); | |
| 289 | 406 | } |
| 407 | + | |
| 408 | +} | |
| 409 | + | |
| 410 | +class DocumentShortcutResultItem extends ProxyResultItem | |
| 411 | +{ | |
| 412 | + public function getDocumentID() { return $this->getId(); } | |
| 413 | + public function getMimeIconPath() { return $this->proxy->getMimeIconPath() . '_shortcut'; } | |
| 414 | + | |
| 415 | +} | |
| 416 | + | |
| 417 | +class FolderShortcutResultItem extends ProxyResultItem | |
| 418 | +{ | |
| 419 | + public function getFolderID() { return $this->getId(); } | |
| 420 | + public function getMimeIconPath() { return 'folder_shortcut'; } | |
| 421 | + | |
| 290 | 422 | } |
| 291 | 423 | |
| 292 | 424 | function MatchResultCompare($a, $b) | ... | ... |
search2/indexing/indexers/JavaXMLRPCLuceneIndexer.inc.php
| ... | ... | @@ -187,14 +187,11 @@ class JavaXMLRPCLuceneIndexer extends Indexer |
| 187 | 187 | { |
| 188 | 188 | try |
| 189 | 189 | { |
| 190 | - $item = new QueryResultItem($document_id); | |
| 191 | - $item->Title = $hit->Title; | |
| 192 | - $item->Text = $hit->Content; | |
| 193 | - $item->Rank = $hit->Rank; | |
| 190 | + $item = new DocumentResultItem($document_id, $hit->Rank, $hit->Title, $hit->Content); | |
| 194 | 191 | |
| 195 | 192 | if ($item->CanBeReadByUser) |
| 196 | 193 | { |
| 197 | - $results[$document_id] = $item; | |
| 194 | + $results['docs'][$document_id] = $item; | |
| 198 | 195 | } |
| 199 | 196 | } |
| 200 | 197 | catch(IndexerInconsistencyException $ex) | ... | ... |
search2/search/expr.inc.php
| ... | ... | @@ -43,6 +43,8 @@ |
| 43 | 43 | * |
| 44 | 44 | */ |
| 45 | 45 | |
| 46 | +// TODO: search expression evaluation needs some optimisation | |
| 47 | + | |
| 46 | 48 | require_once('indexing/indexerCore.inc.php'); |
| 47 | 49 | require_once('search/fieldRegistry.inc.php'); |
| 48 | 50 | require_once('search/exprConstants.inc.php'); |
| ... | ... | @@ -157,11 +159,28 @@ class Expr |
| 157 | 159 | |
| 158 | 160 | protected $expr_id; |
| 159 | 161 | |
| 162 | + protected $context; | |
| 163 | + | |
| 160 | 164 | public function __construct() |
| 161 | 165 | { |
| 162 | 166 | $this->expr_id = Expr::$node_id++; |
| 163 | 167 | } |
| 164 | 168 | |
| 169 | + public function appliesToContext() | |
| 170 | + { | |
| 171 | + return ExprContext::DOCUMENT; | |
| 172 | + } | |
| 173 | + | |
| 174 | + public function setContext($context) | |
| 175 | + { | |
| 176 | + $this->context = $context; | |
| 177 | + } | |
| 178 | + | |
| 179 | + public function getContext() | |
| 180 | + { | |
| 181 | + return $this->context; | |
| 182 | + } | |
| 183 | + | |
| 165 | 184 | public function getExprId() |
| 166 | 185 | { |
| 167 | 186 | return $this->expr_id; |
| ... | ... | @@ -406,6 +425,14 @@ class FieldExpr extends Expr |
| 406 | 425 | } |
| 407 | 426 | } |
| 408 | 427 | |
| 428 | +class ExprContext | |
| 429 | +{ | |
| 430 | + const DOCUMENT = 1; | |
| 431 | + const FOLDER = 2; | |
| 432 | + const DOCUMENT_AND_FOLDER = 3; | |
| 433 | +} | |
| 434 | + | |
| 435 | + | |
| 409 | 436 | class DBFieldExpr extends FieldExpr |
| 410 | 437 | { |
| 411 | 438 | /** |
| ... | ... | @@ -966,24 +993,43 @@ class SQLQueryBuilder implements QueryBuilder |
| 966 | 993 | private $sql; |
| 967 | 994 | private $db; |
| 968 | 995 | private $metadata; |
| 996 | + private $context; | |
| 969 | 997 | |
| 970 | - public function __construct() | |
| 998 | + public function __construct($context) | |
| 971 | 999 | { |
| 972 | - $this->used_tables = array( | |
| 973 | - 'documents'=>1, | |
| 974 | - 'document_metadata_version'=>1, | |
| 975 | - 'document_content_version'=>0, | |
| 976 | - 'tag_words'=>0, | |
| 977 | - 'document_fields_link'=>0 | |
| 978 | - ); | |
| 979 | - | |
| 980 | - $this->aliases = array( | |
| 981 | - 'documents'=>'d', | |
| 982 | - 'document_metadata_version'=>'dmv', | |
| 983 | - 'document_content_version'=>'dcv', | |
| 984 | - 'tag_words'=>'tw', | |
| 985 | - 'document_fields_link'=>'pdfl' | |
| 986 | - ); | |
| 1000 | + $this->context = $context; | |
| 1001 | + | |
| 1002 | + switch ($context) | |
| 1003 | + { | |
| 1004 | + case ExprContext::DOCUMENT: | |
| 1005 | + $this->used_tables = array( | |
| 1006 | + 'documents'=>1, | |
| 1007 | + 'document_metadata_version'=>1, | |
| 1008 | + 'document_content_version'=>0, | |
| 1009 | + 'tag_words'=>0, | |
| 1010 | + 'document_fields_link'=>0 | |
| 1011 | + ); | |
| 1012 | + | |
| 1013 | + $this->aliases = array( | |
| 1014 | + 'documents'=>'d', | |
| 1015 | + 'document_metadata_version'=>'dmv', | |
| 1016 | + 'document_content_version'=>'dcv', | |
| 1017 | + 'tag_words'=>'tw', | |
| 1018 | + 'document_fields_link'=>'pdfl' | |
| 1019 | + ); | |
| 1020 | + break; | |
| 1021 | + case ExprContext::FOLDER: | |
| 1022 | + $this->used_tables = array( | |
| 1023 | + 'folders'=>1, | |
| 1024 | + ); | |
| 1025 | + | |
| 1026 | + $this->aliases = array( | |
| 1027 | + 'folders'=>'f', | |
| 1028 | + ); | |
| 1029 | + break; | |
| 1030 | + default: | |
| 1031 | + throw new Exception('This was not expected - Context = ' . $context); | |
| 1032 | + } | |
| 987 | 1033 | |
| 988 | 1034 | $this->sql = ''; |
| 989 | 1035 | $this->db = array(); |
| ... | ... | @@ -1013,8 +1059,15 @@ class SQLQueryBuilder implements QueryBuilder |
| 1013 | 1059 | } |
| 1014 | 1060 | elseif ($expr->isDBExpr()) |
| 1015 | 1061 | { |
| 1016 | - $this->db[] = & $parent; | |
| 1017 | - $this->used_tables[$expr->getTable()]++; | |
| 1062 | + if (($this->context & $expr->appliesToContext()) == $this->context) | |
| 1063 | + { | |
| 1064 | + $this->db[] = & $parent; | |
| 1065 | + $tablename = $expr->getTable(); | |
| 1066 | + if (array_key_exists($tablename, $this->used_tables)) | |
| 1067 | + { | |
| 1068 | + $this->used_tables[$tablename]++; | |
| 1069 | + } | |
| 1070 | + } | |
| 1018 | 1071 | } |
| 1019 | 1072 | elseif ($expr->isOpExpr()) |
| 1020 | 1073 | { |
| ... | ... | @@ -1042,12 +1095,16 @@ class SQLQueryBuilder implements QueryBuilder |
| 1042 | 1095 | |
| 1043 | 1096 | if ($field->isMetadataField()) |
| 1044 | 1097 | { |
| 1045 | - $this->metadata[] = $expr->getParent(); | |
| 1098 | + $this->metadata[] = $expr->getParent(); | |
| 1046 | 1099 | } |
| 1047 | 1100 | elseif ($field->isDBExpr()) |
| 1048 | 1101 | { |
| 1049 | - $this->db[] = $expr->getParent(); | |
| 1050 | - $this->used_tables[$field->getTable()]++; | |
| 1102 | + $this->db[] = $expr->getParent(); | |
| 1103 | + $tablename = $field->getTable(); | |
| 1104 | + if (array_key_exists($tablename, $this->used_tables)) | |
| 1105 | + { | |
| 1106 | + $this->used_tables[$tablename]++; | |
| 1107 | + } | |
| 1051 | 1108 | } |
| 1052 | 1109 | } |
| 1053 | 1110 | } |
| ... | ... | @@ -1076,29 +1133,40 @@ class SQLQueryBuilder implements QueryBuilder |
| 1076 | 1133 | $left = $expr->left(); |
| 1077 | 1134 | $right = $expr->right(); |
| 1078 | 1135 | $isNot = $expr->not(); |
| 1079 | - if ($left->isMetadataField()) | |
| 1136 | + if ($left->isMetadataField() ) | |
| 1080 | 1137 | { |
| 1081 | - $offset = $this->resolveMetadataOffset($expr) + 1; | |
| 1082 | - | |
| 1083 | - $fieldset = $left->getField(); | |
| 1084 | - $query = '('; | |
| 1085 | - | |
| 1086 | - if ($isNot) | |
| 1087 | - { | |
| 1088 | - $query .= "df$offset.name IS NULL OR "; | |
| 1089 | - } | |
| 1090 | - | |
| 1091 | - $query .= '(' . "df$offset.name='$fieldset' AND " . $right->getSQL($left, "dfl$offset.value", $expr->op(), $isNot) . ')'; | |
| 1092 | - | |
| 1093 | - | |
| 1094 | - $query .= ')'; | |
| 1095 | - | |
| 1138 | + if ($this->context == ExprContext::DOCUMENT) | |
| 1139 | + { | |
| 1140 | + $offset = $this->resolveMetadataOffset($expr) + 1; | |
| 1141 | + | |
| 1142 | + $fieldset = $left->getField(); | |
| 1143 | + $query = '('; | |
| 1144 | + | |
| 1145 | + if ($isNot) | |
| 1146 | + { | |
| 1147 | + $query .= "df$offset.name IS NULL OR "; | |
| 1148 | + } | |
| 1149 | + | |
| 1150 | + $query .= '(' . "df$offset.name='$fieldset' AND " . $right->getSQL($left, "dfl$offset.value", $expr->op(), $isNot) . ')'; | |
| 1151 | + | |
| 1152 | + $query .= ')'; | |
| 1153 | + } | |
| 1154 | + else | |
| 1155 | + { | |
| 1156 | + $query = 'false'; | |
| 1157 | + } | |
| 1096 | 1158 | } |
| 1097 | 1159 | else |
| 1098 | 1160 | { |
| 1099 | - $fieldname = $this->getFieldnameFromExpr($expr); | |
| 1100 | - | |
| 1101 | - $query = $right->getSQL($left, $left->modifyName($fieldname), $expr->op(), $isNot); | |
| 1161 | + if ($this->context == ExprContext::FOLDER && $left->getContext() != ExprContext::FOLDER) | |
| 1162 | + { | |
| 1163 | + $query = 'false'; | |
| 1164 | + } | |
| 1165 | + else | |
| 1166 | + { | |
| 1167 | + $fieldname = $this->getFieldnameFromExpr($expr); | |
| 1168 | + $query = $right->getSQL($left, $left->modifyName($fieldname), $expr->op(), $isNot); | |
| 1169 | + } | |
| 1102 | 1170 | } |
| 1103 | 1171 | return $query; |
| 1104 | 1172 | } |
| ... | ... | @@ -1107,17 +1175,30 @@ class SQLQueryBuilder implements QueryBuilder |
| 1107 | 1175 | { |
| 1108 | 1176 | if (count($this->metadata) + count($this->db) == 0) |
| 1109 | 1177 | { |
| 1110 | - throw new Exception('nothing to do'); | |
| 1178 | + // return empty result set | |
| 1179 | + return 'select 1 from documents where false'; | |
| 1111 | 1180 | } |
| 1112 | 1181 | |
| 1113 | - // we are doing this because content table is dependant on metadata table | |
| 1114 | - if ($this->used_tables['document_content_version'] > 0) $this->used_tables['document_metadata_version']++; | |
| 1115 | - | |
| 1116 | 1182 | $sql = |
| 1117 | 1183 | 'SELECT ' . "\n"; |
| 1118 | 1184 | |
| 1119 | - $sql .= | |
| 1185 | + if ($this->context == ExprContext::DOCUMENT) | |
| 1186 | + { | |
| 1187 | + // we are doing this because content table is dependant on metadata table | |
| 1188 | + if ($this->used_tables['document_content_version'] > 0) | |
| 1189 | + { | |
| 1190 | + $this->used_tables['document_metadata_version']++; | |
| 1191 | + } | |
| 1192 | + | |
| 1193 | + $sql .= | |
| 1120 | 1194 | ' DISTINCT d.id, dmv.name as title'; |
| 1195 | + } | |
| 1196 | + else | |
| 1197 | + { | |
| 1198 | + $sql .= | |
| 1199 | + ' DISTINCT f.id, f.name as title'; | |
| 1200 | + } | |
| 1201 | + | |
| 1121 | 1202 | |
| 1122 | 1203 | $offset=0; |
| 1123 | 1204 | foreach($this->db as $expr) |
| ... | ... | @@ -1133,26 +1214,36 @@ class SQLQueryBuilder implements QueryBuilder |
| 1133 | 1214 | } |
| 1134 | 1215 | |
| 1135 | 1216 | $sql .= |
| 1136 | - "\n" . 'FROM ' ."\n" . | |
| 1137 | - ' documents d ' ."\n"; | |
| 1217 | + "\n" . 'FROM ' ."\n"; | |
| 1138 | 1218 | |
| 1139 | - if ($this->used_tables['document_metadata_version'] > 0) | |
| 1140 | - { | |
| 1141 | - $sql .= ' INNER JOIN document_metadata_version dmv ON d.metadata_version_id=dmv.id' . "\n"; | |
| 1142 | - } | |
| 1143 | - if ($this->used_tables['document_content_version'] > 0) | |
| 1144 | - { | |
| 1145 | - $sql .= ' INNER JOIN document_content_version dcv ON dmv.content_version_id=dcv.id ' . "\n"; | |
| 1146 | - } | |
| 1147 | - if ($this->used_tables['document_fields_link'] > 0) | |
| 1219 | + if ($this->context == ExprContext::DOCUMENT) | |
| 1148 | 1220 | { |
| 1149 | - $sql .= ' LEFT JOIN document_fields_link pdfl ON dmv.id=pdfl.metadata_version_id ' . "\n"; | |
| 1150 | - } | |
| 1221 | + $primaryAlias = 'd'; | |
| 1222 | + $sql .= ' documents d ' ."\n"; | |
| 1151 | 1223 | |
| 1152 | - if ($this->used_tables['tag_words'] > 0) | |
| 1224 | + if ($this->used_tables['document_metadata_version'] > 0) | |
| 1225 | + { | |
| 1226 | + $sql .= ' INNER JOIN document_metadata_version dmv ON d.metadata_version_id=dmv.id' . "\n"; | |
| 1227 | + } | |
| 1228 | + if ($this->used_tables['document_content_version'] > 0) | |
| 1229 | + { | |
| 1230 | + $sql .= ' INNER JOIN document_content_version dcv ON dmv.content_version_id=dcv.id ' . "\n"; | |
| 1231 | + } | |
| 1232 | + if ($this->used_tables['document_fields_link'] > 0) | |
| 1233 | + { | |
| 1234 | + $sql .= ' LEFT JOIN document_fields_link pdfl ON dmv.id=pdfl.metadata_version_id ' . "\n"; | |
| 1235 | + } | |
| 1236 | + | |
| 1237 | + if ($this->used_tables['tag_words'] > 0) | |
| 1238 | + { | |
| 1239 | + $sql .= ' LEFT OUTER JOIN document_tags dt ON dt.document_id=d.id ' . "\n" . | |
| 1240 | + ' LEFT OUTER JOIN tag_words tw ON dt.tag_id = tw.id ' . "\n"; | |
| 1241 | + } | |
| 1242 | + } | |
| 1243 | + else | |
| 1153 | 1244 | { |
| 1154 | - $sql .= ' LEFT OUTER JOIN document_tags dt ON dt.document_id=d.id ' . "\n" . | |
| 1155 | - ' LEFT OUTER JOIN tag_words tw ON dt.tag_id = tw.id ' . "\n"; | |
| 1245 | + $primaryAlias = 'f'; | |
| 1246 | + $sql .= ' folders f ' ."\n"; | |
| 1156 | 1247 | } |
| 1157 | 1248 | |
| 1158 | 1249 | $offset = 0; |
| ... | ... | @@ -1171,17 +1262,18 @@ class SQLQueryBuilder implements QueryBuilder |
| 1171 | 1262 | $offset++; |
| 1172 | 1263 | } |
| 1173 | 1264 | |
| 1174 | - | |
| 1175 | - | |
| 1176 | - $offset=0; | |
| 1177 | - foreach($this->metadata as $expr) | |
| 1265 | + if ($this->context == ExprContext::DOCUMENT) | |
| 1178 | 1266 | { |
| 1179 | - $offset++; | |
| 1180 | - $field = $expr->left(); | |
| 1267 | + $offset=0; | |
| 1268 | + foreach($this->metadata as $expr) | |
| 1269 | + { | |
| 1270 | + $offset++; | |
| 1271 | + $field = $expr->left(); | |
| 1181 | 1272 | |
| 1182 | - $fieldid = $field->getFieldId(); | |
| 1183 | - $sql .= " LEFT JOIN document_fields_link dfl$offset ON dfl$offset.metadata_version_id=d.metadata_version_id AND dfl$offset.document_field_id=$fieldid" . "\n"; | |
| 1184 | - $sql .= " LEFT JOIN document_fields df$offset ON df$offset.id=dfl$offset.document_field_id" . "\n"; | |
| 1273 | + $fieldid = $field->getFieldId(); | |
| 1274 | + $sql .= " LEFT JOIN document_fields_link dfl$offset ON dfl$offset.metadata_version_id=d.metadata_version_id AND dfl$offset.document_field_id=$fieldid" . "\n"; | |
| 1275 | + $sql .= " LEFT JOIN document_fields df$offset ON df$offset.id=dfl$offset.document_field_id" . "\n"; | |
| 1276 | + } | |
| 1185 | 1277 | } |
| 1186 | 1278 | |
| 1187 | 1279 | // Add permissions sql for read access |
| ... | ... | @@ -1189,15 +1281,16 @@ class SQLQueryBuilder implements QueryBuilder |
| 1189 | 1281 | $permId = $oPermission->getID(); |
| 1190 | 1282 | $oUser = User::get($_SESSION['userID']); |
| 1191 | 1283 | $aPermissionDescriptors = KTPermissionUtil::getPermissionDescriptorsForUser($oUser); |
| 1192 | - $sPermissionDescriptors = (!empty($aPermissionDescriptors)) ? implode(',', $aPermissionDescriptors) : ''; | |
| 1284 | + $sPermissionDescriptors = empty($aPermissionDescriptors)? -1: implode(',', $aPermissionDescriptors); | |
| 1193 | 1285 | |
| 1194 | - $sql .= 'LEFT JOIN folders f ON d.folder_id = f.id '. "\n"; | |
| 1195 | - | |
| 1196 | - $sql .= 'INNER JOIN permission_lookups AS PL ON f.permission_lookup_id = PL.id '. "\n"; | |
| 1286 | + $sql .= "INNER JOIN permission_lookups AS PL ON $primaryAlias.permission_lookup_id = PL.id\n"; | |
| 1197 | 1287 | $sql .= 'INNER JOIN permission_lookup_assignments AS PLA ON PL.id = PLA.permission_lookup_id AND PLA.permission_id = '.$permId. " \n"; |
| 1288 | + $sql .= "WHERE PLA.permission_descriptor_id IN ($sPermissionDescriptors) AND "; | |
| 1198 | 1289 | |
| 1199 | - $sql .= "WHERE PLA.permission_descriptor_id IN ($sPermissionDescriptors) AND dmv.status_id=1 AND d.status_id=1 AND \n "; | |
| 1200 | - | |
| 1290 | + if ($this->context == ExprContext::DOCUMENT) | |
| 1291 | + { | |
| 1292 | + $sql .= "dmv.status_id=1 AND d.status_id=1 AND \n "; | |
| 1293 | + } | |
| 1201 | 1294 | return $sql; |
| 1202 | 1295 | } |
| 1203 | 1296 | |
| ... | ... | @@ -1222,8 +1315,6 @@ class SQLQueryBuilder implements QueryBuilder |
| 1222 | 1315 | |
| 1223 | 1316 | private function resolveJoinOffset($expr) |
| 1224 | 1317 | { |
| 1225 | - | |
| 1226 | - | |
| 1227 | 1318 | $offset=0; |
| 1228 | 1319 | foreach($this->db as $item) |
| 1229 | 1320 | { |
| ... | ... | @@ -1242,11 +1333,18 @@ class SQLQueryBuilder implements QueryBuilder |
| 1242 | 1333 | $right = $expr->right(); |
| 1243 | 1334 | if (DefaultOpCollection::isBoolean($expr)) |
| 1244 | 1335 | { |
| 1245 | - $query = '(' . $this->buildCoreSQLExpr($left) . ' ' . $expr->op() . ' ' . $this->buildCoreSQLExpr($right) . ')'; | |
| 1336 | + $query = '(' . $this->buildCoreSQLExpr($left) . ' ' . $expr->op() . ' ' . $this->buildCoreSQLExpr($right) . ')'; | |
| 1246 | 1337 | } |
| 1247 | 1338 | else |
| 1248 | 1339 | { |
| 1249 | - $query = $this->getSQLEvalExpr($expr); | |
| 1340 | + if (($this->context & $expr->appliesToContext()) == $this->context) | |
| 1341 | + { | |
| 1342 | + $query = $this->getSQLEvalExpr($expr); | |
| 1343 | + } | |
| 1344 | + else | |
| 1345 | + { | |
| 1346 | + $query = 'false'; | |
| 1347 | + } | |
| 1250 | 1348 | } |
| 1251 | 1349 | |
| 1252 | 1350 | return $query; |
| ... | ... | @@ -1259,7 +1357,11 @@ class SQLQueryBuilder implements QueryBuilder |
| 1259 | 1357 | |
| 1260 | 1358 | $sql = $this->buildCoreSQL(); |
| 1261 | 1359 | |
| 1262 | - $sql .= $this->buildCoreSQLExpr($expr); | |
| 1360 | + $expr = $this->buildCoreSQLExpr($expr); | |
| 1361 | + if ($expr != 'false') | |
| 1362 | + { | |
| 1363 | + $sql .= $expr; | |
| 1364 | + } | |
| 1263 | 1365 | |
| 1264 | 1366 | return $sql; |
| 1265 | 1367 | } |
| ... | ... | @@ -1299,19 +1401,22 @@ class SQLQueryBuilder implements QueryBuilder |
| 1299 | 1401 | $sql .= $value->getSQL($field, $left->modifyName($fieldname), $expr->op(), $expr->not()); |
| 1300 | 1402 | } |
| 1301 | 1403 | |
| 1302 | - $moffset=0; | |
| 1303 | - foreach($this->metadata as $expr) | |
| 1404 | + if ($this->context == ExprContext::DOCUMENT) | |
| 1304 | 1405 | { |
| 1305 | - $moffset++; | |
| 1306 | - if ($offset++) | |
| 1406 | + $moffset=0; | |
| 1407 | + foreach($this->metadata as $expr) | |
| 1307 | 1408 | { |
| 1308 | - $sql .= " $op\n " ; | |
| 1309 | - } | |
| 1409 | + $moffset++; | |
| 1410 | + if ($offset++) | |
| 1411 | + { | |
| 1412 | + $sql .= " $op\n " ; | |
| 1413 | + } | |
| 1310 | 1414 | |
| 1311 | - $field = $expr->left(); | |
| 1312 | - $value = $expr->right(); | |
| 1415 | + $field = $expr->left(); | |
| 1416 | + $value = $expr->right(); | |
| 1313 | 1417 | |
| 1314 | - $sql .= $value->getSQL($field, "dfl$moffset.value", $expr->getOp()); | |
| 1418 | + $sql .= $value->getSQL($field, "dfl$moffset.value", $expr->getOp()); | |
| 1419 | + } | |
| 1315 | 1420 | } |
| 1316 | 1421 | |
| 1317 | 1422 | return $sql; |
| ... | ... | @@ -1331,7 +1436,6 @@ class SQLQueryBuilder implements QueryBuilder |
| 1331 | 1436 | |
| 1332 | 1437 | if (substr($col, 0, 4) == 'expr' && is_numeric(substr($col, 4))) |
| 1333 | 1438 | { |
| 1334 | - | |
| 1335 | 1439 | $exprno = substr($col, 4); |
| 1336 | 1440 | if ($exprno <= count($this->db)) |
| 1337 | 1441 | { |
| ... | ... | @@ -1379,8 +1483,6 @@ class SQLQueryBuilder implements QueryBuilder |
| 1379 | 1483 | } |
| 1380 | 1484 | return '(' . implode(') AND (', $text) . ')'; |
| 1381 | 1485 | } |
| 1382 | - | |
| 1383 | - | |
| 1384 | 1486 | } |
| 1385 | 1487 | |
| 1386 | 1488 | |
| ... | ... | @@ -1444,6 +1546,13 @@ class OpExpr extends Expr |
| 1444 | 1546 | $this->has_text=$value; |
| 1445 | 1547 | } |
| 1446 | 1548 | |
| 1549 | + public function setContext($context) | |
| 1550 | + { | |
| 1551 | + parent::setContext($context); | |
| 1552 | + $this->left()->setContext($context); | |
| 1553 | + $this->right()->setContext($context); | |
| 1554 | + } | |
| 1555 | + | |
| 1447 | 1556 | public function getHasDb() |
| 1448 | 1557 | { |
| 1449 | 1558 | return $this->has_db; |
| ... | ... | @@ -1619,7 +1728,6 @@ class OpExpr extends Expr |
| 1619 | 1728 | |
| 1620 | 1729 | $point = null; |
| 1621 | 1730 | |
| 1622 | - | |
| 1623 | 1731 | if ($left_op_match && $right_op_match) { $point = 'point'; } |
| 1624 | 1732 | |
| 1625 | 1733 | $left_op_match_flex = $left_op_match || ($left->isOpExpr()); |
| ... | ... | @@ -1682,6 +1790,11 @@ class OpExpr extends Expr |
| 1682 | 1790 | return $this->getHasDb() && $this->getHasText(); |
| 1683 | 1791 | } |
| 1684 | 1792 | |
| 1793 | + public function appliesToContext() | |
| 1794 | + { | |
| 1795 | + return $this->left()->appliesToContext() | $this->right()->appliesToContext(); | |
| 1796 | + } | |
| 1797 | + | |
| 1685 | 1798 | /** |
| 1686 | 1799 | * Enter description here... |
| 1687 | 1800 | * |
| ... | ... | @@ -1805,7 +1918,7 @@ class OpExpr extends Expr |
| 1805 | 1918 | * @param array $rightres |
| 1806 | 1919 | * @return array |
| 1807 | 1920 | */ |
| 1808 | - protected static function intersect($leftres, $rightres) | |
| 1921 | + protected static function _intersect($leftres, $rightres) | |
| 1809 | 1922 | { |
| 1810 | 1923 | if (empty($leftres) || empty($rightres)) |
| 1811 | 1924 | { |
| ... | ... | @@ -1814,7 +1927,7 @@ class OpExpr extends Expr |
| 1814 | 1927 | $result = array(); |
| 1815 | 1928 | foreach($leftres as $item) |
| 1816 | 1929 | { |
| 1817 | - $document_id = $item->DocumentID; | |
| 1930 | + $document_id = $item->Id; | |
| 1818 | 1931 | |
| 1819 | 1932 | if (!$item->IsLive) |
| 1820 | 1933 | { |
| ... | ... | @@ -1831,6 +1944,22 @@ class OpExpr extends Expr |
| 1831 | 1944 | return $result; |
| 1832 | 1945 | } |
| 1833 | 1946 | |
| 1947 | + protected static function intersect($leftres, $rightres) | |
| 1948 | + { | |
| 1949 | + return array( | |
| 1950 | + 'docs'=>self::_intersect($leftres['docs'],$rightres['docs']), | |
| 1951 | + 'folders'=>self::_intersect($leftres['folders'],$rightres['folders']) | |
| 1952 | + ); | |
| 1953 | + } | |
| 1954 | + | |
| 1955 | + protected static function union($leftres, $rightres) | |
| 1956 | + { | |
| 1957 | + return array( | |
| 1958 | + 'docs'=>self::_union($leftres['docs'],$rightres['docs']), | |
| 1959 | + 'folders'=>self::_union($leftres['folders'],$rightres['folders']) | |
| 1960 | + ); | |
| 1961 | + } | |
| 1962 | + | |
| 1834 | 1963 | /** |
| 1835 | 1964 | * The objective of this function is to merge the results so that there is a union of the results, |
| 1836 | 1965 | * but there should be no duplicates. |
| ... | ... | @@ -1839,7 +1968,7 @@ class OpExpr extends Expr |
| 1839 | 1968 | * @param array $rightres |
| 1840 | 1969 | * @return array |
| 1841 | 1970 | */ |
| 1842 | - protected static function union($leftres, $rightres) | |
| 1971 | + protected static function _union($leftres, $rightres) | |
| 1843 | 1972 | { |
| 1844 | 1973 | if (empty($leftres)) |
| 1845 | 1974 | { |
| ... | ... | @@ -1855,15 +1984,15 @@ class OpExpr extends Expr |
| 1855 | 1984 | { |
| 1856 | 1985 | if ($item->IsLive) |
| 1857 | 1986 | { |
| 1858 | - $result[$item->DocumentID] = $item; | |
| 1987 | + $result[$item->Id] = $item; | |
| 1859 | 1988 | } |
| 1860 | 1989 | } |
| 1861 | 1990 | |
| 1862 | 1991 | foreach($rightres as $item) |
| 1863 | 1992 | { |
| 1864 | - if (!array_key_exists($item->DocumentID, $result) || $item->Rank > $result[$item->DocumentID]->Rank) | |
| 1993 | + if (!array_key_exists($item->Id, $result) || $item->Rank > $result[$item->Id]->Rank) | |
| 1865 | 1994 | { |
| 1866 | - $result[$item->DocumentID] = $item; | |
| 1995 | + $result[$item->Id] = $item; | |
| 1867 | 1996 | } |
| 1868 | 1997 | } |
| 1869 | 1998 | return $result; |
| ... | ... | @@ -1996,7 +2125,7 @@ class OpExpr extends Expr |
| 1996 | 2125 | { |
| 1997 | 2126 | if (empty($group)) { return array(); } |
| 1998 | 2127 | |
| 1999 | - $exprbuilder = new SQLQueryBuilder(); | |
| 2128 | + $exprbuilder = new SQLQueryBuilder($this->getContext()); | |
| 2000 | 2129 | |
| 2001 | 2130 | if (count($group) == 1) |
| 2002 | 2131 | { |
| ... | ... | @@ -2020,11 +2149,18 @@ class OpExpr extends Expr |
| 2020 | 2149 | |
| 2021 | 2150 | foreach($rs as $item) |
| 2022 | 2151 | { |
| 2023 | - $document_id = $item['id']; | |
| 2152 | + $id = $item['id']; | |
| 2024 | 2153 | $rank = $exprbuilder->getRanking($item); |
| 2025 | - if (!array_key_exists($document_id, $results) || $rank > $results[$document_id]->Rank) | |
| 2154 | + if (!array_key_exists($id, $results) || $rank > $results[$id]->Rank) | |
| 2026 | 2155 | { |
| 2027 | - $results[$document_id] = new QueryResultItem($document_id, $rank, $item['title'], $exprbuilder->getResultText($item)); | |
| 2156 | + if ($this->context == ExprContext::DOCUMENT) | |
| 2157 | + { | |
| 2158 | + $results[$id] = new DocumentResultItem($id, $rank, $item['title'], $exprbuilder->getResultText($item)); | |
| 2159 | + } | |
| 2160 | + else | |
| 2161 | + { | |
| 2162 | + $results[$id] = new FolderResultItem($id, $rank, $item['title'], $exprbuilder->getResultText($item)); | |
| 2163 | + } | |
| 2028 | 2164 | } |
| 2029 | 2165 | } |
| 2030 | 2166 | |
| ... | ... | @@ -2034,7 +2170,10 @@ class OpExpr extends Expr |
| 2034 | 2170 | |
| 2035 | 2171 | private function exec_text_query($op, $group) |
| 2036 | 2172 | { |
| 2037 | - if (empty($group)) { return array(); } | |
| 2173 | + if (($this->getContext() != ExprContext::DOCUMENT) || empty($group)) | |
| 2174 | + { | |
| 2175 | + return array(); | |
| 2176 | + } | |
| 2038 | 2177 | |
| 2039 | 2178 | $exprbuilder = new TextQueryBuilder(); |
| 2040 | 2179 | |
| ... | ... | @@ -2060,12 +2199,21 @@ class OpExpr extends Expr |
| 2060 | 2199 | } |
| 2061 | 2200 | |
| 2062 | 2201 | return $results; |
| 2063 | - | |
| 2064 | - | |
| 2065 | 2202 | } |
| 2066 | 2203 | |
| 2067 | - public function evaluate() | |
| 2204 | + public function evaluate($context = ExprContext::DOCUMENT_AND_FOLDER) | |
| 2068 | 2205 | { |
| 2206 | + if ($context == ExprContext::DOCUMENT_AND_FOLDER) | |
| 2207 | + { | |
| 2208 | + $docs = $this->evaluate(ExprContext::DOCUMENT); | |
| 2209 | + $folders = $this->evaluate(ExprContext::FOLDER); | |
| 2210 | + | |
| 2211 | + return array( | |
| 2212 | + 'docs' => $docs['docs'], | |
| 2213 | + 'folders' => $folders['folders']); | |
| 2214 | + } | |
| 2215 | + $this->setContext($context); | |
| 2216 | + | |
| 2069 | 2217 | $left = $this->left(); |
| 2070 | 2218 | $right = $this->right(); |
| 2071 | 2219 | $op = $this->op(); |
| ... | ... | @@ -2075,12 +2223,12 @@ class OpExpr extends Expr |
| 2075 | 2223 | { |
| 2076 | 2224 | $point = 'point'; |
| 2077 | 2225 | } |
| 2226 | + $resultContext = ($this->getContext() == ExprContext::DOCUMENT)?'docs':'folders'; | |
| 2078 | 2227 | |
| 2079 | 2228 | if ($point == 'merge') |
| 2080 | 2229 | { |
| 2081 | - | |
| 2082 | - $leftres = $left->evaluate(); | |
| 2083 | - $rightres = $right->evaluate(); | |
| 2230 | + $leftres = $left->evaluate($context); | |
| 2231 | + $rightres = $right->evaluate($context); | |
| 2084 | 2232 | switch ($op) |
| 2085 | 2233 | { |
| 2086 | 2234 | case ExprOp::OP_AND: |
| ... | ... | @@ -2099,31 +2247,33 @@ class OpExpr extends Expr |
| 2099 | 2247 | { |
| 2100 | 2248 | if ($this->isDBonly()) |
| 2101 | 2249 | { |
| 2102 | - $result = $this->exec_db_query($op, array($this)); | |
| 2250 | + $result[$resultContext] = $this->exec_db_query($op, array($this)); | |
| 2103 | 2251 | } |
| 2104 | 2252 | elseif ($this->isTextOnly()) |
| 2105 | 2253 | { |
| 2106 | - $result = $this->exec_text_query($op, array($this)); | |
| 2254 | + $result[$resultContext] = $this->exec_text_query($op, array($this)); | |
| 2107 | 2255 | } |
| 2108 | 2256 | elseif (in_array($op, array(ExprOp::OP_OR, ExprOp::OP_AND))) |
| 2109 | 2257 | { |
| 2258 | + // do we get to this??? | |
| 2259 | + // TODO: remove me please.... the simpleQuery stuff should go??? | |
| 2110 | 2260 | $db_group = array(); |
| 2111 | 2261 | $text_group = array(); |
| 2112 | 2262 | $this->explore($left, $right, $db_group, 'db'); |
| 2113 | 2263 | $this->explore($left, $right, $text_group, 'text'); |
| 2114 | 2264 | |
| 2115 | - $db_result = $this->exec_db_query($op, $db_group); | |
| 2116 | - $text_result = $this->exec_text_query($op, $text_group); | |
| 2265 | + $db_result[$resultContext] = $this->exec_db_query($op, $db_group); | |
| 2266 | + $text_result[$resultContext] = $this->exec_text_query($op, $text_group); | |
| 2117 | 2267 | |
| 2118 | 2268 | switch ($op) |
| 2119 | 2269 | { |
| 2120 | 2270 | case ExprOp::OP_AND: |
| 2121 | 2271 | if ($this->debug) print "\n\npoint: intersect\n\n"; |
| 2122 | - $result = OpExpr::intersect($db_result, $text_result); | |
| 2272 | + $result[$resultContext] = OpExpr::intersect($db_result, $text_result); | |
| 2123 | 2273 | break; |
| 2124 | 2274 | case ExprOp::OP_OR: |
| 2125 | 2275 | if ($this->debug) print "\n\nmerge: union\n\n"; |
| 2126 | - $result = OpExpr::union($db_result, $text_result); | |
| 2276 | + $result[$resultContext] = OpExpr::union($db_result, $text_result); | |
| 2127 | 2277 | break; |
| 2128 | 2278 | default: |
| 2129 | 2279 | throw new Exception('how did this happen??'); |
| ... | ... | @@ -2141,9 +2291,9 @@ class OpExpr extends Expr |
| 2141 | 2291 | } |
| 2142 | 2292 | |
| 2143 | 2293 | $permResults = array(); |
| 2144 | - foreach($result as $idx=>$item) | |
| 2294 | + foreach($result[$resultContext] as $idx=>$item) | |
| 2145 | 2295 | { |
| 2146 | - $permResults[$idx] = $item; | |
| 2296 | + $permResults[$resultContext][$idx] = $item; | |
| 2147 | 2297 | } |
| 2148 | 2298 | |
| 2149 | 2299 | return $permResults; | ... | ... |
search2/search/fields/CreatedByField.inc.php
| ... | ... | @@ -7,31 +7,31 @@ |
| 7 | 7 | * Document Management Made Simple |
| 8 | 8 | * Copyright (C) 2008 KnowledgeTree Inc. |
| 9 | 9 | * Portions copyright The Jam Warehouse Software (Pty) Limited |
| 10 | - * | |
| 10 | + * | |
| 11 | 11 | * This program is free software; you can redistribute it and/or modify it under |
| 12 | 12 | * the terms of the GNU General Public License version 3 as published by the |
| 13 | 13 | * Free Software Foundation. |
| 14 | - * | |
| 14 | + * | |
| 15 | 15 | * This program is distributed in the hope that it will be useful, but WITHOUT |
| 16 | 16 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
| 17 | 17 | * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more |
| 18 | 18 | * details. |
| 19 | - * | |
| 19 | + * | |
| 20 | 20 | * You should have received a copy of the GNU General Public License |
| 21 | 21 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 22 | - * | |
| 23 | - * You can contact KnowledgeTree Inc., PO Box 7775 #87847, San Francisco, | |
| 22 | + * | |
| 23 | + * You can contact KnowledgeTree Inc., PO Box 7775 #87847, San Francisco, | |
| 24 | 24 | * California 94120-7775, or email info@knowledgetree.com. |
| 25 | - * | |
| 25 | + * | |
| 26 | 26 | * The interactive user interfaces in modified source and object code versions |
| 27 | 27 | * of this program must display Appropriate Legal Notices, as required under |
| 28 | 28 | * Section 5 of the GNU General Public License version 3. |
| 29 | - * | |
| 29 | + * | |
| 30 | 30 | * In accordance with Section 7(b) of the GNU General Public License version 3, |
| 31 | 31 | * these Appropriate Legal Notices must retain the display of the "Powered by |
| 32 | - * KnowledgeTree" logo and retain the original copyright notice. If the display of the | |
| 32 | + * KnowledgeTree" logo and retain the original copyright notice. If the display of the | |
| 33 | 33 | * logo is not reasonably feasible for technical reasons, the Appropriate Legal Notices |
| 34 | - * must display the words "Powered by KnowledgeTree" and retain the original | |
| 34 | + * must display the words "Powered by KnowledgeTree" and retain the original | |
| 35 | 35 | * copyright notice. |
| 36 | 36 | * Contributor( s): ______________________________________ |
| 37 | 37 | * |
| ... | ... | @@ -47,6 +47,25 @@ class CreatedByField extends DBFieldExpr |
| 47 | 47 | $this->matchField('name'); |
| 48 | 48 | } |
| 49 | 49 | |
| 50 | + public function appliesToContext() | |
| 51 | + { | |
| 52 | + return ExprContext::DOCUMENT | ExprContext::FOLDER; | |
| 53 | + } | |
| 54 | + | |
| 55 | + public function setContext($context) | |
| 56 | + { | |
| 57 | + parent::setContext($context); | |
| 58 | + switch($context) | |
| 59 | + { | |
| 60 | + case ExprContext::DOCUMENT: | |
| 61 | + $this->table = 'documents'; | |
| 62 | + break; | |
| 63 | + case ExprContext::FOLDER: | |
| 64 | + $this->table = 'folders'; | |
| 65 | + break; | |
| 66 | + } | |
| 67 | + } | |
| 68 | + | |
| 50 | 69 | public function getInputRequirements() |
| 51 | 70 | { |
| 52 | 71 | return array('value'=>array('type'=>FieldInputType::USER_LIST)); | ... | ... |
search2/search/fields/FullPathField.inc.php
| ... | ... | @@ -7,31 +7,31 @@ |
| 7 | 7 | * Document Management Made Simple |
| 8 | 8 | * Copyright (C) 2008 KnowledgeTree Inc. |
| 9 | 9 | * Portions copyright The Jam Warehouse Software (Pty) Limited |
| 10 | - * | |
| 10 | + * | |
| 11 | 11 | * This program is free software; you can redistribute it and/or modify it under |
| 12 | 12 | * the terms of the GNU General Public License version 3 as published by the |
| 13 | 13 | * Free Software Foundation. |
| 14 | - * | |
| 14 | + * | |
| 15 | 15 | * This program is distributed in the hope that it will be useful, but WITHOUT |
| 16 | 16 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
| 17 | 17 | * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more |
| 18 | 18 | * details. |
| 19 | - * | |
| 19 | + * | |
| 20 | 20 | * You should have received a copy of the GNU General Public License |
| 21 | 21 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 22 | - * | |
| 23 | - * You can contact KnowledgeTree Inc., PO Box 7775 #87847, San Francisco, | |
| 22 | + * | |
| 23 | + * You can contact KnowledgeTree Inc., PO Box 7775 #87847, San Francisco, | |
| 24 | 24 | * California 94120-7775, or email info@knowledgetree.com. |
| 25 | - * | |
| 25 | + * | |
| 26 | 26 | * The interactive user interfaces in modified source and object code versions |
| 27 | 27 | * of this program must display Appropriate Legal Notices, as required under |
| 28 | 28 | * Section 5 of the GNU General Public License version 3. |
| 29 | - * | |
| 29 | + * | |
| 30 | 30 | * In accordance with Section 7(b) of the GNU General Public License version 3, |
| 31 | 31 | * these Appropriate Legal Notices must retain the display of the "Powered by |
| 32 | - * KnowledgeTree" logo and retain the original copyright notice. If the display of the | |
| 32 | + * KnowledgeTree" logo and retain the original copyright notice. If the display of the | |
| 33 | 33 | * logo is not reasonably feasible for technical reasons, the Appropriate Legal Notices |
| 34 | - * must display the words "Powered by KnowledgeTree" and retain the original | |
| 34 | + * must display the words "Powered by KnowledgeTree" and retain the original | |
| 35 | 35 | * copyright notice. |
| 36 | 36 | * Contributor( s): ______________________________________ |
| 37 | 37 | * |
| ... | ... | @@ -47,6 +47,25 @@ class FullPathField extends DBFieldExpr |
| 47 | 47 | $this->setAlias('FullPath'); |
| 48 | 48 | } |
| 49 | 49 | |
| 50 | + public function setContext($context) | |
| 51 | + { | |
| 52 | + parent::setContext($context); | |
| 53 | + switch($context) | |
| 54 | + { | |
| 55 | + case ExprContext::DOCUMENT: | |
| 56 | + $this->table = 'documents'; | |
| 57 | + break; | |
| 58 | + case ExprContext::FOLDER: | |
| 59 | + $this->table = 'folders'; | |
| 60 | + break; | |
| 61 | + } | |
| 62 | + } | |
| 63 | + | |
| 64 | + public function appliesToContext($context) | |
| 65 | + { | |
| 66 | + return ExprContext::DOCUMENT | ExprContext::FOLDER; | |
| 67 | + } | |
| 68 | + | |
| 50 | 69 | public function getInputRequirements() |
| 51 | 70 | { |
| 52 | 71 | return array('value'=>array('type'=>FieldInputType::TEXT)); | ... | ... |
search2/search/fields/TitleField.inc.php
| ... | ... | @@ -7,31 +7,31 @@ |
| 7 | 7 | * Document Management Made Simple |
| 8 | 8 | * Copyright (C) 2008 KnowledgeTree Inc. |
| 9 | 9 | * Portions copyright The Jam Warehouse Software (Pty) Limited |
| 10 | - * | |
| 10 | + * | |
| 11 | 11 | * This program is free software; you can redistribute it and/or modify it under |
| 12 | 12 | * the terms of the GNU General Public License version 3 as published by the |
| 13 | 13 | * Free Software Foundation. |
| 14 | - * | |
| 14 | + * | |
| 15 | 15 | * This program is distributed in the hope that it will be useful, but WITHOUT |
| 16 | 16 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
| 17 | 17 | * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more |
| 18 | 18 | * details. |
| 19 | - * | |
| 19 | + * | |
| 20 | 20 | * You should have received a copy of the GNU General Public License |
| 21 | 21 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 22 | - * | |
| 23 | - * You can contact KnowledgeTree Inc., PO Box 7775 #87847, San Francisco, | |
| 22 | + * | |
| 23 | + * You can contact KnowledgeTree Inc., PO Box 7775 #87847, San Francisco, | |
| 24 | 24 | * California 94120-7775, or email info@knowledgetree.com. |
| 25 | - * | |
| 25 | + * | |
| 26 | 26 | * The interactive user interfaces in modified source and object code versions |
| 27 | 27 | * of this program must display Appropriate Legal Notices, as required under |
| 28 | 28 | * Section 5 of the GNU General Public License version 3. |
| 29 | - * | |
| 29 | + * | |
| 30 | 30 | * In accordance with Section 7(b) of the GNU General Public License version 3, |
| 31 | 31 | * these Appropriate Legal Notices must retain the display of the "Powered by |
| 32 | - * KnowledgeTree" logo and retain the original copyright notice. If the display of the | |
| 32 | + * KnowledgeTree" logo and retain the original copyright notice. If the display of the | |
| 33 | 33 | * logo is not reasonably feasible for technical reasons, the Appropriate Legal Notices |
| 34 | - * must display the words "Powered by KnowledgeTree" and retain the original | |
| 34 | + * must display the words "Powered by KnowledgeTree" and retain the original | |
| 35 | 35 | * copyright notice. |
| 36 | 36 | * Contributor( s): ______________________________________ |
| 37 | 37 | * |
| ... | ... | @@ -39,13 +39,31 @@ |
| 39 | 39 | |
| 40 | 40 | class TitleField extends DBFieldExpr |
| 41 | 41 | { |
| 42 | - | |
| 43 | 42 | public function __construct() |
| 44 | 43 | { |
| 45 | 44 | parent::__construct('name', 'document_metadata_version', _kt('Title')); |
| 46 | 45 | $this->setAlias('Title'); |
| 47 | 46 | } |
| 48 | 47 | |
| 48 | + public function setContext($context) | |
| 49 | + { | |
| 50 | + parent::setContext($context); | |
| 51 | + switch($context) | |
| 52 | + { | |
| 53 | + case ExprContext::DOCUMENT: | |
| 54 | + $this->table = 'document_metadata_version'; | |
| 55 | + break; | |
| 56 | + case ExprContext::FOLDER: | |
| 57 | + $this->table = 'folders'; | |
| 58 | + break; | |
| 59 | + } | |
| 60 | + } | |
| 61 | + | |
| 62 | + public function appliesToContext() | |
| 63 | + { | |
| 64 | + return ExprContext::DOCUMENT | ExprContext::FOLDER; | |
| 65 | + } | |
| 66 | + | |
| 49 | 67 | public function getInputRequirements() |
| 50 | 68 | { |
| 51 | 69 | return array('value'=>array('type'=>FieldInputType::TEXT)); | ... | ... |
search2/search/search.inc.php
| ... | ... | @@ -42,6 +42,8 @@ require_once('search/fieldRegistry.inc.php'); |
| 42 | 42 | require_once('search/expr.inc.php'); |
| 43 | 43 | require_once(KT_LIB_DIR . '/security/Permission.inc'); |
| 44 | 44 | |
| 45 | +// TODO: move standalone functions into a class.... what was I thinking? | |
| 46 | + | |
| 45 | 47 | function rank_compare($a, $b) |
| 46 | 48 | { |
| 47 | 49 | if ($a->Rank == $b->Rank) |
| ... | ... | @@ -66,6 +68,8 @@ function searchfix($str) |
| 66 | 68 | return str_replace(array("\n","\r"), array('',''), addslashes($str)); |
| 67 | 69 | } |
| 68 | 70 | |
| 71 | +// TODO: replace manual json construction with json_encode(). | |
| 72 | + | |
| 69 | 73 | class SearchHelper |
| 70 | 74 | { |
| 71 | 75 | public static function correctPath($path) |
| ... | ... | @@ -366,8 +370,6 @@ class SearchHelper |
| 366 | 370 | dtfl.document_type_id=$documentTypeID |
| 367 | 371 | ORDER BY |
| 368 | 372 | df.name"; |
| 369 | - | |
| 370 | - | |
| 371 | 373 | } |
| 372 | 374 | else |
| 373 | 375 | { |
| ... | ... | @@ -566,7 +568,8 @@ function processSearchExpression($query) |
| 566 | 568 | { |
| 567 | 569 | $expr = parseExpression($query); |
| 568 | 570 | |
| 569 | - $rs = $expr->evaluate(); | |
| 571 | + $rs = $expr->evaluate(ExprContext::DOCUMENT); | |
| 572 | + $rs = $rs['docs']; | |
| 570 | 573 | usort($rs, 'rank_compare'); |
| 571 | 574 | |
| 572 | 575 | $results = array(); |
| ... | ... | @@ -629,4 +632,57 @@ function processSearchExpression($query) |
| 629 | 632 | } |
| 630 | 633 | } |
| 631 | 634 | |
| 635 | +function resolveSearchShortcuts($result) | |
| 636 | +{ | |
| 637 | + $oPermission =& KTPermission::getByName('ktcore.permissions.read'); | |
| 638 | + $permId = $oPermission->getID(); | |
| 639 | + | |
| 640 | + $oUser = User::get($_SESSION['userID']); | |
| 641 | + $aPermissionDescriptors = KTPermissionUtil::getPermissionDescriptorsForUser($oUser); | |
| 642 | + $sPermissionDescriptors = empty($aPermissionDescriptors)? -1: implode(',', $aPermissionDescriptors); | |
| 643 | + | |
| 644 | + $documentIds = implode(',',array_keys($result['docs'])); | |
| 645 | + $linkedDocuments = array(); | |
| 646 | + if (!empty($documentIds)) | |
| 647 | + { | |
| 648 | + $sql = "SELECT d.id, d.linked_document_id from documents d "; | |
| 649 | + $sql .= 'INNER JOIN permission_lookups AS PL ON d.permission_lookup_id = PL.id '. "\n"; | |
| 650 | + $sql .= 'INNER JOIN permission_lookup_assignments AS PLA ON PL.id = PLA.permission_lookup_id AND PLA.permission_id = '.$permId. " \n"; | |
| 651 | + $sql .= " WHERE d.linked_document_id in ($documentIds) AND PLA.permission_descriptor_id IN ($sPermissionDescriptors)"; | |
| 652 | + | |
| 653 | + $rs = DBUtil::getResultArray($sql); | |
| 654 | + | |
| 655 | + foreach($rs as $row) | |
| 656 | + { | |
| 657 | + $id = $row['id']; | |
| 658 | + $linked_id = $row['linked_document_id']; | |
| 659 | + | |
| 660 | + $result['shortdocs'][$id] = new DocumentShortcutResultItem($id, $result['docs'][$linked_id]); | |
| 661 | + } | |
| 662 | + } | |
| 663 | + | |
| 664 | + $folderIds = implode(',',array_keys($result['folders'])); | |
| 665 | + $linkedFolders = array(); | |
| 666 | + | |
| 667 | + if (!empty($folderIds)) | |
| 668 | + { | |
| 669 | + | |
| 670 | + $sql = "SELECT f.id, f.linked_folder_id from folders f "; | |
| 671 | + $sql .= 'INNER JOIN permission_lookups AS PL ON f.permission_lookup_id = PL.id '. "\n"; | |
| 672 | + $sql .= 'INNER JOIN permission_lookup_assignments AS PLA ON PL.id = PLA.permission_lookup_id AND PLA.permission_id = '.$permId. " \n"; | |
| 673 | + $sql .= " WHERE f.linked_folder_id in ($folderIds) AND PLA.permission_descriptor_id IN ($sPermissionDescriptors)"; | |
| 674 | + | |
| 675 | + $rs = DBUtil::getResultArray($sql); | |
| 676 | + | |
| 677 | + foreach($rs as $row) | |
| 678 | + { | |
| 679 | + $id = $row['id']; | |
| 680 | + $linked_id = $row['linked_folder_id']; | |
| 681 | + | |
| 682 | + $result['shortfolders'][$id] = new FolderShortcutResultItem($id, $result['folders'][$linked_id]); | |
| 683 | + } | |
| 684 | + } | |
| 685 | + return $result; | |
| 686 | +} | |
| 687 | + | |
| 632 | 688 | ?> | ... | ... |
templates/ktcore/search2/search_results.smarty
| ... | ... | @@ -46,7 +46,6 @@ function saveSearch() |
| 46 | 46 | url='{/literal}{$rootUrl}{literal}/search2/ajax/saveExpr.php?txtName='+ escape(txtName.value) + |
| 47 | 47 | '&txtQuery=' + escape('{/literal}{$txtQuery|escape:'quotes'}{literal}'); |
| 48 | 48 | |
| 49 | - | |
| 50 | 49 | Ext.Ajax.request( |
| 51 | 50 | { |
| 52 | 51 | url: url, |
| ... | ... | @@ -132,57 +131,82 @@ function onShowAll(showall) |
| 132 | 131 | <table border=0 cellpadding="1" cellspacing="1" width="100%" align=center> |
| 133 | 132 | {assign var=cbid value=0} |
| 134 | 133 | |
| 135 | - {foreach item=document from=$results} | |
| 134 | + {i18n arg_count=$numResults}Search results found: #count#{/i18n} | |
| 135 | + <br/> | |
| 136 | + <br/> | |
| 137 | + | |
| 138 | + {foreach item=hit from=$results} | |
| 136 | 139 | <tr><td> |
| 137 | - <input type="checkbox" name="selection_d[]" id="cb{$cbid}" value="{$document->DocumentID}"><nobr> <a href="{$rootUrl}/view.php?fDocumentId={$document->DocumentID}"><B>{$document->Title|truncate:80}</b></a> | |
| 138 | - {if $document->Title != $document->Filename} | |
| 140 | + <input type="checkbox" {if $hit->IsDocument}name="selection_d[]"{else}name="selection_f[]"{/if} id="cb{$cbid}" value="{$hit->Id}"><nobr> | |
| 141 | + <span class="contenttype {$hit->MimeIconPath}"> | |
| 142 | + | |
| 143 | + {if $hit->IsDocument} | |
| 144 | + <a href="{$rootUrl}/view.php?fDocumentId={$hit->Id}"><B>{$hit->Title|truncate:80}</b></a> | |
| 145 | + {if $hit->Title != $hit->Filename} | |
| 139 | 146 | |
| 140 | - <font style=" color: green "> - Filename: {$document->Filename|truncate:40}</font> | |
| 147 | + <font style=" color: green "> - Filename: {$hit->Filename|truncate:40}</font> | |
| 141 | 148 | {/if} |
| 142 | - {if $document->IsAvailable} | |
| 149 | + {if $hit->IsAvailable} | |
| 143 | 150 | |
| 144 | - <img src="{$rootUrl}/resources/graphics/download.png" title="Download Document" onclick="document.location='{$rootUrl}/action.php?kt_path_info=ktcore.actions.document.view&fDocumentId={$document->DocumentID}';"></a> | |
| 151 | + <img src="{$rootUrl}/resources/graphics/download.png" title="Download Document" onclick="document.location='{$rootUrl}/action.php?kt_path_info=ktcore.actions.document.view&fDocumentId={$hit->Id}';"></a> | |
| 145 | 152 | |
| 146 | 153 | {/if} |
| 147 | 154 | |
| 148 | 155 | |
| 149 | - {if !$document->IsAvailable} | |
| 156 | + {if !$hit->IsAvailable} | |
| 150 | 157 | |
| 151 | 158 | <font style=" color: red "><B> * {i18n}NOT AVAILABLE{/i18n} * </B></font> |
| 152 | 159 | {/if} |
| 153 | 160 | |
| 161 | + {else} | |
| 162 | + <a href="{$rootUrl}/browse.php?fFolderId={$hit->RealId}{if $hit->IsProxy}&fShortcutFolder={$hit->Id}{/if}"><B>{$hit->Title|truncate:80}</b></a> | |
| 163 | + | |
| 164 | + {/if} | |
| 165 | + | |
| 154 | 166 | </nobr> |
| 155 | 167 | </td><td align=right> |
| 156 | - <font style="color: green ">{i18n}Document ID:{/i18n} {$document->DocumentID}</font> | |
| 157 | - | |
| 158 | - <font style=" color: orange ">{i18n}Version:{/i18n} {$document->Version}</font></td> | |
| 168 | + {if $hit->IsDocument} | |
| 169 | + <font style="color: green ">{i18n}Document ID:{/i18n} {$hit->Id}</font> | |
| 170 | + | |
| 171 | + <font style=" color: orange ">{i18n}Version:{/i18n} {$hit->Version}</font></td> | |
| 172 | + {else} | |
| 173 | + <font style="color: green ">{i18n}Folder ID:{/i18n} {$hit->Id}</font> | |
| 174 | + {/if} | |
| 159 | 175 | </tr> |
| 160 | - <tr><td colspan=2>{$document->Text}</td></tr> | |
| 161 | - <tr><td><font style=" color: green "><a href="{$rootUrl}/browse.php?fFolderId={$document->FolderId}" tag="{$document->FullPath}">{$document->FullPath|truncate:40}</a>/{$document->Title|truncate:40} - {$document->Filesize}</font> | |
| 162 | - | |
| 176 | + <tr><td colspan=2>{$hit->Text}</td></tr> | |
| 177 | + <tr><td> | |
| 178 | + {if $hit->IsDocument} | |
| 179 | + <font style=" color: green "><a href="{$rootUrl}/browse.php?fFolderId={$hit->FolderId}" tag="{$hit->FullPath}">{$hit->FullPath|truncate:40}</a>/{$hit->Title|truncate:40} - {$hit->Filesize}</font> | |
| 180 | + {else} | |
| 181 | + <font style=" color: green "><a href="{$rootUrl}/browse.php?fFolderId={$hit->FolderId}" tag="{$hit->FullPath}">{$hit->FullPath|truncate:40}</a></font> | |
| 182 | + {/if} | |
| 163 | 183 | </td> |
| 164 | 184 | <td align=right><nobr> |
| 165 | 185 | <font style="color: orange "> |
| 166 | - {i18n}Created By:{/i18n} {$document->CreatedBy} | |
| 167 | - {i18n}on{/i18n} {$document->DateCreated} | |
| 186 | + {i18n}Created By:{/i18n} {$hit->CreatedBy} | |
| 187 | + {if $hit->IsDocument} | |
| 188 | + {i18n}on{/i18n} {$hit->DateCreated} | |
| 189 | + {/if} | |
| 168 | 190 | </font> |
| 169 | 191 | </td> |
| 192 | + {if $hit->IsDocument} | |
| 170 | 193 | <tr><td> |
| 171 | 194 | {if $workflow != ''} |
| 172 | - <font style="color: orange ">{i18n}Workflow:{/i18n} $document->Workflow}</font> | |
| 195 | + <font style="color: orange ">{i18n}Workflow:{/i18n} $hit->Workflow}</font> | |
| 173 | 196 | {/if} |
| 174 | 197 | </td> |
| 175 | 198 | <td align=right><nobr> |
| 176 | 199 | <font style="color: brown "> |
| 177 | - {if $document->CheckedOutUser != ''} | |
| 178 | - <b>{i18n}Checked out by:{/i18n} {$document->CheckedOutUser} | |
| 179 | - {i18n}on{/i18n} {$document->DateCheckedOut}</b> | |
| 200 | + {if $hit->CheckedOutUser != ''} | |
| 201 | + <b>{i18n}Checked out by:{/i18n} {$hit->CheckedOutUser} | |
| 202 | + {i18n}on{/i18n} {$hit->DateCheckedOut}</b> | |
| 180 | 203 | {else} |
| 181 | - {i18n}Modified by:{/i18n} {$document->ModifiedBy} | |
| 182 | - {i18n}on{/i18n} {$document->DateModified} | |
| 204 | + {i18n}Modified by:{/i18n} {$hit->ModifiedBy} | |
| 205 | + {i18n}on{/i18n} {$hit->DateModified} | |
| 183 | 206 | {/if} |
| 184 | 207 | </font> |
| 185 | 208 | </td> |
| 209 | + {/if} | |
| 186 | 210 | |
| 187 | 211 | <tr><td colspan=2><br></br></td></tr></tr> |
| 188 | 212 | ... | ... |