diff --git a/classes/AssociationManager.php b/classes/AssociationManager.php index 654de72287..00fd1f9e7f 100644 --- a/classes/AssociationManager.php +++ b/classes/AssociationManager.php @@ -1,5 +1,7 @@ isEditor = true; @@ -44,35 +47,122 @@ public function getRelationshipTypes(){ } } - public function getAssociatedRecords($associationArr){ - $sql=''; - - if(array_key_exists('relationship', $associationArr) && $associationArr['relationship'] !== 'none'){ - $familyJoinStr = ''; - $shouldUseFamily = array_key_exists('associated-taxa', $associationArr) && $associationArr['associated-taxa'] == '3'; - if($shouldUseFamily) $familyJoinStr = 'LEFT JOIN taxstatus ts ON o.tidinterpreted = ts.tid'; - - - // "Forward" association - $relationshipType = (array_key_exists('relationship', $associationArr) && $associationArr['relationship'] !== 'any') ? $associationArr['relationship'] : 'IS NOT NULL'; - $relationshipStr = (array_key_exists('relationship', $associationArr) && $associationArr['relationship'] !== 'any') ? ("='" . $relationshipType . "'") : (' IS NOT NULL'); - // $sql .= "AND (o.occid IN (SELECT DISTINCT o.occid FROM omoccurrences o INNER JOIN omoccurassociations oa on o.occid=oa.occid WHERE oa.relationship" . $relationshipStr . " "; - $sql .= "AND (o.occid IN (SELECT DISTINCT o.occid FROM omoccurrences o INNER JOIN omoccurassociations oa on o.occid=oa.occid " . $familyJoinStr . " WHERE oa.relationship" . $relationshipStr . " "; - $sql .= $this->getAssociatedTaxonWhereFrag($associationArr) . ')'; - - // @TODO handle situation where the associationType is external and there's no occidAssociate; pull resourceUrl instead? - //something like: - // $sql =. 'SELECT DISTINCT resourceUrl from omoccurassociations WHERE associationType="externalOccurrence" AND occidAssociate IS NULL AND relationship = ' . $relationshipType . ' AND '; - - // "Reverse" association - $reverseAssociationType = (array_key_exists('relationship', $associationArr) && $associationArr['relationship'] !== 'any') ? $this->getInverseRelationshipOf($relationshipType) : 'IS NOT NULL'; - $reverseRelationshipStr = (array_key_exists('relationship', $associationArr) && $associationArr['relationship'] !== 'any') ? ("='" . $reverseAssociationType . "'") : (' IS NOT NULL'); - $sql .= " OR o.occid IN (SELECT DISTINCT oa.occidAssociate FROM omoccurrences o INNER JOIN omoccurassociations oa on o.occid=oa.occid INNER JOIN omoccurdeterminations od ON oa.occid=od.occid " . $familyJoinStr . " where oa.relationship " . $reverseRelationshipStr . " "; //isCurrent="1" AND my thought was that we want these results to be as relaxed as possible - $sql .= $this->getAssociatedTaxonWhereFrag($associationArr) . ')'; + public function establishInverseRelationshipRecords(){ + $sql = "SELECT * FROM omoccurassociations where occid IS NOT NULL AND occidAssociate IS NOT NULL;"; + if($statement = $this->conn->prepare($sql)){ + $statement->execute(); + $result = $statement->get_result(); + while ($row = $result->fetch_assoc()) { + // $returnVal = $row['inverseRelationship']; + if(!$this->hasInverseRecord($row)){ + $this->createInverseRecord($row); + } + // if that record has an inverse present, do nothing + // else, create an inverse record + } + $statement->close(); + // return $returnVal; + }else{ + return ''; + } + } + + private function hasInverseRecord($record){ + // var_dump($record); + $sql = "SELECT * FROM omoccurassociations WHERE occidAssociate = ? AND occid = ? and relationship = ?;"; + $recordOccid = array_key_exists('occid', $record) ? $record['occid'] : ''; + $recordOccidAssociate = array_key_exists('occidAssociate', $record) ? $record['occidAssociate'] : ''; + $relationship = array_key_exists('relationship', $record) ? $record['relationship'] : ''; + $inverseRelationship = $this->getInverseRelationshipOf($relationship); + if($statement = $this->conn->prepare($sql)){ + $statement->bind_param('iis', $recordOccid, $recordOccidAssociate, $inverseRelationship); + $statement->execute(); + $result = $statement->get_result(); + $returnVal = false; + if ($row = $result->fetch_assoc()) { + // $returnVal = $row['inverseRelationship']; + $returnVal = true; + } + $statement->close(); + return $returnVal; + }else{ + return ''; + } + } + public function createInverseRecord($record){ + $recordOccid = array_key_exists('occid', $record) ? $record['occid'] : ''; + $recordOccidAssociate = array_key_exists('occidAssociate', $record) ? $record['occidAssociate'] : ''; + $relationship = array_key_exists('relationship', $record) ? $record['relationship'] : ''; + $inverseRelationship = $this->getInverseRelationshipOf($relationship); + $verbatimsciname = $this->getCorrespondingVerbatimsciname($recordOccid); + $createdUid = $GLOBALS['SYMB_UID']; + $basisOfRecord = 'scriptGenerated'; + $sql = 'INSERT INTO omoccurassociations(occid, occidAssociate, relationship, basisOfRecord, createdUid, verbatimsciname)'; + $sql .= ' VALUES(?,?,?,?,?,?);'; + $returnVal = false; + // $this->resetConnection(); + $shouldCreateInverseRecord = !empty($recordOccid) && !empty($recordOccidAssociate) && !empty($relationship) && !empty($inverseRelationship) && !empty($recordOccid); + if($shouldCreateInverseRecord && $statement = $this->conn->prepare($sql)){ + $statement->bind_param('iissis', $recordOccidAssociate, $recordOccid, $inverseRelationship, $basisOfRecord, $createdUid, $verbatimsciname); + if($statement->execute()){ + $returnVal = true; + } + $statement->close(); + } + // $this->resetConnectionToRead(); + return $returnVal; + } + + private function getCorrespondingVerbatimsciname($targetOccid){ + $sql = 'SELECT sciname from omoccurrences where occid=?'; + $returnVal = ''; + if($statement = $this->conn->prepare($sql)){ + $statement->bind_param('s', $targetOccid); + $statement->execute(); + $result = $statement->get_result(); + if ($row = $result->fetch_assoc()) { + $returnVal = array_key_exists('sciname', $row) ? $row['sciname'] : ''; + } + $statement->close(); } - return $sql; + return $returnVal; } + // protected function resetConnection(){ + // $this->conn = MySQLiConnectionFactory::getCon('write'); + // } + + // protected function resetConnectionToRead(){ + // $this->conn = MySQLiConnectionFactory::getCon('readonly'); + // } + + public function getAssociatedRecords($associationArr) { + $sql = ''; + + if (array_key_exists('relationship', $associationArr) && $associationArr['relationship'] !== 'none') { + $familyJoinStr = ''; + $shouldUseFamily = array_key_exists('associated-taxa', $associationArr) && $associationArr['associated-taxa'] == '3'; + if ($shouldUseFamily) $familyJoinStr = 'LEFT JOIN taxstatus ts ON o.tidinterpreted = ts.tid'; + + // "Forward" association + $relationshipType = (array_key_exists('relationship', $associationArr) && $associationArr['relationship'] !== 'any') ? $associationArr['relationship'] : 'IS NOT NULL'; + $relationshipStr = (array_key_exists('relationship', $associationArr) && $associationArr['relationship'] !== 'any') ? ("='" . $relationshipType . "'") : ' IS NOT NULL'; + + $forwardSql = "SELECT o.occid FROM omoccurrences o INNER JOIN omoccurassociations oa ON o.occid = oa.occid " . $familyJoinStr . " WHERE oa.relationship " . $relationshipStr . " "; + $forwardSql .= $this->getAssociatedTaxonWhereFrag($associationArr); + + // "Reverse" association + $reverseAssociationType = (array_key_exists('relationship', $associationArr) && $associationArr['relationship'] !== 'any') ? $this->getInverseRelationshipOf($relationshipType) : 'IS NOT NULL'; + $reverseRelationshipStr = (array_key_exists('relationship', $associationArr) && $associationArr['relationship'] !== 'any') ? ("='" . $reverseAssociationType . "'") : ' IS NOT NULL'; + + $reverseSql = "SELECT oa.occidAssociate FROM omoccurrences o INNER JOIN omoccurassociations oa ON o.occid = oa.occid INNER JOIN omoccurdeterminations od ON oa.occid = od.occid " . $familyJoinStr . " WHERE oa.relationship " . $reverseRelationshipStr . " "; + $reverseSql .= $this->getAssociatedTaxonWhereFrag($associationArr); + + $sql .= "AND (o.occid IN (SELECT occid FROM ( " . $forwardSql . " UNION " . $reverseSql . " ) AS occids)"; + } + return $sql; +} + public function getAssociatedTaxonWhereFrag($associationArr){ $sqlWhereTaxa = ''; if(isset($associationArr['taxa'])){ @@ -122,21 +212,21 @@ public function getAssociatedTaxonWhereFrag($associationArr){ //Return matches that are not linked to thesaurus if($rankid > 179){ if($this->exactMatchOnly) $sqlWhereTaxa .= 'OR (o.sciname = "' . $term . '") '; - else $sqlWhereTaxa .= "OR (o.sciname LIKE '" . $term . "%') "; + else $sqlWhereTaxa .= "OR (o.sciname LIKE '" . $term . "%') OR (oa.verbatimsciname LIKE '" . $term . "%') "; } } else{ //Protect against someone trying to download big pieces of the occurrence table through the user interface if(strlen($term) < 4) $term .= ' '; if($this->exactMatchOnly){ - $sqlWhereTaxa .= 'OR (o.sciname = "' . $term . '") '; + $sqlWhereTaxa .= 'OR (o.sciname = "' . $term . '") OR (oa.verbatimsciname LIKE "' . $term . '%") '; } else{ - $sqlWhereTaxa .= 'OR (o.sciname LIKE "' . $term . '%") '; + $sqlWhereTaxa .= 'OR (o.sciname LIKE "' . $term . '%") OR (oa.verbatimsciname LIKE "' . $term . '%") '; if(!strpos($term,' _ ')){ //Accommodate for formats of hybrid designations within input and target data (e.g. x, multiplication sign, etc) $term2 = preg_replace('/^([^\s]+\s{1})/', '$1 _ ', $term); - $sqlWhereTaxa .= "OR (o.sciname LIKE '" . $term2 . "%') "; + $sqlWhereTaxa .= "OR (o.sciname LIKE '" . $term2 . "%') OR (oa.verbatimsciname LIKE '" . $term . "%') "; } } } diff --git a/classes/OccurrenceListManager.php b/classes/OccurrenceListManager.php index 687e794b6f..89b0f13d28 100644 --- a/classes/OccurrenceListManager.php +++ b/classes/OccurrenceListManager.php @@ -40,7 +40,7 @@ public function getSpecimenMap($pageRequest,$cntPerPage){ $pageRequest = ($pageRequest - 1)*$cntPerPage; } $sql .= ' LIMIT ' . $pageRequest . ',' . $cntPerPage; - // echo '
Spec sql: ' . $sql . '
'; exit; + // echo '
Spec sql: ' . $sql . '
'; exit; // @TODO HERE $result = $this->conn->query($sql); if($result){ $securityCollArr = array(); @@ -125,7 +125,7 @@ private function setImages($occArr,&$retArr){ private function setRecordCnt($sqlWhere){ if($sqlWhere){ $sql = "SELECT COUNT(DISTINCT o.occid) AS cnt FROM omoccurrences o ".$this->getTableJoins($sqlWhere).$sqlWhere; - // echo "
Count sql: ".$sql."
"; + // echo "
Count sql: ".$sql."
"; exit; $result = $this->conn->query($sql); if($result){ if($row = $result->fetch_object()){ diff --git a/classes/OccurrenceManager.php b/classes/OccurrenceManager.php index 6a3ef03dc4..8635345ad0 100644 --- a/classes/OccurrenceManager.php +++ b/classes/OccurrenceManager.php @@ -21,6 +21,7 @@ class OccurrenceManager extends OccurrenceTaxaManager { public function __construct($type='readonly'){ parent::__construct($type); if(array_key_exists('reset',$_REQUEST) && $_REQUEST['reset']) $this->reset(); + $this->associationManager = new AssociationManager(); $this->readRequestVariables(); $langTag = ''; if(!empty($GLOBALS['LANG_TAG'])) $langTag = $GLOBALS['LANG_TAG']; @@ -28,7 +29,6 @@ public function __construct($type='readonly'){ include_once($GLOBALS['SERVER_ROOT'] . '/content/lang/classes/OccurrenceManager.' . $langTag . '.php'); else include_once($GLOBALS['SERVER_ROOT'] . '/content/lang/classes/OccurrenceManager.en.php'); $this->LANG = $LANG; - $this->associationManager = new AssociationManager(); } public function __destruct(){ @@ -60,15 +60,11 @@ public function getSqlWhere(){ protected function setSqlWhere(){ $sqlWhere = ''; - // var_dump($this->searchTermArr); - // $deleteMe = $this->associationManager->getAssociatedTaxonWhereFrag($this->associationArr); - // var_dump($deleteMe); if(array_key_exists("targetclid",$this->searchTermArr) && is_numeric($this->searchTermArr["targetclid"])){ if(!$this->voucherManager){ $this->setChecklistVariables($this->searchTermArr['targetclid']); } $voucherVariableArr = $this->voucherManager->getQueryVariableArr(); - // var_dump($voucherVariableArr); if($voucherVariableArr){ if(isset($voucherVariableArr['association-type'])) $this->searchTermArr['association-type'] = $voucherVariableArr['association-type']; if(isset($voucherVariableArr['taxontype-association'])) $this->searchTermArr['taxontype-association'] = $voucherVariableArr['taxontype-association']; @@ -129,11 +125,8 @@ protected function setSqlWhere(){ $this->displaySearchArr[] = $this->LANG['DATASETS'] . ': ' . $this->getDatasetTitle($this->searchTermArr['datasetid']); } $sqlWhere .= $this->getTaxonWhereFrag(); - // echo "
this dot getTaxonWhereFrag() is: " . $this->getTaxonWhereFrag() . "
"; - // echo "
sqlWhere before getting the association taxa is: " . $sqlWhere . "
"; $hasValidRelationship = isset(($this->associationArr['relationship'])) && $this->associationArr['relationship']!=='none'; - // $hasValidAssociatedTaxon = isset($this->associationArr['search']); - if($hasValidRelationship){ // || $hasValidAssociatedTaxon // @TODO + if($hasValidRelationship){ $sqlWhere = substr_replace($sqlWhere,'',-1); $sqlWhere .= $this->associationManager->getAssociatedRecords($this->associationArr) . ')'; } @@ -547,7 +540,6 @@ protected function getTableJoins($sqlWhere){ $sqlJoin .= 'INNER JOIN taxaenumtree e ON o.tidinterpreted = e.tid '; } if(strpos($sqlWhere,'ts.family')){ - echo 'ts.family entered'; $sqlJoin .= 'LEFT JOIN taxstatus ts ON o.tidinterpreted = ts.tid '; } if(strpos($sqlWhere,'ds.datasetid')){ @@ -668,7 +660,6 @@ public function getQueryTermStr(){ $retStr .= '&taxontype=1'; } } - // var_dump($this->associationArr); $patternOfOnlyLettersDigitsAndSpaces = '/^[a-zA-Z0-9\s\-]*$/'; // TOOD accommodate symbols associated with extinct taxa, hybrid crosses, and abbreviations with periods, e.g. "var."? if(isset($this->associationArr['search'])){ if (preg_match($patternOfOnlyLettersDigitsAndSpaces, $this->associationArr['search'])==1) { @@ -715,11 +706,9 @@ private function getDatasetTitle($dsIdStr){ } protected function readRequestVariables(){ - // var_dump($_REQUEST); // @TODO this is an intervention point if(array_key_exists('searchvar',$_REQUEST)){ $parsedArr = array(); $taxaArr = array(); - // parse_str($_REQUEST['searchvar'], $parsedArr); $searchVar = str_replace('&', '&', $_REQUEST['searchvar']); parse_str($searchVar, $parsedArr); @@ -735,7 +724,6 @@ protected function readRequestVariables(){ unset($parsedArr['taxontype']); } $this->setTaxonRequestVariable($taxaArr); - // $this->setAssociationRequestVariable(); } foreach($parsedArr as $k => $v){ $k = $this->cleanInputStr($k); @@ -776,7 +764,6 @@ protected function readRequestVariables(){ if($hasEverythingRequiredForAssociationSearch){ $this->setAssociationRequestVariable(); } - // var_dump($this->searchTermArr); if(array_key_exists('country',$_REQUEST)){ $country = $this->cleanInputStr($_REQUEST['country']); if($country){ @@ -1010,7 +997,6 @@ protected function readRequestVariables(){ $this->searchTermArr['footprintwkt'] = $this->cleanInputStr($_REQUEST['footprintwkt']); } - // var_dump($this->searchTermArr); } private function setChecklistVariables($clid){ diff --git a/classes/OccurrenceTaxaManager.php b/classes/OccurrenceTaxaManager.php index 11ad552e6a..bab1d9ae2e 100644 --- a/classes/OccurrenceTaxaManager.php +++ b/classes/OccurrenceTaxaManager.php @@ -60,8 +60,6 @@ public function setAssociationRequestVariable($inputArr = null, $exactMatchOnly $this->associationArr['relationship'] = $associationTypeStr; } - // $taxonTypeAssociationStr = $this->cleanAndAssignGeneric('taxontype-association', $inputArr); - if($associatedTaxonStr){ $this->associationArr['search'] = $associatedTaxonStr; $this->setAssociationUseThes($inputArr, 'usethes-associations'); @@ -82,14 +80,10 @@ public function setAssociationRequestVariable($inputArr = null, $exactMatchOnly } - // @TODO $taxonType2Str - // var_dump($this->associationArr['taxa']); - - // LEFT OFF HERE figuring out the remaining TODOs here and testing it out } protected function processSingleTerm($searchTerm, $searchTermkey, $defaultTaxaType){ - $this->associationTaxaSearchTerms[$searchTermkey] = $searchTerm; // @TODO generalize + $this->associationTaxaSearchTerms[$searchTermkey] = $searchTerm; $taxaType = $defaultTaxaType; if($defaultTaxaType == TaxaSearchType::ANY_NAME) { $searchTermName = explode(': ',$searchTerm); @@ -100,7 +94,7 @@ protected function processSingleTerm($searchTerm, $searchTermkey, $defaultTaxaTy $taxaType = TaxaSearchType::SCIENTIFIC_NAME; } } - $this->setSciNamesByVerns($searchTerm, $this->associationArr); // @TODO test whether this works + $this->setSciNamesByVerns($searchTerm, $this->associationArr); $this->setTaxonRankAndType($searchTerm, $taxaType, 'usethes-associations'); } @@ -123,7 +117,7 @@ protected function setTaxonRankAndType($searchTerm, $taxaType, $useThesId='useth if($this->associationArr[$useThesId]){ $sql .= 'INNER JOIN taxstatus ts ON t.tid = ts.tidaccepted INNER JOIN taxa t2 ON ts.tid = t2.tid - WHERE (ts.taxauthid = ?) AND (t2.sciname IN(?))'; // @TODO does this work? + WHERE (ts.taxauthid = ?) AND (t2.sciname IN(?))'; $typeStr .= 'is'; array_push($bindingArr, $this->taxAuthId, $this->cleanInStr($searchTerm)); } else{ @@ -132,10 +126,7 @@ protected function setTaxonRankAndType($searchTerm, $taxaType, $useThesId='useth array_push($bindingArr, $this->cleanInStr($searchTerm)); } } - // var_dump($sql); if ($statement = $this->conn->prepare($sql)) { - // var_dump($typeStr); - // var_dump(...$bindingArr); $statement->bind_param($typeStr,...$bindingArr); $statement->execute(); $result = $statement->get_result(); @@ -162,7 +153,7 @@ protected function setTaxonRankAndType($searchTerm, $taxaType, $useThesId='useth protected function setAssociationSynonyms(){ if(isset($this->associationArr['taxa'])){ - foreach($this->associationArr['taxa'] as $searchStr => $searchArr){ // @TODO LEFT OFF HERE + foreach($this->associationArr['taxa'] as $searchStr => $searchArr){ if(isset($searchArr['tid']) && $searchArr['tid']){ foreach($searchArr['tid'] as $tid => $rankid){ $accArr = array(); @@ -195,7 +186,7 @@ protected function addAcceptedChildrenToArray($tid, $rankid, $accArr, $searchStr $accArr[] = $r1['tid']; if(!isset($this->associationArr['taxa'][$r1['sciname']])){ if($rankid == 220) $this->associationArr['taxa'][$r1['sciname']]['tid'][$r1['tid']] = $r1['rankid']; - else $this->associationArr['taxa'][$searchStr]['TID_BATCH'][$r1['tid']] = ''; // @TODO generalize and use in setSynonyms as well to DRY up code + else $this->associationArr['taxa'][$searchStr]['TID_BATCH'][$r1['tid']] = ''; } } } @@ -218,7 +209,7 @@ protected function addSynonymsOfAcceptedTaxaToArray($accArr, $rankid, $searchStr $result = $statement2->get_result(); if($result->num_rows > 0){ while($r2 = $result->fetch_assoc()){ - if($rankid >= 220) $this->associationArr['taxa'][$r2['accepted']]['synonyms'][$r2['tid']] = $r2['sciname']; // @TODO generalize and use in setSynonyms as well to DRY up code + if($rankid >= 220) $this->associationArr['taxa'][$r2['accepted']]['synonyms'][$r2['tid']] = $r2['sciname']; else $this->associationArr['taxa'][$searchStr]['TID_BATCH'][$r2['tid']] = ''; } } @@ -227,7 +218,7 @@ protected function addSynonymsOfAcceptedTaxaToArray($accArr, $rankid, $searchStr } protected function setAssociationUseThes($inputArr = null, $useThesId='usethes'){ - $this->associationArr[$useThesId] = 0; // @TODO generalize and use in setTaxonRequestVariable as well to DRY up code + $this->associationArr[$useThesId] = 0; if(isset($inputArr[$useThesId]) && $inputArr[$useThesId]){ $this->associationArr[$useThesId] = 1; } @@ -236,7 +227,7 @@ protected function setAssociationUseThes($inputArr = null, $useThesId='usethes') } } - protected function setAndGetAssociationDefaultTaxaType($inputArr = null){ // @TOD generalize this work with setTaxonRequestVariable as well + protected function setAndGetAssociationDefaultTaxaType($inputArr = null){ $defaultTaxaType = TaxaSearchType::SCIENTIFIC_NAME; if(isset($inputArr['associated-taxa']) && is_numeric($inputArr['associated-taxa'])){ $defaultTaxaType = $inputArr['associated-taxa']; @@ -375,20 +366,20 @@ private function setSciNamesByVerns(&$searchTerm, &$alternateTaxaArr = null) { while($row = $result->fetch_object()){ $vernName = $row->VernacularName; if($row->rankid == 140){ - if(array_key_exists('taxa', $alternateTaxaArr)){ - $alternateTaxaArr['taxa'][$vernName]['families'][] = $row->sciname; // @TODO check that these values update correctly + if(is_array($alternateTaxaArr) && array_key_exists('taxa', $alternateTaxaArr)){ + $alternateTaxaArr['taxa'][$vernName]['families'][] = $row->sciname; } else{ $this->taxaArr['taxa'][$vernName]['families'][] = $row->sciname; } } else{ - if(array_key_exists('taxa', $alternateTaxaArr)){ + if(is_array($alternateTaxaArr) && array_key_exists('taxa', $alternateTaxaArr)){ $alternateTaxaArr['taxa'][$vernName]['scinames'][] = $row->sciname; }else{ $this->taxaArr['taxa'][$vernName]['scinames'][] = $row->sciname; } } - if(array_key_exists('taxa', $alternateTaxaArr)){ + if(is_array($alternateTaxaArr) && array_key_exists('taxa', $alternateTaxaArr)){ $alternateTaxaArr['taxa'][$vernName]['tid'][$row->tid] = $row->rankid; }else{ $this->taxaArr['taxa'][$vernName]['tid'][$row->tid] = $row->rankid; @@ -446,120 +437,9 @@ private function setSynonyms(){ } } - // public function getAssociatedTaxonWhereFrag(){ - // $sqlWhereTaxa = ''; - // if(isset($this->associationArr['taxa'])){ - // // var_dump($this->associationArr); - // $tidInArr = array(); - // $taxonType = $this->associationArr['associated-taxa']; - // foreach($this->associationArr['taxa'] as $searchTaxon => $searchArr){ - // if(isset($searchArr['taxontype'])) $taxonType = $searchArr['taxontype']; - // if($taxonType == TaxaSearchType::TAXONOMIC_GROUP){ - // //Class, order, or other higher rank - // if(isset($searchArr['tid'])){ - // $tidArr = array_keys($searchArr['tid']); - // //$sqlWhereTaxa .= 'OR (o.tidinterpreted IN(SELECT DISTINCT tid FROM taxaenumtree WHERE (taxauthid = '.$this->taxAuthId.') AND (parenttid IN('.trim($tidStr,',').') OR (tid = '.trim($tidStr,',').')))) '; - // $sqlWhereTaxa .= 'OR (e.parenttid IN('.implode(',', $tidArr).') '; - // $sqlWhereTaxa .= 'OR (e.tid IN('.implode(',', $tidArr).')) '; - // if(isset($searchArr['synonyms'])) $sqlWhereTaxa .= 'OR (e.tid IN('.implode(',',array_keys($searchArr['synonyms'])).')) '; - // //$tidInArr = array_merge($tidInArr,$tidArr); - // //if(isset($searchArr['synonyms'])) $tidInArr = array_merge($tidInArr,array_keys($searchArr['synonyms'])); - // $sqlWhereTaxa .= ') '; - // } - // else{ - // //Unable to find higher taxon within taxonomic tree, thus return nothing - // $sqlWhereTaxa .= 'OR (o.tidinterpreted = 0) '; - // } - // } - // elseif($taxonType == TaxaSearchType::FAMILY_ONLY){ - // //$sqlWhereTaxa .= 'OR ((o.family = "'.$searchTaxon.'") OR (o.sciname = "'.$searchTaxon.'")) '; - // //$sqlWhereTaxa .= 'OR (((ts.family = "'.$searchTaxon.'") AND (ts.taxauthid = '.$this->taxAuthId.')) OR (o.family = "'.$searchTaxon.'") OR (o.sciname = "'.$searchTaxon.'")) '; - // //$sqlWhereTaxa .= 'OR (((ts.family = "'.$searchTaxon.'") AND (ts.taxauthid = '.$this->taxAuthId.')) OR o.sciname = "'.$searchTaxon.'") '; - // if(isset($searchArr['tid'])){ - // $tidArr = array_keys($searchArr['tid']); - // $sqlWhereTaxa .= 'OR ((ts.family = "'.$searchTaxon.'") OR (ts.tid IN('.implode(',', $tidArr).'))) '; - // } - // else{ - // $sqlWhereTaxa .= 'OR ((o.family = "'.$searchTaxon.'") OR (o.sciname = "'.$searchTaxon.'")) '; - // } - // } - // else{ - // if($taxonType == TaxaSearchType::COMMON_NAME){ - // $famArr = $this->setCommonNameWhereTerms($searchArr, $tidInArr); - // if($famArr) $sqlWhereTaxa .= 'OR (o.family IN("'.implode('","',$famArr).'")) '; - // } - // if(isset($searchArr['TID_BATCH'])){ - // $tidInArr = array_merge($tidInArr, array_keys($searchArr['TID_BATCH'])); - // if(isset($searchArr['tid'])) $tidInArr = array_merge($tidInArr, array_keys($searchArr['tid'])); - // } - // else{ - // $term = $this->cleanInStr(trim($searchTaxon,'%')); - // //$term = preg_replace('/\s{1}.{1,2}\s{1}/', ' _ ', $term); - // $term = preg_replace(array('/\s{1}x\s{1}/','/\s{1}X\s{1}/','/\s{1}\x{00D7}\s{1}/u'), ' _ ', $term); - // if(array_key_exists('tid',$searchArr)){ - // $rankid = current($searchArr['tid']); - // $tidArr = array_keys($searchArr['tid']); - // //$sqlWhereTaxa .= "OR (o.tidinterpreted IN(".implode(',',$tidArr).")) "; - // $tidInArr = array_merge($tidInArr, $tidArr); - // //Return matches that are not linked to thesaurus - // if($rankid > 179){ - // if($this->exactMatchOnly) $sqlWhereTaxa .= 'OR (o.sciname = "' . $term . '") '; - // else $sqlWhereTaxa .= 'OR (o.sciname LIKE "' . $term . '%") '; - // } - // } - // else{ - // //Protect against someone trying to download big pieces of the occurrence table through the user interface - // if(strlen($term) < 4) $term .= ' '; - // /* - // if(strpos($term, ' ') || strpos($term, '%')){ - // //Return matches for "Pinus a" - // $sqlWhereTaxa .= "OR (o.sciname LIKE '" . $term . "%') "; - // } - // else{ - // $sqlWhereTaxa .= "OR (o.sciname LIKE '" . $term . " %') "; - // } - // */ - // if($this->exactMatchOnly){ - // $sqlWhereTaxa .= 'OR (o.sciname = "' . $term . '") '; - // } - // else{ - // $sqlWhereTaxa .= 'OR (o.sciname LIKE "' . $term . '%") '; - // if(!strpos($term,' _ ')){ - // //Accommodate for formats of hybrid designations within input and target data (e.g. x, multiplication sign, etc) - // $term2 = preg_replace('/^([^\s]+\s{1})/', '$1 _ ', $term); - // $sqlWhereTaxa .= 'OR (o.sciname LIKE "' . $term2 . '%") '; - // } - // } - // } - // } - // if(array_key_exists('synonyms',$searchArr)){ - // $synArr = $searchArr['synonyms']; - // if($synArr){ - // if($taxonType == TaxaSearchType::SCIENTIFIC_NAME || $taxonType == TaxaSearchType::COMMON_NAME){ - // foreach($synArr as $synTid => $sciName){ - // if(strpos($sciName,'aceae') || strpos($sciName,'idae')){ - // $sqlWhereTaxa .= 'OR (o.family = "' . $sciName . '") '; - // } - // } - // } - // //$sqlWhereTaxa .= 'OR (o.tidinterpreted IN('.implode(',',array_keys($synArr)).')) '; - // $tidInArr = array_merge($tidInArr,array_keys($synArr)); - // } - // } - // } - // } - // if($tidInArr) $sqlWhereTaxa .= 'OR (o.tidinterpreted IN('.implode(',',array_unique($tidInArr)).')) '; - // $sqlWhereTaxa = 'AND ('.trim(substr($sqlWhereTaxa,3)).') '; - // if(strpos($sqlWhereTaxa,'e.parenttid')) $sqlWhereTaxa .= 'AND (e.taxauthid = '.$this->taxAuthId.') '; - // if(strpos($sqlWhereTaxa,'ts.family')) $sqlWhereTaxa .= 'AND (ts.taxauthid = '.$this->taxAuthId.') '; - // } - // if($sqlWhereTaxa) return $sqlWhereTaxa; - // else return false; - // } public function getTaxonWhereFrag(){ $sqlWhereTaxa = ''; - // var_dump($this->taxaArr); if(isset($this->taxaArr['taxa'])){ $tidInArr = array(); $taxonType = $this->taxaArr['taxontype']; @@ -570,12 +450,9 @@ public function getTaxonWhereFrag(){ //Class, order, or other higher rank if(isset($searchArr['tid'])){ $tidArr = array_keys($searchArr['tid']); - //$sqlWhereTaxa .= 'OR (o.tidinterpreted IN(SELECT DISTINCT tid FROM taxaenumtree WHERE (taxauthid = '.$this->taxAuthId.') AND (parenttid IN('.trim($tidStr,',').') OR (tid = '.trim($tidStr,',').')))) '; $sqlWhereTaxa .= 'OR (e.parenttid IN('.implode(',', $tidArr).') '; $sqlWhereTaxa .= 'OR (e.tid IN('.implode(',', $tidArr).')) '; if(isset($searchArr['synonyms'])) $sqlWhereTaxa .= 'OR (e.tid IN('.implode(',',array_keys($searchArr['synonyms'])).')) '; - //$tidInArr = array_merge($tidInArr,$tidArr); - //if(isset($searchArr['synonyms'])) $tidInArr = array_merge($tidInArr,array_keys($searchArr['synonyms'])); $sqlWhereTaxa .= ') '; } else{ @@ -584,9 +461,6 @@ public function getTaxonWhereFrag(){ } } elseif($taxonType == TaxaSearchType::FAMILY_ONLY){ - //$sqlWhereTaxa .= 'OR ((o.family = "'.$searchTaxon.'") OR (o.sciname = "'.$searchTaxon.'")) '; - //$sqlWhereTaxa .= 'OR (((ts.family = "'.$searchTaxon.'") AND (ts.taxauthid = '.$this->taxAuthId.')) OR (o.family = "'.$searchTaxon.'") OR (o.sciname = "'.$searchTaxon.'")) '; - //$sqlWhereTaxa .= 'OR (((ts.family = "'.$searchTaxon.'") AND (ts.taxauthid = '.$this->taxAuthId.')) OR o.sciname = "'.$searchTaxon.'") '; if(isset($searchArr['tid'])){ $tidArr = array_keys($searchArr['tid']); $sqlWhereTaxa .= 'OR ((ts.family = "'.$cleanedSearchTaxon.'") OR (ts.tid IN('.implode(',', $tidArr).'))) '; @@ -606,12 +480,10 @@ public function getTaxonWhereFrag(){ } else{ $term = $this->cleanInStr(trim($searchTaxon,'%')); - //$term = preg_replace('/\s{1}.{1,2}\s{1}/', ' _ ', $term); $term = preg_replace(array('/\s{1}x\s{1}/','/\s{1}X\s{1}/','/\s{1}\x{00D7}\s{1}/u'), ' _ ', $term); if(array_key_exists('tid',$searchArr)){ $rankid = current($searchArr['tid']); $tidArr = array_keys($searchArr['tid']); - //$sqlWhereTaxa .= "OR (o.tidinterpreted IN(".implode(',',$tidArr).")) "; $tidInArr = array_merge($tidInArr, $tidArr); //Return matches that are not linked to thesaurus if($rankid > 179){ @@ -722,7 +594,7 @@ public function getTaxaSearchStr(){ public function getAssociationSearchStr(){ $str = ''; - if(isset($this->associationArr['relationship'])){ + if(isset($this->associationArr['relationship']) && $this->associationArr['relationship'] != 'none'){ $str = 'Taxa that have the following association: '; $str .= $this->associationArr['relationship']; } diff --git a/classes/OmAssociations.php b/classes/OmAssociations.php index ccc3b3ecb7..72fa827d9d 100644 --- a/classes/OmAssociations.php +++ b/classes/OmAssociations.php @@ -2,6 +2,7 @@ include_once('Manager.php'); include_once('OccurrenceUtilities.php'); include_once('UuidFactory.php'); +include_once('AssociationManager.php'); class OmAssociations extends Manager{ @@ -24,11 +25,14 @@ public function __destruct(){ parent::__destruct(); } - public function getAssociationArr($filter = null){ + public function getAssociationArr($filter = null, $excludeScriptGenerated = true){ $retArr = array(); $relOccidArr = array(); $uidArr = array(); $sql = 'SELECT assocID, occid, '.implode(', ', array_keys($this->schemaMap)).', modifiedUid, modifiedTimestamp, createdUid, initialTimestamp FROM omoccurassociations WHERE '; + if($excludeScriptGenerated){ + $sql .= "basisOfRecord IS NULL OR basisOfRecord != 'scriptGenerated' AND "; + } if($this->assocID) $sql .= '(assocID = '.$this->assocID.') '; elseif($filter == 'FULL')$sql .= '(occid = '.$this->occid.' OR occidAssociate = '.$this->occid.') '; elseif($this->occid) $sql .= '(occid = '.$this->occid.') '; @@ -37,6 +41,7 @@ public function getAssociationArr($filter = null){ $sql .= 'AND '.$field.' = "'.$this->cleanInStr($cond).'" '; } } + echo 'sql is: ' . $sql; if($rs = $this->conn->query($sql)){ while($r = $rs->fetch_assoc()){ $retArr[$r['assocID']] = $r; @@ -120,6 +125,7 @@ public function insertAssociation($inputArr){ $paramArr[] = $value; } $sql .= ') VALUES('.trim($sqlValues, ', ').') '; + $insertedRecord = null; if($stmt = $this->conn->prepare($sql)){ $stmt->bind_param($this->typeStr, ...$paramArr); try{ @@ -127,6 +133,19 @@ public function insertAssociation($inputArr){ if($stmt->affected_rows || !$stmt->error){ $this->assocID = $stmt->insert_id; $status = true; + + $fetchSql = 'SELECT * FROM omoccurassociations WHERE assocID = ?'; + if ($fetchStmt = $this->conn->prepare($fetchSql)) { + $fetchStmt->bind_param('i', $this->assocID); + $fetchStmt->execute(); + $result = $fetchStmt->get_result(); + if ($result->num_rows > 0) { + $insertedRecord = $result->fetch_assoc(); + } else { + $this->errorMessage = 'Record not found after insertion.'; + } + $fetchStmt->close(); + } } else $this->errorMessage = $stmt->error; } @@ -139,6 +158,11 @@ public function insertAssociation($inputArr){ } else $this->errorMessage = 'ERROR preparing statement for omoccurassociations insert: '.$this->conn->error; } + + if($status == true){ + $associationManager = new AssociationManager; + $associationManager->createInverseRecord($insertedRecord); + } return $status; } diff --git a/collections/list.php b/collections/list.php index cc5837bd31..c73ecec28f 100644 --- a/collections/list.php +++ b/collections/list.php @@ -3,8 +3,8 @@ if ($LANG_TAG != 'en' && file_exists($SERVER_ROOT . '/content/lang/collections/list.' . $LANG_TAG . '.php')) include_once($SERVER_ROOT . '/content/lang/collections/list.' . $LANG_TAG . '.php'); else include_once($SERVER_ROOT . '/content/lang/collections/list.en.php'); include_once($SERVER_ROOT . '/classes/OccurrenceListManager.php'); +include_once($SERVER_ROOT.'/classes/AssociationManager.php'); header("Content-Type: text/html; charset=" . $CHARSET); -// var_dump($_REQUEST); $taxonFilter = array_key_exists('taxonfilter', $_REQUEST) ? filter_var($_REQUEST['taxonfilter'], FILTER_SANITIZE_NUMBER_INT) : 0; $targetTid = array_key_exists('targettid', $_REQUEST) ? filter_var($_REQUEST['targettid'], FILTER_SANITIZE_NUMBER_INT) : ''; $tabIndex = array_key_exists('tabindex', $_REQUEST) ? filter_var($_REQUEST['tabindex'], FILTER_SANITIZE_NUMBER_INT) : 1; @@ -13,13 +13,23 @@ $datasetid = array_key_exists('datasetid', $_REQUEST) ? filter_var($_REQUEST['datasetid'], FILTER_SANITIZE_NUMBER_INT) : ''; $comingFrom = array_key_exists('comingFrom', $_REQUEST) ? htmlspecialchars($_REQUEST['comingFrom'], HTML_SPECIAL_CHARS_FLAGS) : ''; $_SESSION['datasetid'] = filter_var($datasetid, FILTER_SANITIZE_NUMBER_INT); +$associationManager = new AssociationManager(); +$shouldEstablishInverseRelationshipRecords = array_key_exists('establishInverseRelationshipRecords', $_REQUEST) ? true : false; +if($shouldEstablishInverseRelationshipRecords){ + echo '
Establishing Inverse Relationship Records...
'; + $associationManager->establishInverseRelationshipRecords(); + if($comingFrom === 'search/index.php'){ + header('Location: search/index.php'); + } else{ + header('Location: harvestparams.php'); + } +} + $collManager = new OccurrenceListManager(); $searchVar = $collManager->getQueryTermStr(); -// var_dump($searchVar); if ($targetTid && array_key_exists('mode', $_REQUEST)) $searchVar .= '&mode=voucher&targettid=' . $targetTid; $occurArr = $collManager->getSpecimenMap($pageNumber, $cntPerPage); -// var_dump($occurArr); $SHOULD_INCLUDE_CULTIVATED_AS_DEFAULT = $SHOULD_INCLUDE_CULTIVATED_AS_DEFAULT ?? false; $SHOULD_USE_HARVESTPARAMS = $SHOULD_USE_HARVESTPARAMS ?? false; @@ -66,6 +76,23 @@ }); }); + // function establishInverseRelationshipRecords() { + // console.log('deleteMe got here in establishInverseRelationshipRecords'); + // $.ajax({ + // url: 'list.php', + // type: 'post', + // data: { action: 'establishInverseRelationshipRecords' }, + // success: function(response) { + // console.log('deleteMe success'); + // console.log(response); + // }, + // error: function(xhr, status, error) { + // console.log('deleteMe failure'); + // console.error(xhr.responseText); + // } + // }); + // } + function validateOccurListForm(f) { if (f.targetdatasetid.value == "") { alert(""); @@ -227,6 +254,18 @@ function displayDatasetTools() { if ($associationSearchStr = $collManager->getAssociationSearchStr()) { if (strlen($associationSearchStr) > 300) $associationSearchStr = substr($associationSearchStr, 0, 300) . '... (' . htmlspecialchars($LANG['SHOW_ALL'], ENT_COMPAT | ENT_HTML401 | ENT_SUBSTITUTE) . ')'; // @TODO wouldn't this truncate in either case? echo '
' . $LANG['ASSOCIATIONS'] . ': ' . $associationSearchStr . '
'; + // echo '
' . "Didn't find what you were looking for? Try " . '
' . ". Note that this may take serveral minutes." . '
'; + ?> +
+ Didn't find what you were looking for? +
+ + + +
+ And try your search again. Note that this may take serveral minutes. +
+ getLocalSearchStr()) { echo '
' . $LANG['SEARCH_CRITERIA'] . ': ' . $localSearchStr . '
'; diff --git a/collections/search/index.php b/collections/search/index.php index 86c64cd4be..8ffc82bed7 100644 --- a/collections/search/index.php +++ b/collections/search/index.php @@ -31,6 +31,7 @@ $specArr = (isset($collList['spec'])?$collList['spec']:null); $obsArr = (isset($collList['obs'])?$collList['obs']:null); $associationManager = new AssociationManager(); +$relationshipTypes = $associationManager->getRelationshipTypes(); ?> diff --git a/collections/search/js/searchform.js b/collections/search/js/searchform.js index 15fa4e11fd..f3d950810d 100644 --- a/collections/search/js/searchform.js +++ b/collections/search/js/searchform.js @@ -171,7 +171,6 @@ function addChip(element) { } function handleRemoval(element, inputChip) { - console.log("deleteMe handleRemoval clicked"); element.type === "checkbox" ? (element.checked = false) : (element.value = element.defaultValue); @@ -193,13 +192,6 @@ function handleRemoval(element, inputChip) { collection.checked = false; }); } - // if (element?.getAttribute("id")?.startsWith("materialsampletype")) { - // // if they close a materialsampletype chip, revert to the none option selected - // const targetIndex = document.getElementById( - // "materialsampletype-none" - // ).selectedIndex; - // document.getElementById("materialsampletype").selectedIndex = targetIndex; - // } setAssociationRelationshipTypeToDefault(element); setMaterialSampleToDefault(element); setTaxonTypeToDefault(element); diff --git a/config/schema/3.0/patches/db_schema_patch-3.1.sql b/config/schema/3.0/patches/db_schema_patch-3.1.sql index 84d3cb542d..ed887ae087 100644 --- a/config/schema/3.0/patches/db_schema_patch-3.1.sql +++ b/config/schema/3.0/patches/db_schema_patch-3.1.sql @@ -274,3 +274,5 @@ CREATE TABLE `usersthirdpartyauth` ( ALTER TABLE `omoccurresource` RENAME TO `deprecated_omoccurresource` ; +# We need to relax this if we want inverse relationship entries in omoccurassociations for derivedFromSameIndividual +ALTER TABLE omoccurassociations DROP INDEX UQ_omoccurassoc_sciname, ADD INDEX `UQ_omoccurassoc_sciname` (`occid`, `verbatimSciname`, `associationType`) USING BTREE; \ No newline at end of file diff --git a/content/lang/collections/search/index.es.php b/content/lang/collections/search/index.es.php index 56839f977a..5612ab5847 100644 --- a/content/lang/collections/search/index.es.php +++ b/content/lang/collections/search/index.es.php @@ -115,4 +115,7 @@ $LANG['EXPAND_ALL_SECTIONS'] = 'Expandir todas las secciones'; $LANG['COLLAPSE_ALL_SECTIONS'] = 'Contraer todas las secciones'; $LANG['ASSOCIATIONS'] = 'Asociaciones'; +$LANG['ASSOCIATION_DESCRIPTION'] = 'Encuentre todas las apariciones de taxones que tengan la siguiente asociación'; +$LANG['ASSOCIATION_DESCRIPTION_2'] = 'con el siguiente taxon'; +$LANG['ASSOCIATION_TYPE'] = 'Tipo de asociación'; ?> diff --git a/content/lang/collections/search/index.fr.php b/content/lang/collections/search/index.fr.php index 679b37f1ff..892b06768b 100644 --- a/content/lang/collections/search/index.fr.php +++ b/content/lang/collections/search/index.fr.php @@ -116,5 +116,8 @@ $LANG['EXPAND_ALL_SECTIONS'] = 'Développer toutes les sections'; $LANG['COLLAPSE_ALL_SECTIONS'] = 'Réduire toutes les sections'; $LANG['ASSOCIATIONS'] = 'Les associations'; +$LANG['ASSOCIATION_DESCRIPTION'] = 'Trouver toutes les occurrences de taxons qui ont l\'association suivante'; +$LANG['ASSOCIATION_DESCRIPTION_2'] = 'avec le taxon suivant'; +$LANG['ASSOCIATION_TYPE'] = 'Type d\'association'; ?>