Changeset 11915
- Timestamp:
- 08/30/07 20:24:14 (1 year ago)
- Files:
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/midcom/midcom.core/midcom/core/collector.php
r11911 r11915 101 101 * the query. 102 102 * 103 * NOTE: Checks not implemented yet 104 * 103 105 * Be aware, that this setting will currently not use the QB to filter the objects accordingly, 104 106 * since there is no way yet to filter against parameters. This will mean some performance 105 107 * impact. 106 108 * 107 * While on-site, this is enabled by default, in AIS it is disabled by default. 108 */ 109 var $hide_invisible = false; 109 */ 110 var $hide_invisible = true; 111 112 /** 113 * Keep track if $this->execute has been called 114 */ 115 var $_executed = false; 110 116 111 117 /** … … 158 164 // MidCOM's collector always uses the GUID as the key for ACL purposes 159 165 $this->_mc->set_key_property('guid'); 160 161 if (! array_key_exists("view_contentmgr", $GLOBALS)) 162 { 163 $this->hide_invisible = true; 164 165 if ($GLOBALS['midcom_config']['i18n_multilang_strict'] 166 && $_MIDCOM->i18n->get_midgard_language() != 0) 167 { 168 // FIXME: Re-enable this when it actually works 169 // $this->_mc->set_lang($_MIDCOM->i18n->get_midgard_language()); 170 } 171 } 172 } 173 166 if ( $GLOBALS['midcom_config']['i18n_multilang_strict'] 167 /* Why is this check here (check querybuilder.php for same functionality without this check) ? 168 && $_MIDCOM->i18n->get_midgard_language() != 0 169 */) 170 { 171 // FIXME: Re-enable this when it actually works 172 $this->_mc->set_lang($_MIDCOM->i18n->get_midgard_language()); 173 } 174 } 174 175 175 176 /** … … 181 182 call_user_func_array(array($this->_real_class, '_on_prepare_new_collector'), array(&$this)); 182 183 } 183 184 184 185 185 /** … … 192 192 * 1. bool _on_prepare_exec_collector(&$this) is called before the actual query execution. Return false to 193 193 * abort the operation. 194 * 2. The query is executed. 195 * 3. void _on_process_query_result(&$result) is called after the successful execution of the query. You 196 * may remove any unwanted entries from the resultset at this point. 197 * 198 * If the execution of the query fails for some reason all available error information is logged 199 * and a MIDCOM_ERRCRIT level error is triggered, halting execution. 200 * 201 * @param midgard_collector $mc An instance of the Query builder obtained by the new_collector 202 * function of this class. 203 * @return Array The result of the collector or null on any error. Note, that empty resultsets 204 * will return an empty array. 205 * @todo Implement proper count / Limit support. 194 * 195 * @return boolean indicating success/failure 196 * @see _real_execute() 206 197 */ 207 198 function execute() … … 212 203 debug_add('The _on_prepare_exec_collector callback returned false, so we abort now.'); 213 204 debug_pop(); 214 return null; 215 } 216 217 // Workaround until the QB does return empty arrays: All errors are empty resultsets and errors are ignored. 218 $result = $this->_mc->execute(); 219 if (!$result) 220 { 221 // Workaround mode for now 222 if (mgd_errno() != MGD_ERR_OK) 223 { 224 debug_push_class(__CLASS__, __FUNCTION__); 225 debug_print_r('Result was:', $result); 226 debug_add('The collector failed to execute, aborting.', MIDCOM_LOG_ERROR); 227 debug_add('Last Midgard error was: ' . mgd_errstr(), MIDCOM_LOG_ERROR); 228 if (isset($php_errormsg)) 229 { 230 debug_add("Error message was: {$php_errormsg}", MIDCOM_LOG_ERROR); 231 } 232 debug_pop(); 233 $_MIDCOM->generate_error(MIDCOM_ERRCRIT, 234 'The collector failed to execute, see the log file for more information.'); 235 // This will exit. 236 } 237 } 238 239 return $result; 205 return false; 206 } 207 $this->_executed = true; 208 return true; 209 } 210 211 /** 212 * Executes the MC 213 * 214 * @return void 215 * @see midgard_collector::execute() 216 */ 217 function _real_execute() 218 { 219 return $this->_mc->execute(); 240 220 } 241 221 222 /** 223 * Resets some internal variables for re-execute 224 */ 225 function _reset() 226 { 227 $this->_executed = false; 228 $this->count = -1; 229 $this->denied = 0; 230 } 231 232 /** 233 * Runs a query where <i>limit and offset is taken into account prior to 234 * execution in the core.</i> 235 * 236 * This is useful in cases where you can safely assume read privileges on all 237 * objects, and where you would otherwise have to deal with huge resultsets. 238 * 239 * Be aware that this might lead to empty resultsets "in the middle" of the 240 * actual full resultset when read privileges are missing. 241 * 242 * @see list_keys() 243 */ 242 244 function list_keys_unchecked() 243 245 { 244 return $this->_mc->list_keys(); 245 } 246 246 $this->_reset(); 247 // Add the limit / offsets 248 if ($this->_limit) 249 { 250 $this->_mc->set_limit($this->_limit); 251 } 252 if ($this->_offset) 253 { 254 $this->_mc->set_offset($this->_offset); 255 } 256 257 $newresult = $this->_list_keys_and_check_privileges(); 258 259 if (!is_array($newresult)) 260 { 261 return $newresult; 262 } 263 264 call_user_func_array(array($this->_real_class, '_on_process_collector_result'), array(&$newresult)); 265 266 $this->count = count($newresult); 267 268 debug_pop(); 269 return $newresult; 270 } 271 272 function _list_keys_and_check_privileges() 273 { 274 $this->_real_execute(); 275 $result = $this->_mc->list_keys(); 276 if (!is_array($result)) 277 { 278 return $result; 279 } 280 $newresult = array(); 281 $classname = $this->_real_class; 282 foreach ($result as $object_guid => $empty_copy) 283 { 284 if (!$_MIDCOM->auth->can_do_byguid('midgard:read', $object_guid, $classname)) 285 { 286 debug_add("Failed to load result, read privilege on {$object_guid} not granted for the current user.", MIDCOM_LOG_INFO); 287 $this->denied++; 288 continue; 289 } 290 291 // Check visibility 292 if ($this->hide_invisible) 293 { 294 // TODO: Implement 295 } 296 297 $newresult[$object_guid] = array(); 298 } 299 return $newresult; 300 } 301 302 /** 303 * implements midgard_collector::list_keys with ACL and visibility checking 304 * 305 * @todo implement visibility checking 306 */ 247 307 function list_keys() 248 308 { 249 $result = $this->_mc->list_keys(); 309 /** 310 * PONDER: Should we implement the moving window limit/offset handling here as well ? 311 * probably it's not worth the effort since we're not actually instantiating objects 312 * so many of the inefficencies related to that are avoided. 313 * @see midcom_core_querybuilder::execute_windowed 314 */ 315 $this->_reset(); 316 $result = $this->_list_keys_and_check_privileges(); 317 if (!is_array($result)) 318 { 319 return $result; 320 } 250 321 $newresult = array(); 251 252 if (!$result) 253 { 254 return $newresult; 255 } 256 257 // Workaround until the QB returns the correct type, refetch everything 258 $classname = $this->_real_class; 322 259 323 $limit = $this->_limit; 260 324 $offset = $this->_offset; 261 $skipped_objects = 0; 262 $this->denied = 0; 325 $classname = $this->_real_class; 263 326 foreach ($result as $object_guid => $empty_copy) 264 327 { 328 // We have hit our limit 265 329 if ( $this->_limit > 0 266 330 && $limit == 0) 267 331 { 268 $skipped_objects++; 269 continue; 332 break; 270 333 } 271 334 … … 274 337 debug_add("Failed to load result, read privilege on {$object_guid} not granted for the current user.", MIDCOM_LOG_INFO); 275 338 $this->denied++; 276 $skipped_objects++;277 339 continue; 278 340 } … … 292 354 } 293 355 294 $newresult[$object_guid] = array();356 $newresult[$object_guid] = $empty_copy; 295 357 296 358 if ($this->_limit > 0) … … 302 364 call_user_func_array(array($this->_real_class, '_on_process_collector_result'), array(&$newresult)); 303 365 304 /* This must some QB copy-paste leftover305 // correct record count by the number of limit-skipped objects.306 $this->count = count($newresult) + $skipped_objects;307 */308 366 $this->count = count($newresult); 309 367 310 debug_pop();311 368 return $newresult; 312 369 } … … 350 407 function add_constraint($field, $operator, $value) 351 408 { 409 $this->_reset(); 352 410 // Add check against null values, Core QB is too stupid to get this right. 353 411 if ($value === null) … … 381 439 function add_order($field, $ordering = null) 382 440 { 441 /** 442 * NOTE: So see also querybuilder.php when making changes here 443 */ 383 444 if (empty($field)) 384 445 { … … 396 457 if ($ordering === null) 397 458 { 398 $result = $this->_mc->add_order($field); 459 if (substr($field, 0, 8) == 'reverse ') 460 { 461 $result = $this->_mc->add_order(substr($field, 8), 'DESC'); 462 } 463 else 464 { 465 $result = $this->_mc->add_order($field); 466 } 399 467 } 400 468 else … … 446 514 * @param int $count The maximum number of records in the resultset. 447 515 */ 448 function set_limit($count) 449 { 450 $this->_limit = $count; 516 function set_limit($limit) 517 { 518 $this->_reset(); 519 $this->_limit = $limit; 451 520 } 452 521 … … 463 532 function set_offset($offset) 464 533 { 534 $this->_reset(); 465 535 $this->_offset = $offset; 466 536 } … … 475 545 function set_lang($language) 476 546 { 547 $this->_reset(); 477 548 $this->_mc->set_lang($language); 478 549 } … … 495 566 * Returns the number of elements matching the current query. 496 567 * 497 * <i>Developer's note:</i> According to the Midgard core documentation, the count method 498 * does <b>not</b> execute the query using some COUNT() SQL statement. It merely returns 499 * the number of records found and is, thus, mostly useless as you can just count($result) 500 * on the PHP level anyway. 501 * 502 * To match the original inteded behavoir, the class will automatically execute the given 503 * query if it has not yet been executed, thus breaking full API compatibility to the Midgard 504 * core deliberatly on this point. 505 * 506 * Therefore, it is currently <i>strongly discouraged</i> to assume midgard_collector::count 507 * to be useful as-is. See http://midgard.tigris.org/issues/show_bug.cgi?id=56 for details. 568 * Due to ACL checking we must first execute the full query 508 569 * 509 570 * @return int The number of records found by the last query. … … 513 574 if ($this->count == -1) 514 575 { 515 $this->execute(); 516 // TODO: ACL check 576 if (!$this->_executed) 577 { 578 $this->execute(); 579 } 580 $this->list_keys(); 517 581 } 518 582 return $this->count; … … 528 592 * mind might nevertheless be able to take advantage of it. 529 593 * 530 * @return int The number of records matching the last query without taking access controlinto account.594 * @return int The number of records matching the constraints without taking access control or visibility into account. 531 595 */ 532 596 function count_unchecked() 533 597 { 598 $this->_reset(); 599 if ($this->_limit) 600 { 601 $this->_mc->set_limit($this->_limit); 602 } 603 if ($this->_offset) 604 { 605 $this->_mc->set_offset($this->_offset); 606 } 534 607 return $this->_mc->count(); 535 608 } 536 609 } 537 610 538 539 611 ?> trunk/midcom/midcom.core/midcom/core/querybuilder.php
r11906 r11915 591 591 $limit = $this->_limit; 592 592 $offset = $this->_offset; 593 $skipped_objects = 0;594 593 $this->denied = 0; 595 594 … … 599 598 && $limit == 0) 600 599 { 601 $skipped_objects++; 602 continue; 600 break; 603 601 } 604 602 … … 627 625 628 626 /** 629 * Temporary helper until execute can be optimized with rerunnable QBs, 630 * runs a query where <i>limit and offset is taken into account prior to 627 * Runs a query where <i>limit and offset is taken into account prior to 631 628 * execution in the core.</i> 632 629 * … … 733 730 function add_order($field, $ordering = null) 734 731 { 732 /** 733 * NOTE: So see also collector.php when making changes here 734 */ 735 735 if (! $field) 736 736 { … … 854 854 * Returns the number of elements matching the current query. 855 855 * 856 * Due to ACL checking we must first execute the full query to get856 * Due to ACL checking we must first execute the full query 857 857 * 858 858 * @return int The number of records found by the last query. … … 891 891 } 892 892 } 893 893 894 ?>
