public function write() { global $createNewRec, $result, $debug; // set up writer class instances $occ = new OmOccurrences(); // Note: We may create a new instance below. $det = new OmOccurDeterminations(); $imageHandler = new ImageShared(); $imageHandler->documentGuid = $this->containingDocument->guid; $imageHandler->documentDate = $this->containingDocument->date; // Special case handling of HUH double barcode errors $cc = $this->collectioncode; if ($cc == 'A' || $cc == 'GH' || $cc == 'FH' || $cc == 'AMES' || $cc == 'ECON' || $cc == 'NEVP') { // Known cases of sheets where a new barcode number was added in addition to an existing number for the sheet. // original existing number is the correct number. if ($this->catalognumber == '00447650') { $this->catalognumber = '00354371'; $this->occurrenceid = '4b11b05c-03f3-4f72-a917-a4a48fc2fb33'; } if ($this->catalognumber == '00447657') { $this->catalognumber = '00354391'; $this->occurrenceid = '96dc15ca-6224-4d63-9039-9633cafca7be'; } if ($this->catalognumber == '00448806') { $this->catalognumber = '00348333'; $this->occurrenceid = '1c2e1397-614a-44c0-bfa4-1edc1d4bb455'; } if ($this->catalognumber == '00448807') { $this->catalognumber = '00348334'; $this->occurrenceid = 'b5551dfc-53b4-4792-96bc-d66d748f2de2'; } if ($this->catalognumber == '00448821') { $this->catalognumber = '00348335'; $this->occurrenceid = '251eb221-b8f8-4d30-a3b7-fafb067262e5'; } if ($this->catalognumber == '00448775') { $this->catalognumber = '00348331'; $this->occurrenceid = '032c0d22-78b2-4c8e-88f6-9ef6638fb707'; } if ($this->catalognumber == '00448797') { $this->catalognumber = '00348332'; $this->occurrenceid = 'ba20e76f-4d97-4943-b150-b7141b9b24e3'; } if ($this->catalognumber == '00448506') { $this->catalognumber = '00415842'; $this->occurrenceid = '1688968c-dd07-4483-b20c-6137d465443a'; } if ($this->catalognumber == '00448485') { $this->catalognumber = '00415838'; $this->occurrenceid = '591ddf2e-b92a-46a7-85de-63f628688598'; } } // End Special case if ($debug) { echo "Preparing to save [{$cc}][{$this->catalognumber}]"; } $collid = $occ->lookupCollId($this->institutioncode, $this->collectioncode); $collreportmatch = "collid=[{$collid}], institutionCode=[{$this->institutioncode}], collectionCode=[{$this->collectioncode}]\n"; // Record exists if there is a matching DarwinCore triplet. $exists = $occ->loadByDWCTriplet($this->institutioncode, $this->collectioncode, $this->catalognumber); if ($debug) { echo "Exists=[{$exists}]"; } if (!$exists) { // Image upload process in TcnImageTools creates omoccurrences records where // collectioncode is not populated, but collid is. Need to handle both cases. $exists = $occ->loadByCollidCatalog($collid, $this->catalognumber); // Guidance from Ed: omoccurrences.institutioncode and omoccurrences.collectioncode should only // be populated if different from the values in omcollections for the omoccurrences.collid. } if (!$exists) { $occ = new OmOccurrences(); $occ->setcollid($collid); $occ->setcollectionCode($this->collectioncode); $occ->setcollectionID($this->collectionid); $occ->setinstitutionCode($this->institutioncode); $occ->setcatalogNumber($this->catalognumber); $occ->setprocessingStatus("unprocessed"); // Provide for link to authoritative database record (which doesn't yet exist). // extract just the uuid from the urn:uuid:{uuid} string. $matches = explode(':', $this->occurrenceid); if (count($matches) == 3) { $uuid = $matches[2]; if ($debug) { echo "extracted uuid=[{$uuid}]"; } $occ->setdbpk($uuid); } else { // if the expected uuid wasn't found, use the catalog number as the best available proxy for dbbk $occ->setdbpk($this->catalognumber); } // if creating a new occurrence record, assume it was created by the annotator on the dc:created date. $occ->setrecordenteredby($this->recordenteredby); $occ->setdateentered($this->datemodified); $occ->setstorageLocation($this->storagelocation); // NEVP ingest $occ->setfundingSource($this->fundingsource); // NEVP ingest $occ->setdocumentGuid($this->containingDocument->guid); $occ->setdocumentDate($this->containingDocument->date); } $occ->setoccurrenceId($this->occurrenceid); $occ->setbasisOfRecord($this->basisofrecord); // Separators in name strings may be amperstand (HUH standard for name pairs), semicolon, or pipe (AppleCore). // convert all to semicolon and split on that. $this->recordedby = str_replace("|", ";", $this->recordedby); $this->recordedby = str_replace("&", ";", $this->recordedby); if (strpos($this->recordedby, ";") > 0) { // split on first semicolon. $occ->setrecordedBy(trim(substr($this->recordedby, 0, strpos($this->recordedby, ";")))); $occ->setassociatedCollectors(trim(substr($this->recordedby, strpos($this->recordedby, ";") + 1, strlen($this->recordedby)))); } else { $occ->setrecordedBy(trim($this->recordedby)); $occ->setassociatedCollectors(""); } $occ->setcollectorid($this->collectorid); if ($this->recordnumber != null) { $occ->setrecordNumber($this->recordnumber); } $occ->settypeStatus($this->getTypeStatusList()); if ($this->country == null) { $occ->setcountry(DEFAULT_NEVP_COUNTRY); } else { $occ->setcountry($this->country); } if ($this->stateprovince != null) { $occ->setstateProvince($this->stateprovince); } if ($this->county != null) { $occ->setcounty($this->county); } $occ->setmunicipality($this->municipality); if ($this->locality != null) { $occ->setlocality($this->locality); } if ($this->collectingevent != null) { // Symbiota event date is a mysql date field, thus less // expressive than an ISO date field, but also has // startdayofyear and enddayofyear fields for handling ranges within a year. // // Pass off responsibility for parsing range to OmOccurrences implementation. $occ->seteventDate($this->collectingevent->eventdate); $occ->setyear($this->collectingevent->startyear); $occ->setmonth($this->collectingevent->startmonth); $occ->setday($this->collectingevent->startday); $occ->setverbatimEventDate($this->collectingevent->verbatimeventdate); } if (class_exists('Gazeteer')) { $gazeteer = new Gazeteer(); // For NEVP, lookup georeference from state+municipality $georef = $gazeteer->lookup($this->stateprovince, $this->municipality, $occ->getyear()); if ($georeference->foundMatch === true) { $occ->setdecimalLatitude($georef->latitude); $occ->setdecimalLongitude($georef->longitude); $occ->setcoordinateUncertaintyInMeters($georef->errorRadius); $occ->setgeodeticDatum($georef->geodeticDatum); $occ->setgeoreferencedBy($georef->georeferencedBy); $occ->setgeoreferenceProtocol($georef->georeferenceProtocol); $occ->setgeoreferenceSources($georef->georeferenceSources); } } if ($this->minimumelevationinmeters != null) { $occ->setminimumElevationInMeters($this->minimumelevationinmeters); } if ($this->maximumelevationinmeters != null) { $occ->setmaximumElevationInMeters($this->maximumelevationinmeters); } $filedUnder = $this->getFiledUnderID(); if ($filedUnder != null) { $occ->setsciname($filedUnder->getNameWithoutAuthor()); // without author $occ->setscientificName($filedUnder->getNameWithAuthor()); // with author // Set locality security based on TID of accepted name of filed under name $sectid = $det->lookupAcceptedTID($filedUnder->scientificname); if ($sectid == null) { $sectid = $det->lookupTID($filedUnder->scientificname); } if ($sectid == null) { $occ->setlocalitySecurity(0); } else { $occ->setlocalitySecurity($det->checkSecurityStatus($sectid)); } if ($det->lookupAcceptedTID($filedUnder->scientificname) > 0) { $occ->settidinterpreted($det->lookupAcceptedTID($filedUnder->scientificname)); } $occ->setfamily($filedUnder->family); if (strlen($occ->getfamily()) == 0) { $occ->setfamily($det->lookupFamilyForTID($det->lookupTID($filedUnder->scientificname))); } $occ->setgenus($filedUnder->genus); $occ->setspecificEpithet($filedUnder->specificepithet); $occ->setinfraSpecificEpithet($filedUnder->infraspecificepithet); $occ->setidentificationQualifier($filedUnder->identificationqualifier); $occ->setscientificNameAuthorship($filedUnder->scientificnameauthorship); $occ->settaxonGuid($filedUnder->taxonguid); // work out value for taxon rank. $occ->settaxonRank($filedUnder->infraspecificrank); if (strlen($filedUnder->infraspecificepithet) > 0 && strlen($filedUnder->infraspecificrank) == 0) { $occ->settaxonRank("subspecies"); } if (strlen($filedUnder->infraspecificepithet) == 0 && strlen($filedUnder->specificepithet) > 0) { $occ->settaxonRank("species"); } if (strlen($filedUnder->infraspecificepithet) == 0 && strlen($filedUnder->specificepithet) == 0 && strlen($filedUnder->genus) > 0) { $occ->settaxonRank("genus"); } if ($filedUnder->dateidentified != NULL) { $occ->setdateIdentified($filedUnder->identificationdate->writeAll()); } } // TODO: Handle motivations (transcribing and NSF abstract numbers). // NSF abstract number handled here with fundingsource (but not // implemented in symbiota). // motivations extracted, but nothing done with here. if ($debug) { echo ",createnew=[{$createNewRec}]\n"; } if (!$exists || $createNewRec == 1) { // if record exists, then TcnImageConf variable createNewRec specifies policy for update. $saveresult = $occ->save(); $occid = $occ->getoccid(); if ($debug) { echo "occid=[{$occid}],saveresult=[{$saveresult}]\n"; } if ($saveresult === TRUE) { if (preg_match('/Barcode .* exists\\./', $occ->errorMessage())) { $result->updatecount++; } else { if ($exists) { if ($debug) { echo "Updated occid: [" . $occ->getoccid() . "]\n"; } $result->updatecount++; } else { if ($debug) { echo "Added occid: [" . $occ->getoccid() . "]\n"; } $result->insertcount++; } foreach ($this->identifications as $id) { $id->occid = $occ->getoccid(); $id->write(); } } // Create image records from associatedmedia array. foreach ($this->associatedmedia as $media) { $sourceUrl = null; $imgWebUrl = null; $sourceID = null; $imgWebID = null; $mediaguid = $media->guid; if (is_array($media->accesspoints)) { foreach ($media->accesspoints as $accesspoint) { if (strlen($accesspoint->accessURI) > 0) { $irodsPath = str_replace('/', '\\/', $accesspoint->accessURI); $irodsPath = preg_replace('/^file:/', 'irods:', $irodsPath); $imageresult = getiPlantID($accesspoint->accessURI, $irodsPath); if ($imageresult->statusok === FALSE) { echo "Error: " . $imageresult->error . "\n"; $result->imagefailurecount++; } else { if ($debug) { echo "[{$accesspoint->format}]"; } $iPlantID = $imageresult->resource_uniq; if ($accesspoint->format == "dng") { // Original dng file $sourceUrl = "http://bisque.iplantcollaborative.org/image_service/image/{$iPlantID}"; $sourceID = $iPlantID; } if ($accesspoint->format == "jpg") { // Preconstructed derivative JPG file $imgWebUrl = "http://bisque.iplantcollaborative.org/image_service/image/{$iPlantID}?resize=1250&format=jpeg"; $imgWebID = $iPlantID; $imgTnUrl = "http://bisque.iplantcollaborative.org/image_service/image/{$iPlantID}?thumbnail=225,225"; // Because this is a JPEG, no need to request ?rotate=guess&format=jpeg,quality,100 // and the folks at iPlant are requesting that this request be made without the // un-needed transformation parameters. $imgLgUrl = "http://bisque.iplantcollaborative.org/image_service/image/{$iPlantID}"; } } } // end if accesspoint has accessURL } // end for each accesspoint } // end isarray // Workaround to handle new case of only a JPEG being provided by some insitutions if ($sourceUrl == null && $imgLgUrl != null) { // a jpeg was provided, but not a DNG, use the large version of the jpeg as the source. $sourceUrl = $imgLgUrl; } if ($sourceUrl != null && $imgWebUrl != null) { // found something to save. $result->imagecount++; $tid = $det->lookupTID($filedUnder->scientificname); $caption = "{$this->collectioncode} {$this->catalognumber} {$filedUnder->scientificname}"; $locality = $occ->getcountry() . " {$this->stateprovince} {$this->county} {$this->municipality} {$this->locality}"; $sortsequence = 50; // default number $copyright = $media->rights; $owner = $media->owner; $notes = $media->usageterms; $imgid = $imageHandler->getImgIDForSourceURL($sourceUrl); if ($imgid == "") { // add this image record $isaveresult = $imageHandler->databaseImageRecord($imgWebUrl, $imgTnUrl, $imgLgUrl, $tid, $caption, $this->recordenteredby, null, $sourceUrl, $copyright, $owner, $locality, $occid, $notes, $sortsequence, "specimen", "", $sourceID, $copyright, ""); if ($isaveresult == "") { $result->imageinsertcount++; } else { $result->imagefailurecount++; } } else { $isaveresult = $imageHandler->updateImageRecord($imgid, $imgWebUrl, $imgTnUrl, $imgLgUrl, $tid, $caption, $this->recordenteredby, null, $sourceUrl, $copyright, $owner, $locality, $occid, $notes, $sortsequence, "specimen", "", $sourceID, $copyright, ""); if ($isaveresult == "") { $result->imageupdatecount++; } else { $result->imagefailurecount++; } } if ($debug) { echo "imagesaveresult=[{$isaveresult}]\n"; } } } $result->successcount++; } else { $result->errors .= "Error in " . $this->collectioncode . "-" . $this->catalognumber . ": [" . $occ->errorMessage() . "]\n"; if ($occ->errorMessage() == "Cannot add or update a child row: a foreign key constraint fails (`symbiota`.`omoccurrences`, CONSTRAINT `FK_omoccurrences_collid` FOREIGN KEY (`collid`) REFERENCES `omcollections` (`CollID`) ON DELETE CASCADE ON UPDATE CASCADE)") { $result->errors .= "Interpretation: Record contains a collectionCode and institutionCode combination which was not found in omcollections (or only a collectionCode that was not found in omcollections or omoccurrences). \n"; $result->errors .= $collreportmatch; } $result->failurecount++; } } else { echo "Skipping, record exists and specified policy is to not update. [" . $occ->getoccid() . "]\n"; } }
public function write() { global $createNewRec, $result; $occ = new OmOccurrences(); $det = new OmOccurDeterminations(); $collid = $occ->lookupCollId(null, $this->collectioncode); // Record exists if there is a matching DarwinCore triplet. $exists = $occ->loadByDWCTriplet($occ->lookupInstitutionCode($collid), $this->collectioncode, $this->unitid); if (!$exists) { // Image upload process in TcnImageTools creates omoccurrences records where // collectioncode is not populated, but collid is. Need to handle both cases. $exists = $occ->loadByCollidCatalog($collid, $this->unitid); // TODO: Question for Ed: Find out if institutioncode and collectioncode should be populated if we // end up here. } if (!$exists) { // create new record $occ = new OmOccurrences(); $occ->setcollid($collid); $occ->setcollectionCode($this->collectioncode); $occ->setinstitutionCode($occ->lookupInstitutionCode($collid)); $occ->setcatalogNumber($this->unitid); $occ->setbasisOfRecord("PreservedSpecimen"); $occ->setprocessingStatus("unprocessed"); if (strpos($this->getTypeStatusList(), "Photograph") !== false || strpos($this->getTypeStatusList(), "Drawing") !== false) { // Handle case of Iconotypes. // Note: GPI/LAPI schema doesn't have a standard means of identifying non-type drawings. $occ->setbasisOfRecord("StillImage"); } } // Schema documentation suggests, but does not enforce, semicolon as separator for list of collectors. if (strpos(";", $this->collectors) > 0) { // split on first semicolon. $occ->setrecordedBy(substr($this->collectors, 0, strpos(";", $this->collectors))); $occ->setassociatedCollectors(substr($this->collectors, strpos(";", $this->collectors), strlen($this->collectors))); } else { $occ->setrecordedBy($this->collectors); $occ->setassociatedCollectors(""); } if ($this->collectornumber != null) { $occ->setrecordNumber($this->collectornumber); } $occ->settypeStatus($this->getTypeStatusList()); if ($this->countryname != null) { $occ->setcountry($this->countryname); } if (substr($this->locality, 0, 1) == "{") { // Depreciated, but there may be FH documents in the wild that put this into // Locality rather than Notes. $locbits = json_decode($this->locality); $occ->setstateProvince($locbits->{'stateProvince'}); $occ->setcounty($locbits->{'county'}); $occ->setlocality($locbits->{'locality'}); } else { if ($this->locality != null) { $occ->setlocality($this->locality); } } if ($this->collectiondate != NULL) { $occ->seteventDate($this->collectiondate->writeStart()); $occ->setyear($this->collectiondate->startyear); $occ->setmonth($this->collectiondate->startday); $occ->setday($this->collectiondate->startday); $occ->setverbatimEventDate($this->collectiondate->writeAll()); } else { $occ->setverbatimEventDate("[No Data]"); } $filedUnder = $this->getFiledUnderID(); if ($filedUnder != null) { $occ->setsciname($filedUnder->getSciName()); // Set locality security based on TID of accepted name of filed under name $sectid = $det->lookupAcceptedTID($filedUnder->getSciName()); if ($sectid == null) { $sectid = $det->lookupTID($filedUnder->getSciName()); } if ($sectid == null) { $occ->setlocalitySecurity(0); } else { $occ->setlocalitySecurity($det->checkSecurityStatus($sectid)); } if ($det->lookupAcceptedTID($filedUnder->getSciName()) > 0) { $occ->settidinterpreted($det->lookupAcceptedTID($filedUnder->getSciName())); } if ($filedUnder->family != "NoData") { $occ->setfamily($filedUnder->family); } if (strlen($occ->getfamily()) == 0) { $occ->setfamily($det->lookupFamilyForTID($det->lookupTID($filedUnder->getSciName()))); } $occ->setgenus($filedUnder->genus); $occ->setspecificEpithet($filedUnder->species); $occ->setinfraSpecificEpithet($filedUnder->infraspecificepithet); $occ->setscientificNameAuthorship($filedUnder->author); // work out value for taxon rank. $occ->settaxonRank($filedUnder->infraspecificrank); if (strlen($filedUnder->infraspecificepithet) > 0 && strlen($filedUnder->infraspecificrank) == 0) { $occ->settaxonRank("subspecies"); } if (strlen($filedUnder->infraspecificepithet) == 0 && strlen($filedUnder->species) > 0) { $occ->settaxonRank("species"); } if (strlen($filedUnder->infraspecificepithet) == 0 && strlen($filedUnder->species) == 0 && strlen($filedUnder->genus) > 0) { $occ->settaxonRank("genus"); } if ($filedUnder->identificationdate != NULL) { $occ->setdateIdentified($filedUnder->identificationdate->writeAll()); } } if (preg_match("/^[0-9.]+\$/", $this->altitude)) { $occ->setminimumElevationInMeters($this->altitude); } else { if ($this->altitude != null) { $occ->setverbatimElevation($this->altitude); } } if (substr($this->notes, 0, 1) == "{") { $bits = json_decode($this->notes); // Extended higher geography information if (array_key_exists('stateProvince', $bits)) { $occ->setstateProvince($bits->{'stateProvince'}); } if (array_key_exists('county', $bits)) { $occ->setcounty($bits->{'county'}); } if (array_key_exists('municipality', $bits)) { $occ->setmunicipality($bits->{'municipality'}); } // Exsicatti $extitle = ""; $exvolume = ""; $exfasicle = ""; $exnumber = ""; $exauthor = ""; if (array_key_exists('extitle', $bits)) { $extitle = $bits->{'extitle'}; } if (array_key_exists('exvolume', $bits)) { $exvolume = $bits->{'exvolume'}; } if (array_key_exists('fasicle', $bits)) { $exfasicle = $bits->{'fasicle'}; } if (array_key_exists('exnumber', $bits)) { $exnumber = $bits->{'exnumber'}; } if (array_key_exists('exauthor', $bits)) { $exauthor = $bits->{'exauthor'}; } // TODO: Take Exsiccati data and link(/create?) records in Symbiota } else { $occ->setoccurrenceRemarks($this->notes); } if (!$exists || $createNewRec == 1) { // if record exists, then TcnImageConf variable createNewRec specifies policy for update. if ($occ->save()) { if ($exists) { //echo "Updated occid: [".$occ->getoccid()."]\n"; $result->successcount++; $result->updatecount++; } else { //echo "Added occid: [".$occ->getoccid()."]\n"; $result->successcount++; $result->insertcount++; } foreach ($this->identifications as $id) { $id->occid = $occ->getoccid(); $id->write(); } } else { $result->errors .= "Error: [" . $occ->errorMessage() . "]\n"; $result->failurecount++; } } else { echo "Skipping, record exists and specified policy is to not update. [" . $occ->getoccid() . "]\n"; } }