public static function cmp($a, $b)
 {
     if ($a->parent_metadata_structure_id == $b->parent_metadata_structure_id) {
         if ($a->ordering == $b->ordering) {
             if ($a->name == $b->name) {
                 return 0;
             }
             return $a->name < $b->name ? -1 : 1;
         }
         return $a->ordering < $b->ordering ? -1 : 1;
     }
     $lineageA = $a->getLineage();
     $lineageAIds = Db_Linked::arrayOfAttrValues($lineageA, 'metadata_structure_id');
     if (in_array($b->metadata_structure_id, $lineageAIds)) {
         // b is some kind of parent of a, therefore b comes before a, i.e. a > b
         return 1;
     }
     $lineageB = $b->getLineage();
     $lineageBIds = Db_Linked::arrayOfAttrValues($lineageB, 'metadata_structure_id');
     if (in_array($a->metadata_structure_id, $lineageBIds)) {
         // a is some kind of parent of b, therefore a comes before b, i.e. a < b
         return -1;
     }
     //            util_prePrintR($lineageA);
     //            util_prePrintR($lineageB);
     // trim off matching ancestories
     while ($lineageA[0]->metadata_structure_id == $lineageB[0]->metadata_structure_id) {
         array_shift($lineageA);
         array_shift($lineageB);
         //                util_prePrintR($lineageA);
         //                util_prePrintR($lineageB);
     }
     // return the cmp of the first descendents of the point of ancestral divergence
     return Metadata_Structure::cmp($lineageA[0], $lineageB[0]);
 }
 function testCmp()
 {
     $mds1 = Metadata_Structure::getOneFromDb(['metadata_structure_id' => 6001], $this->DB);
     $mds2 = Metadata_Structure::getOneFromDb(['metadata_structure_id' => 6004], $this->DB);
     $this->assertEqual(-1, Metadata_Structure::cmp($mds2, $mds1));
     $this->assertEqual(1, Metadata_Structure::cmp($mds1, $mds2));
     $this->assertEqual(0, Metadata_Structure::cmp($mds2, $mds2));
     $mds3 = Metadata_Structure::getOneFromDb(['metadata_structure_id' => 6002], $this->DB);
     $this->assertEqual(-1, Metadata_Structure::cmp($mds1, $mds3));
     $this->assertEqual(1, Metadata_Structure::cmp($mds3, $mds1));
     $this->assertEqual(-1, Metadata_Structure::cmp($mds2, $mds3));
     $this->assertEqual(1, Metadata_Structure::cmp($mds3, $mds2));
     $mds = Metadata_Structure::getAllFromDb(['parent_metadata_structure_id' => 0], $this->DB);
     usort($mds, 'Metadata_Structure::cmp');
     $this->assertEqual('leaf', $mds[0]->name);
     $this->assertEqual('flower', $mds[1]->name);
 }
 public static function cmp($a, $b)
 {
     if ($a->notebook_page_id == $b->notebook_page_id) {
         if ($a->label_metadata_structure_id == $b->label_metadata_structure_id) {
             if ($a->value_metadata_term_value_id == 0 && $b->value_metadata_term_value_id == 0) {
                 return strcmp($a->value_open, $b->value_open);
             }
             if ($a->value_metadata_term_value_id == 0) {
                 return 1;
             }
             if ($b->value_metadata_term_value_id == 0) {
                 return -1;
             }
             return Metadata_Structure::cmp($a->getMetadataTermValue(), $b->getMetadataTermValue());
         }
         return Metadata_Structure::cmp($a->getMetadataStructure(), $b->getMetadataStructure());
     }
     return Notebook_Page::cmp($a->getNotebookPage(), $b->getNotebookPage());
 }
 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());
 }