Skip to content

Commit

Permalink
Simplified taxonomy traversal, added tests for incomplete records.
Browse files Browse the repository at this point in the history
  • Loading branch information
woodb committed Oct 19, 2014
1 parent 773221d commit 3c23ff4
Show file tree
Hide file tree
Showing 6 changed files with 204 additions and 32 deletions.
4 changes: 4 additions & 0 deletions src/API/Object.php
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@ public function __get( $key ) {
&& !is_null( $this->_cache->{ $key } ) )
return $this->_cache->$key;

// Special case for the PBDB ID
if ( $key == 'pbdbid' )
return $this->parameters->id;

// If not a local property, try loading from PBDB
if ( is_null( $this->properties->{ $key } ) )
$this->load( $this->properties->block( $key ) );
Expand Down
23 changes: 8 additions & 15 deletions src/FossilOccurence.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ public function __construct() {
*/
public function __get( $key ) {
$p = parent::__get( $key );
if ( !in_array( $key, array( 'taxon', 'genus', 'kingdom', 'phylum',
'class', 'order', 'family' ) ) ) {
if ( !in_array( $key, array( 'taxon', 'species', 'genus', 'kingdom',
'phylum', 'class', 'order', 'family' ) ) ) {
if ( !is_null( $p ) ) {
return $p;
}
Expand All @@ -54,26 +54,19 @@ public function __get( $key ) {
case 'reidentification':
return self::factory( $this->properties->reid_no );
break;
case 'species':
return $this->properties->species_name;
break;
case 'taxon':
if ( property_exists( $this->_cache, 'taxon' ) )
return $this->_cache->taxon;
$this->_cache->taxon = Taxon::factory( $this->taxon_no );
return $this->_cache->taxon;
case 'species':
case 'genus':
$_key = !isset( $_key ) ? 'taxon_no' : $_key;
case 'kingdom':
$_key = !isset( $_key ) ? 'kingdom_no' : $_key;
case 'phylum':
$_key = !isset( $_key ) ? 'phylum_no' : $_key;
case 'class':
$_key = !isset( $_key ) ? 'class_no' : $_key;
case 'order':
$_key = !isset( $_key ) ? 'order_no' : $_key;
case 'family':
$_key = !isset( $_key ) ? 'family_no' : $_key;
return Taxon::factory( $this->properties->$_key );
break;
default:
throw new \DomainException( 'Invalid property ' . $key );
return $this->taxon->{ $key };
}

return null;
Expand Down
27 changes: 12 additions & 15 deletions src/Taxon.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@ public function __construct() {
*/
public function __get( $key ) {
$p = parent::__get( $key );
if ( !in_array( $key, array( 'taxon', 'genus', 'kingdom', 'phylum',
'class', 'order', 'family' ) ) ) {
if ( !in_array( $key, array( 'taxon', 'species', 'genus', 'kingdom',
'phylum', 'class', 'order', 'family' ) ) ) {
if ( !is_null( $p ) ) {
return $p;
}
Expand Down Expand Up @@ -74,7 +74,10 @@ public function __get( $key ) {
case 'genus':
if ( $this->rank == 'species' )
return $this->parent;
return $this;
elseif ( $this->rank == 'genus' )
return $this;
else
return null;
case 'order':
$_key = !isset( $_key ) ? 'order_no' : $_key;
case 'kingdom':
Expand All @@ -94,20 +97,14 @@ public function __get( $key ) {
* returned a cached object if we had one to offer, so we're
* making a new one and returning it.
*/
if ( !property_exists( $this->_cache, $key ) ) {
$this->_cache->{ $key } = self::factory( $this->{ $_key }
);
return $this->_cache->{ $key };
} else {
return $this->_cache->{ $key };
}
if ( !$this->{ $_key } ) return null;

// We couldn't find what we were looking for, exit.
return null;
if ( !property_exists( $this->_cache, $key ) )
$this->_cache->{ $key } = self::factory( $this->{ $_key } );

if ( property_exists( $this->_cache, $key ) )
return $this->_cache->{ $key };

break;
default:
throw new \DomainException( 'Invalid property ' . $key );
break;
}

Expand Down
57 changes: 57 additions & 0 deletions tests/FossilOccurenceTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,63 @@ public function testAbstractedRetrieveData() {
$this->assertContains( "Brachiopoda", $fossil->phylum->name );
$this->assertContains( "Wellerella", $fossil->genus->name );
$this->assertContains( "Wellerella", $fossil->taxon->name );

$data = array(
'taxon' => "Pinocetus polonicus",
'species' => "Pinocetus polonicus",
'genus' => "Pinocetus",
'family' => "Aglaocetidae",
'order' => "Cetacea",
'class' => "Mammalia",
'phylum' => "Chordata",
'kingdom' => "Metazoa",
);

$fossil = FossilOccurence::factory( 147937 );

foreach ( $data as $lvl => $taxon_name ) {
$expected = $taxon_name;
$observed = $fossil->{ $lvl }->name;
$this->assertEquals( $expected, $observed );
}
}

public function testIncompleteTaxa() {
$fossil_data_json = file_get_contents( 'tests/data/fossils-incomplete-taxa.json' );
$fossil_data = json_decode( $fossil_data_json );

$valid_ranks = array( 'species', 'genus', 'family', 'order', 'class',
'phylum', 'kingdom' );

// These are occurrence_no's that should probably be pointed out to
// PBDB as being anomalous in how their taxonomy is being calculated.
$exclude_ids = array( 461074, 462836 );

foreach ( $fossil_data as $fossil_datum ) {
$rank = $fossil_datum->taxon_rank;
$rank_no = array_search( $rank, $valid_ranks );
$fossil_no = (int) $fossil_datum->occurrence_no;

// Skip taxon ranks that we do not support
if ( !in_array( $rank, $valid_ranks )
|| in_array( $fossil_no, $exclude_ids )
|| $rank == 'species'
|| $rank == 'kingdom' )
continue;

$rank_child = $valid_ranks[ ( $rank_no - 1 ) ];
$rank_parent = $valid_ranks[ ( $rank_no + 1 ) ];
$taxon_no = (int) $fossil_datum->taxon_no;


$f = FossilOccurence::factory( $fossil_no );
$this->assertEquals( $rank, $f->taxon->rank );
$this->assertEquals( $taxon_no, $f->taxon_no );
$this->assertEquals( $taxon_no, $f->taxon->pbdbid );
$this->assertNull( $f->taxon->{ $rank_child } );
$this->assertNotNull( $f->taxon->{ $rank_parent } );
}

}

}
3 changes: 1 addition & 2 deletions tests/TaxonTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,6 @@ public function testFactory() {
$this->assertEquals( $taxon->name, "Pinocetus polonicus" );
}

/**
*/
public function testHierarchy() {
// from {@link http://paleobiodb.org/data1.1/taxa/single.json?id=53140}
$data = array(
Expand All @@ -84,4 +82,5 @@ public function testHierarchy() {
}

}

}
122 changes: 122 additions & 0 deletions tests/data/fossils-incomplete-taxa.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
[
{
"occurrence_no": 187702,
"taxon_rank": "genus",
"taxon_name": "Pomatodelphis cf. sp.",
"taxon_no": 36819
},
{
"occurrence_no": 289579,
"taxon_rank": "genus",
"taxon_name": "Squalodon ? sp.",
"taxon_no": 36852
},
{
"occurrence_no": 371205,
"taxon_rank": "family",
"taxon_name": "Delphinidae indet.",
"taxon_no": 42953
},
{
"occurrence_no": 395326,
"taxon_rank": "family",
"taxon_name": "Cetotheriidae indet.",
"taxon_no": 42973
},
{
"occurrence_no": 460978,
"taxon_rank": "subfamily",
"taxon_name": "Physeterinae indet.",
"taxon_no": 62911
},
{
"occurrence_no": 460984,
"taxon_rank": "family",
"taxon_name": "Kentriodontidae indet.",
"taxon_no": 42938
},
{
"occurrence_no": 460985,
"taxon_rank": "family",
"taxon_name": "Physeteridae indet.",
"taxon_no": 42967
},
{
"occurrence_no": 460989,
"taxon_rank": "suborder",
"taxon_name": "Odontoceti indet.",
"taxon_no": 42937
},
{
"occurrence_no": 460991,
"taxon_rank": "family",
"taxon_name": "Ziphiidae indet.",
"taxon_no": 42951
},
{
"occurrence_no": 460993,
"taxon_rank": "family",
"taxon_name": "Pontoporiidae indet.",
"taxon_no": 42965
},
{
"occurrence_no": 460994,
"taxon_rank": "family",
"taxon_name": "Delphinidae indet.",
"taxon_no": 42953
},
{
"occurrence_no": 461048,
"taxon_rank": "genus",
"taxon_name": "Scaldicetus sp.",
"taxon_no": 36728
},
{
"occurrence_no": 461074,
"taxon_rank": "genus",
"taxon_name": "Scaldicetus sp.",
"taxon_no": 36900
},
{
"occurrence_no": 462836,
"taxon_rank": "family",
"taxon_name": "Eurhinodelphinidae indet.",
"taxon_no": 53264
},
{
"occurrence_no": 462855,
"taxon_rank": "family",
"taxon_name": "Delphinidae indet.",
"taxon_no": 42953
},
{
"occurrence_no": 463341,
"taxon_rank": "order",
"taxon_name": "Cetacea indet.",
"taxon_no": 36652
},
{
"occurrence_no": 464110,
"taxon_rank": "subfamily",
"taxon_name": "Pomatodelphininae indet.",
"taxon_no": 63630
},
{
"occurrence_no": 464111,
"taxon_rank": "subfamily",
"taxon_name": "Platanistinae indet.",
"taxon_no": 63585
},
{
"occurrence_no": 464112,
"taxon_rank": "family",
"taxon_name": "Platanistidae indet.",
"taxon_no": 42941
},
{
"occurrence_no": 464113,
"taxon_rank": "suborder",
"taxon_name": "Odontoceti indet.",
"taxon_no": 42937
}
]

0 comments on commit 3c23ff4

Please sign in to comment.