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"; } }