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