(I hope I'm right in calling this a bug--if it's not, I'm happy to re-label as a support request.)

I've installed the File_MARC PEAR library, but am running into an error that I hope somebody can help me figure out. When trying to import from a .mrc file, the import fails (it works when using just the legacy MARC library, though there are some glitches I'm trying to figure out there: I wanted to try using File_MARC to see if htat would address them first).

Checking my logs, the error I get is this:
Call to undefined method File_MARC_Control_Field::getSubfield() in /Applications/MAMP/htdocs/c18booktracker-experimental/sites/all/modules/marc/marc.module on line 331

My first thought was that something might have changed in the File_MARC library (I had installed the latest version), so I rolled back to the version that was current when MARC 6.x-2.0-beta3 was released (back in June). I'm still seeing the problem, however. I'm afraid I'm getting a little lost in all of the different functions that are at work among the various submodules, and can't quite figure out what's breaking. Any pointers would be much appreciated.

Comments

benjamin.pauley’s picture

Hmm... Poking around the documentation at http://pear.php.net/package/File_MARC/docs/latest/File_MARC/File_MARC_Da..., I see that the getSubfield() method is there, rather than in File_MARC_Control_Field. Could that be part of the issue?

dan_scott’s picture

Control fields in MARC don't have subfields, which is why the getSubfields() method is not defined for File_MARC_Control_Field. I don't know what your code or the Drupal code looks like, but I'm guessing it's iterating over every field in the record and blindly trying to grab subfields from them. You need to test to see if the field is an instance of File_MARC_Control_Field or File_MARC_Data_Field first before trying to grab subfields.

aaustin’s picture

Thanks for replying Dan. In a way that sort of makes my day that you responded to this bug report.

You're right, the function calling getSubfields is just a very generic helper function to help mitigate the issue that File_MARC may or may not be installed and is just blindly trying to grab a subfield value.

I'm not sure how I haven't seen this myself but it looks like I was not accounting for control fields and the fix should be pretty easy. Unfortunately, I am overwhelmed at work right now and don't have time to do it immediately.

Here is the code:

function marc_value($marc, $key){
  $field = substr($key, 0, 3);
  $subfield = substr($key, 4, 1);
  if ($marc->record) {
    $record = $marc->record;
    $marcfield = $record->getField($field);
    if ($marcfield){
      $marcsubfield = $marcfield->getSubfield($subfield);
    }
    if ($marcsubfield){
      $value = $marcsubfield->getData();
    }
  }
  elseif ($marc->legacy) {
    $value = $marc->legacy[$field][0][$subfield];
  }
  if ($value){
    return $value;
  }
}

In the meantime, you could probably just hack the module if you needed an immediate fix. I am still figuring out File_MARC but I would think this might work. - Maybe Dan has a better fix? I am assuming I can getData() for a control field but I haven't tried it.

function marc_value($marc, $key){
  $field = substr($key, 0, 3);
  $subfield = substr($key, 4, 1);
  if ($marc->record) {
    $record = $marc->record;
    $marcfield = $record->getField($field);
    if ($subfield){
      if ($marcfield){
        $marcsubfield = $marcfield->getSubfield($subfield);
      }
      if ($marcsubfield){
        $value = $marcsubfield->getData();
      }
    }
    else {
      $value = $marcfield->getData();
    }
  }
  elseif ($marc->legacy) {
    $value = $marc->legacy[$field][0][$subfield];
  }
  if ($value){
    return $value;
  }
}
benjamin.pauley’s picture

Thanks to both of you—I had just finished up a meeting with a student and was turning to working my way through marc.module in an effort to see if I could figure out what was going on (and, as aaustin says, hack the module—though I swear I was going to use this as the occasion to try to learn how to roll a patch!).

This gives me something more to work with, though since I'm trying to teach myself as I go, it could be slow going. I added aaustin's code from #3 and get a new PHP error:
Call to a member function getData() on a non-object

I'll keep looking myself to see what I can find, but if anyone has any ideas, I'd welcome some pointers.

benjamin.pauley’s picture

Oops, spoke too soon: that error arose from a hack I had made to the module. Of course, now I have to figure out *my* mistake, but that's hardly your problem!

My apologies.

dan_scott’s picture

Heh, thank my Google Alert for bringing this to my attention :)

If I understand correctly what you're doing here, try the instanceof operator to determine whether the field you've retrieved is a data field or control field:

function marc_value($marc, $key){
  $field = substr($key, 0, 3);
  $subfield = substr($key, 4, 1);
  if ($marc->record) {
    $record = $marc->record;
    $marcfield = $record->getField($field);
    if ($marcfield instanceof File_MARC_Data_Field){
      $marcsubfield = $marcfield->getSubfield($subfield);
    }
    if ($marcsubfield){
      $value = $marcsubfield->getData();
    }
  }
  elseif ($marc->legacy) {
    $value = $marc->legacy[$field][0][$subfield];
  }
  if ($value){
    return $value;
  }
}

I'm not what you want to have happen if someone calls marc_value() with a control field tag ("008") and a subfield ("a"); you could either ignore the subfield value and just call getData() on the field, or return an error saying "don't do that!".

aaustin’s picture

Oops it looks like I put: $marcfield = $record->getField($field) on the wrong side of the if, so when it tried to $marcfield->getData(), there was no $marcfield.

I fixed it above. Although, it still has not really been tested.