Commit 80a7c793c49d55cd2cf8f62ea2d5b749d17126d3

Authored by Megan Watson
1 parent ac7fc794

Pivotal Tracker: 676448 Refactored getList() to use loadFromArray() instead of r…

…epeatedly hitting the database using get().

Committed by: Megan Watson
Showing 1 changed file with 120 additions and 173 deletions
lib/ktentity.inc
@@ -333,6 +333,7 @@ class KTEntity { @@ -333,6 +333,7 @@ class KTEntity {
333 } 333 }
334 334
335 $array = array_keys($this->_aFieldToSelect); 335 $array = array_keys($this->_aFieldToSelect);
  336 + $array2 = array_flip($this->_aFieldToSelect);
336 337
337 if (!$aCache) { 338 if (!$aCache) {
338 $case = array(); 339 $case = array();
@@ -342,6 +343,9 @@ class KTEntity { @@ -342,6 +343,9 @@ class KTEntity {
342 foreach($case as $k => $v) { 343 foreach($case as $k => $v) {
343 $case[substr($k, 1)] = $v; 344 $case[substr($k, 1)] = $v;
344 } 345 }
  346 + foreach($array2 as $k => $v) {
  347 + $case[strtolower($k)] = $v;
  348 + }
345 } else { 349 } else {
346 $case = $aCache['fieldnames']; 350 $case = $aCache['fieldnames'];
347 } 351 }
@@ -406,200 +410,117 @@ class KTEntityUtil { @@ -406,200 +410,117 @@ class KTEntityUtil {
406 return KTEntityUtil::getList($sTable, $sClassName, $aWhereClause, $aOptions); 410 return KTEntityUtil::getList($sTable, $sClassName, $aWhereClause, $aOptions);
407 } 411 }
408 412
  413 + /**
  414 + * Core function for KTEntityUtil, gets a list of all the objects according to the given where clause
  415 + *
  416 + * @param string $sTable
  417 + * @param string $sClassName
  418 + * @param array|string $aWhereClause
  419 + * @param array $aOptions
  420 + * @return array
  421 + */
409 function &getList($sTable, $sClassName, $aWhereClause = null, $aOptions = null) { 422 function &getList($sTable, $sClassName, $aWhereClause = null, $aOptions = null) {
410 global $default; 423 global $default;
  424 +
  425 + // Force the where clause to be an array
  426 + if (!is_array($aWhereClause)) {
  427 + $aWhereClause = array($aWhereClause, array());
  428 + }
  429 +
  430 + // Force the options to be an array
411 if (is_null($aOptions)) { 431 if (is_null($aOptions)) {
412 $aOptions = array(); 432 $aOptions = array();
413 } 433 }
414 434
  435 + // Merge in the standard options for the class
415 $aBaseOpts = call_user_func(array($sClassName, "_ktentityOptions")); 436 $aBaseOpts = call_user_func(array($sClassName, "_ktentityOptions"));
416 - $aOptions = KTUtil::meldOptions($aBaseOpts, $aOptions);  
417 -  
418 - $bIDs = false;  
419 - $bIDs = KTUtil::arrayGet($aOptions, "ids", false);  
420 - $sIDField = 'id';  
421 - $cache = KTUtil::arrayGet($aOptions, 'cache', false);  
422 -  
423 - if (!is_array($aWhereClause)) {  
424 - $aWhereClause = array($aWhereClause, array()); 437 + if(!is_array($aBaseOpts)){
  438 + $aBaseOpts = array();
425 } 439 }
  440 + $aOptions = array_merge($aBaseOpts, $aOptions);
426 441
  442 + /* *** Check for all option values *** */
427 443
428 - if (!$cache) { // && EVIL_CACHE_GRIND) {  
429 - $cache = 'auto';  
430 - } 444 + // Check if only the id's have been requested
  445 + $bIDs = isset($aOptions['ids']) ? $aOptions['ids'] : false;
431 446
432 - if (isset($GLOBALS['_STOPCACHING'][$sClassName])) {  
433 - if ($GLOBALS['_STOPCACHING'][$sClassName] > 5) {  
434 - $cache = false;  
435 - }  
436 - } 447 + // Check if the id field differs from the standard
  448 + $sIDField = isset($aOptions['idfield']) ? $aOptions['idfield'] : 'id';
437 449
438 - if (isset($aOptions['orderby'])) {  
439 - $sOrderBy = $aOptions['orderby'];  
440 - if (!empty($aWhereClause[0])) {  
441 - $aWhereClause[0] .= " ORDER BY " . $sOrderBy;  
442 - } else {  
443 - $aWhereClause[0] = "ORDER BY " . $sOrderBy;  
444 - }  
445 - } 450 + // Check for an order by clause
  451 + $sOrderBy = isset($aOptions['orderby']) ? $aOptions['orderby'] : false;
446 452
447 - $sIDField = KTUtil::arrayGet($aOptions, "idfield", 'id');  
448 - $aWhereClause[2] = $sIDField; 453 + // Check for a limit and offset
  454 + $iLimit = isset($aOptions['limit']) ? $aOptions['limit'] : false;
  455 + $iOffset = isset($aOptions['offset']) ? $aOptions['offset'] : false;
449 456
450 - if (isset($aOptions['limit'])) {  
451 - if (isset($aOptions['offset'])) {  
452 - $iOffset = $aOptions['offset'];  
453 - } else {  
454 - $iOffset = 0;  
455 - }  
456 - $iLimit = $aOptions['limit']; 457 + // Check for the cache value
  458 + $cache = isset($aOptions['cache']) ? $aOptions['cache'] : 'getlist';
457 459
458 - if ($iOffset) {  
459 - $aWhereClause[0] .= " LIMIT $iOffset, $iLimit";  
460 - } else {  
461 - $aWhereClause[0] .= " LIMIT $iLimit";  
462 - } 460 + /* *** Construct the query *** */
  461 +
  462 + $sQuery = '';
  463 + if($bIDs !== false){
  464 + $sQuery = "SELECT $sIDField FROM $sTable";
  465 + }else{
  466 + $oObject = new $sClassName;
  467 + $select = $oObject->_getSqlSelection();
  468 + $sQuery = "SELECT {$select} FROM $sTable";
463 } 469 }
464 470
465 - $fullselect = KTUtil::arrayGet($aOptions, 'fullselect', false); 471 + // Append the where clause
  472 + $sWhere = '';
  473 + $aParams = array();
  474 + if(isset($aWhereClause[0]) && !empty($aWhereClause[0])){
  475 + // check whether the WHERE or ORDER has already been included in the query string
  476 + $check = substr($aWhereClause[0], 0, 5);
466 477
467 - if ($cache) {  
468 - if ($cache === 'auto') {  
469 - $vals = serialize($aWhereClause);  
470 - } else if (is_array($aWhereClause)) {  
471 - $vals = serialize($aWhereClause[1]);  
472 - } else {  
473 - $vals = serialize($aWhereClause); 478 + if($check != 'WHERE' && $check != 'ORDER'){
  479 + $sWhere = 'WHERE ';
474 } 480 }
475 - if (KTLOG_CACHE) $default->log->debug(sprintf("Trying list cache for class %s, %s: %s", $sClassName, $cache, $vals)); 481 + $sWhere .= $aWhereClause[0];
  482 + $aParams = isset($aWhereClause[1]) && !empty($aWhereClause[1]) ? $aWhereClause[1] : array();
476 483
477 - $oCache =& KTCache::getSingleton();  
478 - $suffix = '';  
479 - if ($fullselect) {  
480 - $suffix = '_fullselect';  
481 - }  
482 - $group = sprintf("%s/%s%s", $sClassName, $cache, $suffix);  
483 - list($bCached, $mCached) = $oCache->get($group, $vals);  
484 - } else {  
485 - $bCached = false; 484 + $sQuery .= " $sWhere";
486 } 485 }
487 486
488 - if ($cache && !$bCached) {  
489 - global $default;  
490 - if (KTLOG_CACHE) $default->log->debug(sprintf("No list cache for class %s, %s: %s", $sClassName, $cache, $vals)); 487 + // Append the order by
  488 + if($sOrderBy != false){
  489 + $sQuery .= " ORDER BY $sOrderBy";
491 } 490 }
492 - if ($bCached && EVIL_CACHE_GRIND) {  
493 - if (!empty($fullselect)) {  
494 - $oObject = new $sClassName;  
495 - $select = $oObject->_getSqlSelection();  
496 - $sQuery = "SELECT $select FROM " . $sTable;/*ok*/  
497 - } else {  
498 - $sIDField = KTUtil::arrayGet($aOptions, "idfield", 'id');  
499 - $sQuery = "SELECT $sIDField FROM " . $sTable;/*ok*/  
500 - }  
501 - $aParams = array();  
502 - if (!empty($aWhereClause[0])) {  
503 - if (is_string($aWhereClause)) {  
504 - if (substr($aWhereClause, 0, 5) != 'WHERE') {  
505 - if (substr($aWhereClause, 0, 5) != 'ORDER') {  
506 - $sQuery .= ' WHERE';  
507 - }  
508 - }  
509 - $sQuery .= ' ' . $aWhereClause;  
510 - } else if (is_array($aWhereClause)) {  
511 - if (substr($aWhereClause[0], 0, 5) != 'WHERE') {  
512 - if (substr($aWhereClause[0], 0, 5) != 'ORDER') {  
513 - $sQuery .= ' WHERE';  
514 - }  
515 - }  
516 - $sQuery .= ' ' . $aWhereClause[0];  
517 - $aParams = $aWhereClause[1];  
518 - } else {  
519 - return new PEAR_Error('Weird WhereClause passed');  
520 - }  
521 - }  
522 491
523 - if (!empty($fullselect)) {  
524 - $aIDs = DBUtil::getResultArray(array($sQuery, $aParams));  
525 - } else {  
526 - $aIDs = DBUtil::getResultArrayKey(array($sQuery, $aParams), $sIDField); 492 + // Append a limit and offset
  493 + if($iLimit != false){
  494 + $sLimit = '';
  495 + if($iOffset != false){
  496 + $sLimit .= "$iOffset, ";
527 } 497 }
528 - // compare mcached == $aIds 498 + $sLimit .= $iLimit;
529 499
530 - if ($aIDs != $mCached) {  
531 - /*  
532 - print "==================\n\n\n\n\n";  
533 - var_dump($aIDs);  
534 - print "------\n";  
535 - var_dump($mCached);  
536 - */  
537 - $oCache->alertFailure($group, array('Stored IDS != Cache IDS'));  
538 - }  
539 - } else if ($bCached) {  
540 - if (KTLOG_CACHE) $default->log->debug(sprintf("Using object cache for class %s, %s: %s", $sClassName, $cache, $vals));  
541 - $aIDs = $mCached;  
542 - /* */  
543 - } else {  
544 - if (!empty($fullselect)) {  
545 - $oObject = new $sClassName;  
546 - $select = $oObject->_getSqlSelection();  
547 - $sQuery = "SELECT $select FROM " . $sTable;/*ok*/  
548 - } else {  
549 - $sIDField = KTUtil::arrayGet($aOptions, "idfield", 'id');  
550 - $sQuery = "SELECT $sIDField FROM " . $sTable;/*ok*/  
551 - }  
552 - $aParams = array();  
553 - if (!is_null($aWhereClause[0])) {  
554 - if (is_string($aWhereClause)) {  
555 - if (substr($aWhereClause, 0, 5) != 'WHERE') {  
556 - if (substr($aWhereClause, 0, 5) != 'ORDER') {  
557 - $sQuery .= ' WHERE';  
558 - }  
559 - }  
560 - $sQuery .= ' ' . $aWhereClause;  
561 - } else if (is_array($aWhereClause)) {  
562 - if (substr($aWhereClause[0], 0, 5) != 'WHERE') {  
563 - if (substr($aWhereClause[0], 0, 5) != 'ORDER') {  
564 - $sQuery .= ' WHERE';  
565 - }  
566 - }  
567 - $sQuery .= ' ' . $aWhereClause[0];  
568 - $aParams = $aWhereClause[1];  
569 - } else {  
570 - return new PEAR_Error('Weird WhereClause passed');  
571 - }  
572 - }  
573 -  
574 - if (!empty($fullselect)) {  
575 - $aIDs = DBUtil::getResultArray(array($sQuery, $aParams));  
576 - } else {  
577 - $aIDs = DBUtil::getResultArrayKey(array($sQuery, $aParams), $sIDField);  
578 - } 500 + $sQuery .= " LIMIT $sLimit";
579 } 501 }
580 502
581 - if (PEAR::isError($aIDs)) {  
582 - return $aIDs;  
583 - } 503 + /* *** Check the cache *** */
  504 +
  505 + $oCache = KTCache::getSingleton();
  506 + $vals = serialize(array($sQuery, $aParams));
  507 + $group = $sClassName.'/'.$cache;
  508 +
  509 + list($bCached, $mCached) = $oCache->get($group, $vals);
584 510
585 - if ($cache && !$bCached) {  
586 - if (KTLOG_CACHE) $default->log->debug(sprintf("Setting object cache for class %s, %s, %s", $sClassName, $cache, $vals));  
587 - $oCache->set($group, $vals, $aIDs);  
588 - }  
589 511
590 - if ($bIDs === true) { 512 + /* *** Execute the query *** */
  513 +
  514 + // If only id's are requested, return them
  515 + if($bIDs){
  516 + $aIDs = DBUtil::getResultArrayKey(array($sQuery, $aParams), $sIDField);
591 return $aIDs; 517 return $aIDs;
592 } 518 }
593 519
594 - if (!empty($fullselect)) {  
595 - $aRet =& KTEntityUtil::loadFromArrayMulti($sClassName, $aIDs);  
596 - return $aRet;  
597 - }  
598 - $aRet = array();  
599 - foreach ($aIDs as $iId) {  
600 - $aRet[] = call_user_func(array($sClassName, 'get'), $iId);  
601 - }  
602 - return $aRet; 520 + // Get the object data and load into objects
  521 + $results = DBUtil::getResultArray(array($sQuery, $aParams));
  522 + $aObjects = KTEntityUtil::loadFromArrayMulti($sClassName, $results);
  523 + return $aObjects;
603 } 524 }
604 525
605 function &createFromArray ($sClassName, $aOptions) { 526 function &createFromArray ($sClassName, $aOptions) {
@@ -650,7 +571,25 @@ class KTEntityUtil { @@ -650,7 +571,25 @@ class KTEntityUtil {
650 571
651 function &loadFromArrayMulti($sClassName, $aMultiArray, $aOptions = null) { 572 function &loadFromArrayMulti($sClassName, $aMultiArray, $aOptions = null) {
652 $aRet = array(); 573 $aRet = array();
  574 + $config =& KTConfig::getSingleton();
  575 + //$useProxy = $config->get('cache/proxyCacheEnabled');
653 foreach ($aMultiArray as $aArray) { 576 foreach ($aMultiArray as $aArray) {
  577 +
  578 + //if($useProxy){
  579 + $iId = (int)$aArray['id'];
  580 + if(empty($iId)){
  581 + $iId = null;
  582 + }
  583 + $sProxyClass = KTEntityUtil::_getProxyClass($sClassName);
  584 + $oObject =new $sProxyClass($iId, $aArray);
  585 + $res = $oObject->getId();
  586 + if (PEAR::isError($res)) {
  587 + return $res;
  588 + }
  589 + $aRet[] = $oObject;
  590 + continue;
  591 + //}
  592 +
654 $oObject =new $sClassName; 593 $oObject =new $sClassName;
655 $ret = $oObject->loadFromArray($aArray); 594 $ret = $oObject->loadFromArray($aArray);
656 if (PEAR::isError($ret)) { 595 if (PEAR::isError($ret)) {
@@ -666,15 +605,17 @@ class KTEntityUtil { @@ -666,15 +605,17 @@ class KTEntityUtil {
666 return PEAR::raiseError(_kt('Non-numeric identifier')); 605 return PEAR::raiseError(_kt('Non-numeric identifier'));
667 } 606 }
668 $iId = (int)$iId; 607 $iId = (int)$iId;
669 - /* */  
670 - $sProxyClass = KTEntityUtil::_getProxyClass($sClassName);  
671 - $oObject =new $sProxyClass($iId);  
672 - $res = $oObject->getId();  
673 - if (PEAR::isError($res)) {  
674 - return $res;  
675 - }  
676 - return $oObject;  
677 - /* */ 608 + // Use a proxy class if enabled
  609 + $config =& KTConfig::getSingleton();
  610 + //if($config->get('cache/proxyCacheEnabled')){
  611 + $sProxyClass = KTEntityUtil::_getProxyClass($sClassName);
  612 + $oObject =new $sProxyClass($iId);
  613 + $res = $oObject->getId();
  614 + if (PEAR::isError($res)) {
  615 + return $res;
  616 + }
  617 + return $oObject;
  618 + //}
678 // XXX Object cache currently causes hard-to-trace inconsistencies in data. 619 // XXX Object cache currently causes hard-to-trace inconsistencies in data.
679 // $oObject =& KTUtil::arrayGet($GLOBALS['_OBJECTCACHE'][$sClassName], $iId); 620 // $oObject =& KTUtil::arrayGet($GLOBALS['_OBJECTCACHE'][$sClassName], $iId);
680 // if ($oObject) { return $oObject; } 621 // if ($oObject) { return $oObject; }
@@ -736,11 +677,13 @@ class KTEntityUtil { @@ -736,11 +677,13 @@ class KTEntityUtil {
736 } 677 }
737 eval($code); 678 eval($code);
738 } 679 }
  680 +
739 function _proxyBuild($sClassName, $sProxyClassName) { 681 function _proxyBuild($sClassName, $sProxyClassName) {
740 // var_dump("Building proxy for $sClassName"); 682 // var_dump("Building proxy for $sClassName");
741 $methods = get_class_methods($sClassName); 683 $methods = get_class_methods($sClassName);
742 $allcode = array(); 684 $allcode = array();
743 $allcode[] = sprintf('var $cacheGlobal = null;%s', "\n"); 685 $allcode[] = sprintf('var $cacheGlobal = null;%s', "\n");
  686 + $allcode[] = sprintf('var $aFieldArr = null;%s', "\n");
744 687
745 foreach ($methods as $sMethod) { 688 foreach ($methods as $sMethod) {
746 if(substr($sMethod, 0, 2) == '__') { 689 if(substr($sMethod, 0, 2) == '__') {
@@ -765,13 +708,17 @@ class KTEntityUtil { @@ -765,13 +708,17 @@ class KTEntityUtil {
765 return $oObject; 708 return $oObject;
766 } 709 }
767 $oObject =new %s; 710 $oObject =new %s;
768 - $res = $oObject->load($this->iId); 711 + if(!empty($this->aFieldArr)){
  712 + $res = $oObject->loadFromArray($this->aFieldArr);
  713 + }else{
  714 + $res = $oObject->load($this->iId);
  715 + }
769 if (PEAR::isError($res)) { 716 if (PEAR::isError($res)) {
770 return $res; 717 return $res;
771 } 718 }
772 $this->cacheGlobal[$this->iId] =& $oObject; 719 $this->cacheGlobal[$this->iId] =& $oObject;
773 return $oObject; 720 return $oObject;
774 - }', $sClassName, $sClassName, $sClassName, $sClassName); 721 + }', $sClassName, $sClassName, $sClassName, $sClassName, $sClassName);
775 722
776 $allcode[] = sprintf('function _save(&$oObject) { 723 $allcode[] = sprintf('function _save(&$oObject) {
777 $this->cacheGlobal[$this->iId] =& $oObject; 724 $this->cacheGlobal[$this->iId] =& $oObject;
@@ -802,7 +749,7 @@ class KTEntityUtil { @@ -802,7 +749,7 @@ class KTEntityUtil {
802 /* */ 749 /* */
803 }'; 750 }';
804 751
805 - $allcode[] = sprintf('function %s ($iId) { $this->iId = $iId; $this->cacheGlobal =& $GLOBALS["_OBJECTCACHE"][%s]; }' . "\n", $sProxyClassName, $sClassName); 752 + $allcode[] = sprintf('function %s ($iId, $aInfo = null) { $this->iId = $iId; $this->aFieldArr = $aInfo; $this->cacheGlobal =& $GLOBALS["_OBJECTCACHE"][%s]; }' . "\n", $sProxyClassName, $sClassName);
806 753
807 $gen = sprintf("class %s extends %s {\n", $sProxyClassName, $sClassName); 754 $gen = sprintf("class %s extends %s {\n", $sProxyClassName, $sClassName);
808 $gen .= " " . join("\n ", $allcode) . "\n"; 755 $gen .= " " . join("\n ", $allcode) . "\n";