00001 <?PHP 00002 00003 # 00004 # FILE: SPT--SPTOAIServer.php 00005 # 00006 # METHODS PROVIDED: 00007 # SPTOAIServer() 00008 # - constructor 00009 # 00010 # AUTHOR: Edward Almasy 00011 # 00012 # Part of the Scout Portal Toolkit 00013 # Copyright 2002-2004 Internet Scout Project 00014 # http://scout.wisc.edu 00015 # 00016 00017 class SPTOAIServer extends OAIServer { 00018 00019 # ---- PUBLIC INTERFACE -------------------------------------------------- 00020 00021 function SPTOAIServer($RetrievalSearchParameters = NULL) 00022 { 00023 global $SysConfig; 00024 00025 # grab our own database handle 00026 $this->DB = new SPTDatabase(); 00027 $DB =& $this->DB; 00028 00029 # set up repository description 00030 $DB->Query("SELECT * FROM SystemConfiguration"); 00031 $Record = $DB->FetchRow(); 00032 $RepDescr["Name"] = $SysConfig->PortalName(); 00033 $ServerName = ($_SERVER["SERVER_NAME"] != "127.0.0.1") 00034 ? $_SERVER["SERVER_NAME"] 00035 : $_SERVER["HTTP_HOST"]; 00036 $RepDescr["BaseURL"] = "http://".$ServerName.$_SERVER["SCRIPT_NAME"]; 00037 $RepDescr["DateGranularity"] = "DATE"; 00038 $RepDescr["EarliestDate"] = $Record["OaiEarliestDate"]; 00039 $RepDescr["AdminEmail"][] = $SysConfig->AdminEmail(); 00040 $RepDescr["IDDomain"] = $Record["OaiIdDomain"]; 00041 $RepDescr["IDPrefix"] = $Record["OaiIdPrefix"]; 00042 00043 # create item factory object for retrieving items from DB 00044 $this->SPTItemFactory = new SPTOAIItemFactory($RetrievalSearchParameters); 00045 00046 # call parent's constructor 00047 $this->OAIServer($DB, $RepDescr, $this->SPTItemFactory, TRUE, $SysConfig->OAISQEnabled()); 00048 00049 # set up description of nsdl_dc format 00050 $NsdldcNamespaceList = array( 00051 "nsdl_dc" => "http://ns.nsdl.org/nsdl_dc_v1.01", 00052 "dc" => "http://purl.org/dc/elements/1.1/", 00053 "dct" => "http://purl.org/dc/terms/", 00054 "ieee" => "http://www.ieee.org/xsd/LOMv1p0", 00055 ); 00056 $NsdldcElements = array( 00057 "dc:title", 00058 "dc:creator", 00059 "dc:subject", 00060 "dc:description", 00061 "dc:publisher", 00062 "dc:contributor", 00063 "dc:date", 00064 "dc:type", 00065 "dc:format", 00066 "dc:identifier", 00067 "dc:source", 00068 "dc:language", 00069 "dc:relation", 00070 "dc:coverage", 00071 "dc:rights", 00072 "dct:audience", 00073 "dct:alternative", 00074 "dct:tableOfContents", 00075 "dct:abstract", 00076 "dct:created", 00077 "dct:valid", 00078 "dct:available", 00079 "dct:issued", 00080 "dct:modified", 00081 "dct:extent", 00082 "dct:medium", 00083 "dct:isVersionOf", 00084 "dct:hasVersion", 00085 "dct:isReplacedBy", 00086 "dct:replaces", 00087 "dct:isRequiredBy", 00088 "dct:requires", 00089 "dct:isPartOf", 00090 "dct:hasPart", 00091 "dct:isReferencedBy", 00092 "dct:references", 00093 "dct:isFormatOf", 00094 "dct:hasFormat", 00095 "dct:conformsTo", 00096 "dct:spatial", 00097 "dct:temporal", 00098 "dct:mediator", 00099 "dct:dateAccepted", 00100 "dct:dateCopyrighted", 00101 "dct:dateSubmitted", 00102 "dct:educationLevel", 00103 "dct:accessRights", 00104 "dct:bibliographicCitation", 00105 "ieee:interactivityType", 00106 "ieee:interactivityLevel", 00107 "ieee:typicalLearningTime", 00108 ); 00109 $NsdldcQualifiers = array( 00110 "dct:LCSH", 00111 "dct:MESH", 00112 "dct:DDC", 00113 "dct:LCC", 00114 "dct:UDC", 00115 "dct:DCMIType", 00116 "dct:IMT", 00117 "dct:ISO639-2", 00118 "dct:RFC1766", 00119 "dct:URI", 00120 "dct:Point", 00121 "dct:ISO3166", 00122 "dct:Box", 00123 "dct:TGN", 00124 "dct:Period", 00125 "dct:W3CDTF", 00126 "dct:RFC3066", 00127 ); 00128 $this->AddFormat("nsdl_dc", "nsdl_dc:nsdl_dc", 00129 "http://ns.nsdl.org/nsdl_dc_v1.01" 00130 ." http://ns.nsdl.org/schemas/nsdl_dc/nsdl_dc_v1.01.xsd", 00131 "1.01.001", 00132 $NsdldcNamespaceList, $NsdldcElements, $NsdldcQualifiers); 00133 00134 # load field mappings from database and set in parent 00135 $Schema = new MetadataSchema(); 00136 $DB->Query("SELECT * FROM OAIFieldMappings"); 00137 while ($Record = $DB->FetchRow()) 00138 { 00139 if ($Record["OAIFieldName"] != "Unmapped") 00140 { 00141 parent::SetFieldMapping($Record["FormatName"], 00142 $Record["SPTFieldId"], 00143 $Record["OAIFieldName"]); 00144 } 00145 } 00146 00147 # load qualifier mappings from database and set in parent 00148 $DB->Query("SELECT * FROM OAIQualifierMappings"); 00149 while ($Record = $DB->FetchRow()) 00150 { 00151 if ($Record["OAIQualifierName"] != "Unmapped") 00152 { 00153 $LocalQualifier = new Qualifier($Record["SPTQualifierId"]); 00154 $LocalQualifierName = $LocalQualifier->Name(); 00155 parent::SetQualifierMapping($Record["FormatName"], 00156 $LocalQualifierName, 00157 $Record["OAIQualifierName"]); 00158 } 00159 } 00160 } 00161 00162 # add SQL conditional for selecting resources 00163 function AddSQLConditionalForResources($Conditional) 00164 { 00165 # pass conditional on to item factory 00166 $this->SPTItemFactory->AddSQLConditionalForResources($Conditional); 00167 } 00168 00169 # get/set mapping of local field to OAI field (overloads parent method) 00170 function GetFieldMapping($FormatName, $LocalFieldName) 00171 { 00172 # retrieve ID for local field 00173 $Schema = new MetadataSchema(); 00174 $LocalField = $Schema->GetFieldByName($LocalFieldName); 00175 $LocalFieldId = $LocalField->Id(); 00176 00177 # return stored value 00178 return parent::GetFieldMapping($FormatName, $LocalFieldId); 00179 } 00180 function SetFieldMapping($FormatName, $LocalFieldName, $OAIFieldName) 00181 { 00182 # retrieve ID for local field 00183 $Schema = new MetadataSchema(); 00184 $LocalField = $Schema->GetFieldByName($LocalFieldName); 00185 $LocalFieldId = $LocalField->Id(); 00186 00187 # check whether mapping is already in database 00188 $DB =& $this->DB; 00189 $MapCount = $DB->Query("SELECT COUNT(*) AS MapCount FROM OAIFieldMappings" 00190 ." WHERE FormatName = '".$FormatName."'" 00191 ." AND SPTFieldId = '".$LocalFieldId."'", 00192 "MapCount"); 00193 00194 # if mapping is already in database 00195 if ($MapCount > 0) 00196 { 00197 # change mapping in database 00198 $DB->Query("UPDATE OAIFieldMappings" 00199 ." SET OAIFieldName = '".addslashes($OAIFieldName)."'" 00200 ." WHERE FormatName = '".addslashes($FormatName)."'" 00201 ." AND SPTFieldId = '".$LocalFieldId."'"); 00202 } 00203 else 00204 { 00205 # add new mapping to database 00206 $DB->Query("INSERT INTO OAIFieldMappings" 00207 ." (FormatName, SPTFieldId, OAIFieldName) VALUES" 00208 ." ('".addslashes($FormatName)."', '".$LocalFieldId 00209 ."', '".addslashes($OAIFieldName)."')"); 00210 } 00211 00212 # call parent method 00213 parent::SetFieldMapping($FormatName, $LocalFieldId, $OAIFieldName); 00214 } 00215 00216 # set mapping of local qualifier to OAI qualifier (overloads parent method) 00217 function SetQualifierMapping($FormatName, $LocalQualifierName, $OAIQualifierName) 00218 { 00219 # retrieve ID for local qualifier 00220 $QFactory = new QualifierFactory(); 00221 $LocalQualifier = $QFactory->GetQualifierByName($LocalQualifierName); 00222 $LocalQualifierId = $LocalQualifier->Id(); 00223 00224 # check whether mapping is already in database 00225 $DB =& $this->DB; 00226 $MapCount = $DB->Query("SELECT COUNT(*) AS MapCount FROM OAIQualifierMappings" 00227 ." WHERE FormatName = '".addslashes($FormatName)."'" 00228 ." AND SPTQualifierId = '".$LocalQualifierId."'", 00229 "MapCount"); 00230 00231 # if mapping is already in database 00232 if ($MapCount > 0) 00233 { 00234 # change mapping in database 00235 $DB->Query("UPDATE OAIQualifierMappings" 00236 ." SET OAIQualifierName = '".addslashes($OAIQualifierName)."'" 00237 ." WHERE FormatName = '".addslashes($FormatName)."'" 00238 ." AND SPTQualifierId = '".$LocalQualifierId."'"); 00239 } 00240 else 00241 { 00242 # add new mapping to database 00243 $DB->Query("INSERT INTO OAIQualifierMappings" 00244 ." (FormatName, SPTQualifierId, OAIQualifierName) VALUES" 00245 ." ('".addslashes($FormatName)."', '".$LocalQualifierId 00246 ."', '".addslashes($OAIQualifierName)."')"); 00247 } 00248 00249 # call parent method 00250 parent::SetQualifierMapping($FormatName, $LocalQualifierName, $OAIQualifierName); 00251 } 00252 00253 00254 # ---- PRIVATE INTERFACE ------------------------------------------------- 00255 00256 var $DB; 00257 var $SPTItemFactory; 00258 00259 } 00260 00261 class SPTOAIItemFactory extends OAIItemFactory { 00262 00263 # ---- PUBLIC INTERFACE -------------------------------------------------- 00264 00265 # object constructor 00266 function SPTOAIItemFactory($RetrievalSearchParameters = NULL) 00267 { 00268 # save any supplied retrieval parameters 00269 $this->RetrievalSearchParameters = $RetrievalSearchParameters; 00270 } 00271 00272 function GetItem($ItemId) 00273 { 00274 # add link to full record page for item 00275 $ServerName = ($_SERVER["SERVER_NAME"] != "127.0.0.1") 00276 ? $_SERVER["SERVER_NAME"] 00277 : $_SERVER["HTTP_HOST"]; 00278 $SearchInfo["fullRecordLink"] = "http://".$ServerName.dirname($_SERVER["SCRIPT_NAME"])."/SPT--FullRecord.php?ResourceId=".$ItemId; 00279 00280 # if a search score is available for the item 00281 if (isset($this->SearchScores) && isset($this->SearchScores[$ItemId])) 00282 { 00283 # add search info for item 00284 $SearchInfo["searchScore"] = $this->SearchScores[$ItemId]; 00285 $SearchInfo["searchScoreScale"] = $this->SearchScoreScale; 00286 } 00287 00288 # attempt to create item 00289 $Item = new SPTOAIItem($ItemId, $SearchInfo); 00290 00291 # if item creation failed 00292 if ($Item->Status() == -1) 00293 { 00294 # return NULL to indicate that no item was found with that ID 00295 return NULL; 00296 } 00297 else 00298 { 00299 # return item to caller 00300 return $Item; 00301 } 00302 } 00303 00304 function GetItems($StartingDate = NULL, $EndingDate = NULL) 00305 { 00306 return $this->GetItemsInSet(NULL, $StartingDate, $EndingDate); 00307 } 00308 00309 function GetItemsInSet($Set, $StartingDate = NULL, $EndingDate = NULL) 00310 { 00311 # initialize search parameters with release flag requirement 00312 $SearchStrings["Release Flag"] = "=1"; 00313 00314 # if both begin and end date supplied 00315 if (($StartingDate != NULL) && ($EndingDate != NULL)) 00316 { 00317 # select resources created between starting and ending dates 00318 $SearchStrings["Date Of Record Creation"] = 00319 array(">=".$StartingDate, "<=".$EndingDate); 00320 } 00321 # else if begin date specified 00322 elseif ($StartingDate != NULL) 00323 { 00324 # select resources created after begin date 00325 $SearchStrings["Date Of Record Creation"] = ">=".$StartingDate; 00326 } 00327 # else if end date specified 00328 elseif ($EndingDate != NULL) 00329 { 00330 # select resources created after begin date 00331 $SearchStrings["Date Of Record Creation"] = "<=".$EndingDate; 00332 } 00333 00334 # if set specified 00335 if ($Set != NULL) 00336 { 00337 # load set mappings 00338 $this->LoadSetNameInfo(); 00339 00340 # if set is valid 00341 if (isset($this->SetFields[$Set])) 00342 { 00343 # add field spec to search strings 00344 $SearchStrings[$this->SetFields[$Set]] = "= ".$this->SetValues[$Set]; 00345 } 00346 else 00347 { 00348 # set will not match anything so return empty array to caller 00349 return array(); 00350 } 00351 } 00352 00353 # perform search for desired items 00354 $Engine = new SPTSearchEngine(); 00355 if ($this->RetrievalSearchParameters) 00356 { 00357 $SearchStrings = array_merge($SearchStrings, 00358 $this->RetrievalSearchParameters); 00359 } 00360 $SearchResults = $Engine->FieldedSearch($SearchStrings, 0, 1000000); 00361 00362 # extract resource IDs from search results 00363 $ItemIds = array_keys($SearchResults); 00364 00365 # return array of resource IDs to caller 00366 return $ItemIds; 00367 } 00368 00369 # return array containing all set specs (with human-readable set names as keys) 00370 function GetListOfSets() 00371 { 00372 # make sure set name info is loaded 00373 $this->LoadSetNameInfo(); 00374 00375 # return list of sets to caller 00376 return $this->SetSpecs; 00377 } 00378 00379 # retrieve IDs of items that match search parameters (only needed if OAI-SQ supported) 00380 function SearchForItems($SearchParams, $StartingDate = NULL, $EndingDate = NULL) 00381 { 00382 # translate field IDs into field names for search parameters 00383 $Schema = new MetadataSchema; 00384 foreach ($SearchParams as $FieldId => $Value) 00385 { 00386 if ($FieldId == "X-KEYWORD-X") 00387 { 00388 $SearchStrings["XXXKeywordXXX"] = $Value; 00389 } 00390 else 00391 { 00392 $Field = $Schema->GetField($FieldId); 00393 $SearchStrings[$Field->Name()] = $Value; 00394 } 00395 } 00396 00397 # add release flag requirement to search parameters 00398 $SearchStrings["Release Flag"] = "=1"; 00399 00400 # if both begin and end date supplied 00401 if (($StartingDate != NULL) && ($EndingDate != NULL)) 00402 { 00403 # select resources created between starting and ending dates 00404 $SearchStrings["Date Of Record Creation"] = 00405 array(">=".$StartingDate, "<=".$EndingDate); 00406 } 00407 # else if begin date specified 00408 elseif ($StartingDate != NULL) 00409 { 00410 # select resources created after begin date 00411 $SearchStrings["Date Of Record Creation"] = ">=".$StartingDate; 00412 } 00413 # else if end date specified 00414 elseif ($EndingDate != NULL) 00415 { 00416 # select resources created after begin date 00417 $SearchStrings["Date Of Record Creation"] = "<=".$EndingDate; 00418 } 00419 00420 # perform search for desired items 00421 $Engine = new SPTSearchEngine(); 00422 if ($this->RetrievalSearchParameters) 00423 { 00424 $SearchStrings = array_merge($SearchStrings, 00425 $this->RetrievalSearchParameters); 00426 } 00427 $SearchResults = $Engine->FieldedSearch($SearchStrings, 0, 1000000); 00428 00429 # save search scores 00430 $this->SearchScores = $SearchResults; 00431 $this->SearchScoreScale = $Engine->FieldedSearchWeightScale($SearchStrings); 00432 00433 # extract resource IDs from search results 00434 $ItemIds = array_keys($SearchResults); 00435 00436 # return array of resource IDs to caller 00437 return $ItemIds; 00438 } 00439 00440 00441 # ---- PRIVATE INTERFACE ------------------------------------------------- 00442 00443 var $SetSpecs; 00444 var $SetFields; 00445 var $SetValues; 00446 var $RetrievalSearchParameters; 00447 var $SearchScores; 00448 var $SearchScoreScale; 00449 00450 # normalize value for use as an OAI set spec 00451 function NormalizeForSetSpec($Name) 00452 { 00453 return preg_replace("/[^a-zA-Z0-9\-_.!~*'()]/", "", $Name); 00454 } 00455 00456 # load normalized set names and name mappings 00457 function LoadSetNameInfo() 00458 { 00459 # if set names have not already been loaded 00460 if (!isset($this->SetSpecs)) 00461 { 00462 # start with empty list of sets 00463 $this->SetSpecs = array(); 00464 $this->SetFields = array(); 00465 $this->SetValues = array(); 00466 00467 # for each metadata field that is a type that can be used for sets 00468 $Schema = new MetadataSchema(); 00469 $Fields = $Schema->GetFields(MetadataSchema::MDFTYPE_TREE|MetadataSchema::MDFTYPE_CONTROLLEDNAME|MetadataSchema::MDFTYPE_OPTION); 00470 foreach ($Fields as $Field) 00471 { 00472 # if field is flagged as being used for OAI sets 00473 if ($Field->UseForOaiSets()) 00474 { 00475 # retrieve all possible values for field 00476 $FieldValues = $Field->GetPossibleValues(); 00477 00478 # prepend field name to each value and add to list of sets 00479 $FieldName = $Field->Name(); 00480 $NormalizedFieldName = $this->NormalizeForSetSpec($FieldName); 00481 foreach ($FieldValues as $Value) 00482 { 00483 $SetSpec = $NormalizedFieldName.":" 00484 .$this->NormalizeForSetSpec($Value); 00485 $this->SetSpecs[$FieldName.": ".$Value] = $SetSpec; 00486 $this->SetFields[$SetSpec] = $FieldName; 00487 $this->SetValues[$SetSpec] = $Value; 00488 } 00489 } 00490 } 00491 } 00492 } 00493 } 00494 00495 class SPTOAIItem extends OAIItem { 00496 00497 # ---- PUBLIC INTERFACE -------------------------------------------------- 00498 00499 # object constructor 00500 function SPTOAIItem($ItemId, $SearchInfo = NULL) 00501 { 00502 # save ID for later use 00503 $this->Id = $ItemId; 00504 00505 # save any search info supplied 00506 $this->SearchInfo = $SearchInfo; 00507 00508 # attempt to create resource object 00509 $this->Resource = new Resource($ItemId); 00510 00511 # if resource object creation failed 00512 if ($this->Resource->Status() == -1) 00513 { 00514 # set status to -1 to indicate constructor failure 00515 $this->LastStatus = -1; 00516 } 00517 else 00518 { 00519 # set status to 1 to indicate constructor success 00520 $this->LastStatus = 1; 00521 00522 # if cumulative rating data is available for this resource 00523 global $SysConfig; 00524 if ($SysConfig->ResourceRatingsEnabled() 00525 && $this->Resource->CumulativeRating()) 00526 { 00527 # add cumulative rating data to search info 00528 $this->SearchInfo["cumulativeRating"] = 00529 $this->Resource->CumulativeRating(); 00530 $this->SearchInfo["cumulativeRatingScale"] = 100; 00531 } 00532 } 00533 } 00534 00535 function GetId() { return $this->Id; } 00536 00537 function GetDatestamp() 00538 { 00539 $DateString = $this->Resource->Get("Date Of Record Creation"); 00540 if ($DateString == "0000-00-00 00:00:00") { $DateString = date("Y-m-d"); } 00541 $Date = new SPTDate($DateString); 00542 return $Date->FormattedISO8601(); 00543 } 00544 00545 function GetValue($ElementName) 00546 { 00547 # retrieve value 00548 $ReturnValue = $this->Resource->GetByFieldId($ElementName); 00549 00550 # strip out any HTML tags if text value 00551 if (is_string($ReturnValue)) 00552 { 00553 $ReturnValue = strip_tags($ReturnValue); 00554 } 00555 00556 # format correctly if standardized date 00557 if ($this->GetQualifier($ElementName) == "W3C-DTF") 00558 { 00559 $Timestamp = strtotime($ReturnValue); 00560 $ReturnValue = date('Y-m-d\TH:i:s', $Timestamp) 00561 .substr_replace(date('O', $Timestamp), ':', 3, 0); 00562 } 00563 00564 # return value to caller 00565 return $ReturnValue; 00566 } 00567 00568 function GetQualifier($ElementName) 00569 { 00570 $ReturnValue = NULL; 00571 $Qualifier = $this->Resource->GetQualifierByFieldId($ElementName, TRUE); 00572 if (is_array($Qualifier)) 00573 { 00574 foreach ($Qualifier as $ItemId => $QualObj) 00575 { 00576 if (is_object($QualObj)) 00577 { 00578 $ReturnValue[$ItemId] = $QualObj->Name(); 00579 } 00580 } 00581 } 00582 else 00583 { 00584 if (isset($Qualifier) && is_object($Qualifier)) 00585 { 00586 $ReturnValue = $Qualifier->Name(); 00587 } 00588 } 00589 return $ReturnValue; 00590 } 00591 00592 function GetSets() 00593 { 00594 # start out with empty list 00595 $Sets = array(); 00596 00597 # for each possible metadata field 00598 $Schema = new MetadataSchema(); 00599 $Fields = $Schema->GetFields(MetadataSchema::MDFTYPE_TREE|MetadataSchema::MDFTYPE_CONTROLLEDNAME|MetadataSchema::MDFTYPE_OPTION); 00600 foreach ($Fields as $Field) 00601 { 00602 # if field is flagged for use for OAI sets 00603 if ($Field->UseForOaiSets()) 00604 { 00605 # retrieve values for resource for this field and add to set list 00606 $FieldName = $Field->Name(); 00607 $Values = $this->Resource->Get($FieldName); 00608 if (isset($Values) && ($Values != NULL)) 00609 { 00610 $NormalizedFieldName = $this->NormalizeForSetSpec($FieldName); 00611 if (is_array($Values) && count($Values)) 00612 { 00613 foreach ($Values as $Value) 00614 { 00615 $Sets[] = $NormalizedFieldName.":" 00616 .$this->NormalizeForSetSpec($Value); 00617 } 00618 } 00619 else 00620 { 00621 $Sets[] = $NormalizedFieldName.":" 00622 .$this->NormalizeForSetSpec($Values); 00623 } 00624 } 00625 } 00626 } 00627 00628 # return list of sets to caller 00629 return $Sets; 00630 } 00631 00632 function GetSearchInfo() 00633 { 00634 return $this->SearchInfo; 00635 } 00636 00637 function Status() 00638 { 00639 return $this->LastStatus; 00640 } 00641 00642 00643 # ---- PRIVATE INTERFACE ------------------------------------------------- 00644 00645 var $Id; 00646 var $Resource; 00647 var $LastStatus; 00648 var $SearchInfo; 00649 00650 # normalize value for use as an OAI set spec 00651 function NormalizeForSetSpec($Name) 00652 { 00653 return preg_replace("/[^a-zA-Z0-9\-_.!~*'()]/", "", $Name); 00654 } 00655 } 00656 00657 00658 ?>