public static function cmp($a, $b)
 {
     if ($a->specimen_id == $b->specimen_id) {
         if ($a->ordering == $b->ordering) {
             return strcmp($a->image_reference, $b->image_reference);
         }
         return $a->ordering < $b->ordering ? -1 : 1;
     }
     return Specimen::cmp($a->getSpecimen(), $b->getSpecimen());
 }
 function testCmp()
 {
     $s1 = Specimen::getOneFromDb(['specimen_id' => 8001], $this->DB);
     $s2 = Specimen::getOneFromDb(['specimen_id' => 8002], $this->DB);
     $this->assertEqual(Specimen::cmp($s1, $s2), -1);
     $this->assertEqual(Specimen::cmp($s1, $s1), 0);
     $this->assertEqual(Specimen::cmp($s2, $s1), 1);
     $sall = Specimen::getAllFromDb([], $this->DB);
     usort($sall, 'Specimen::cmp');
     $this->assertEqual(4, count($sall));
     $this->assertEqual(8001, $sall[0]->specimen_id);
     $this->assertEqual(8003, $sall[1]->specimen_id);
     $this->assertEqual(8002, $sall[2]->specimen_id);
     $this->assertEqual(8004, $sall[3]->specimen_id);
 }
 public static function cmp($a, $b)
 {
     // role, then action, then type, then target
     if ($a->role_id == $b->role_id) {
         if ($a->action_id == $b->action_id) {
             if (Role_Action_Target::$SORT_PRIORITIES_FOR_TYPES[$a->target_type] == Role_Action_Target::$SORT_PRIORITIES_FOR_TYPES[$b->target_type]) {
                 if ($a->target_id == $b->target_id) {
                     return 0;
                 }
                 if ($a->target_id == 0) {
                     return -1;
                 }
                 if ($b->target_id == 0) {
                     return 1;
                 }
                 switch ($a->target_type) {
                     case 'notebook':
                         return Notebook::cmp($a->getTargets()[0], $b->getTargets()[0]);
                         break;
                     case 'metadata_structure':
                         return Metadata_Structure::cmp($a->getTargets()[0], $b->getTargets()[0]);
                         break;
                     case 'plant':
                         return Authoritative_Plant::cmp($a->getTargets()[0], $b->getTargets()[0]);
                         break;
                     case 'specimen':
                         return Specimen::cmp($a->getTargets()[0], $b->getTargets()[0]);
                         break;
                     default:
                         return 0;
                 }
             }
             return Role_Action_Target::$SORT_PRIORITIES_FOR_TYPES[$a->target_type] < Role_Action_Target::$SORT_PRIORITIES_FOR_TYPES[$b->target_type] ? -1 : 1;
         }
         return Action::cmp($a->getAction(), $b->getAction());
     }
     return Role::cmp($a->getRole(), $b->getRole());
 }