Skip to content

Commit 7aa315e

Browse files
committed
Refactor Record into different types
Create separate classes for bibliographic, holdings and authority so we can add different support methods.
1 parent 84e9b0c commit 7aa315e

File tree

11 files changed

+301
-123
lines changed

11 files changed

+301
-123
lines changed

src/AuthorityRecord.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?php
2+
3+
namespace Scriptotek\Marc;
4+
5+
class AuthorityRecord extends Record
6+
{
7+
8+
}

src/BibliographicRecord.php

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
<?php
2+
3+
namespace Scriptotek\Marc;
4+
5+
use Scriptotek\Marc\Fields\Isbn;
6+
use Scriptotek\Marc\Fields\Subject;
7+
use Scriptotek\Marc\Fields\SubjectInterface;
8+
use Scriptotek\Marc\Fields\Title;
9+
10+
class BibliographicRecord extends Record
11+
{
12+
/**
13+
* Get the descriptive cataloging form value from LDR/18. Returns any of
14+
* the constants Marc21::NON_ISBD, Marc21::AACR2, Marc21::ISBD_PUNCTUATION_OMITTED,
15+
* Marc21::ISBD_PUNCTUATION_INCLUDED, Marc21::NON_ISBD_PUNCTUATION_OMITTED
16+
* or Marc21::UNKNOWN_CATALOGING_FORM.
17+
*
18+
* @return string
19+
* @throws UnknownRecordType
20+
*/
21+
public function getCatalogingForm()
22+
{
23+
$leader = $this->record->getLeader();
24+
return substr($leader, 18, 1);
25+
}
26+
27+
/*************************************************************************
28+
* Helper methods for specific fields. Each of these are supported by
29+
* a class in src/Fields/
30+
*************************************************************************/
31+
32+
/**
33+
* Get an array of the 020 fields as `Isbn` objects.
34+
*
35+
* @return Isbn[]
36+
*/
37+
public function getIsbns()
38+
{
39+
return Isbn::get($this);
40+
}
41+
42+
/**
43+
* Get the 245 field as a `Title` object. Returns null if no such field was found.
44+
*
45+
* @return Title
46+
*/
47+
public function getTitle()
48+
{
49+
return Title::get($this);
50+
}
51+
52+
/**
53+
* Get an array of the 6XX fields as `SubjectInterface` objects, optionally
54+
* filtered by vocabulary and/or tag.
55+
*
56+
* @param string $vocabulary
57+
* @param string|string[] $tag
58+
* @return SubjectInterface[]
59+
*/
60+
public function getSubjects($vocabulary = null, $tag = null)
61+
{
62+
$tag = is_null($tag) ? [] : (is_array($tag) ? $tag : [$tag]);
63+
64+
return array_values(array_filter(Subject::get($this), function (SubjectInterface $subject) use ($vocabulary, $tag) {
65+
$a = is_null($vocabulary) || $vocabulary == $subject->getVocabulary();
66+
$b = empty($tag) || in_array($subject->getType(), $tag);
67+
68+
return $a && $b;
69+
}));
70+
}
71+
}

src/Collection.php

Lines changed: 67 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
namespace Scriptotek\Marc;
44

5+
use File_MARC_Record;
6+
use Scriptotek\Marc\Exceptions\UnknownRecordType;
57
use Scriptotek\Marc\Importers\Importer;
68

79
class Collection implements \Iterator
@@ -48,6 +50,45 @@ public static function fromString($data)
4850
return $importer->fromString($data);
4951
}
5052

53+
/**
54+
* Determines if a record is a bibliographic, holdings or authority record.
55+
*
56+
* @param File_MARC_Record $record
57+
* @return string
58+
*/
59+
public static function getRecordType(File_MARC_Record $record)
60+
{
61+
$leader = $record->getLeader();
62+
$recordType = substr($leader, 6, 1);
63+
64+
switch ($recordType) {
65+
case 'a': // Language material
66+
case 'c': // Notated music
67+
case 'd': // Manuscript notated music
68+
case 'e': // Cartographic material
69+
case 'f': // Manuscript cartographic material
70+
case 'g': // Projected medium
71+
case 'i': // Nonmusical sound recording
72+
case 'j': // Musical sound recording
73+
case 'k': // Two-dimensional nonprojectable graphic
74+
case 'm': // Computer file
75+
case 'o': // Kit
76+
case 'p': // Mixed materials
77+
case 'r': // Three-dimensional artifact or naturally occurring object
78+
case 't': // Manuscript language material
79+
return Marc21::BIBLIOGRAPHIC;
80+
case 'z':
81+
return Marc21::AUTHORITY;
82+
case 'u': // Unknown
83+
case 'v': // Multipart item holdings
84+
case 'x': // Single-part item holdings
85+
case 'y': // Serial item holdings
86+
return Marc21::HOLDINGS;
87+
default:
88+
throw new UnknownRecordType();
89+
}
90+
}
91+
5192
/**
5293
* Returns an array representation of the collection.
5394
*
@@ -58,6 +99,31 @@ public function toArray()
5899
return iterator_to_array($this);
59100
}
60101

102+
/**
103+
* Creates a Record object from a File_MARC_Record object.
104+
*
105+
* @param File_MARC_Record $record
106+
* @return AuthorityRecord|BibliographicRecord|HoldingsRecord
107+
*/
108+
public function recordFactory(File_MARC_Record $record)
109+
{
110+
try {
111+
$recordType = self::getRecordType($record);
112+
} catch (UnknownRecordType $e) {
113+
return new Record($record);
114+
}
115+
switch ($recordType) {
116+
case Marc21::BIBLIOGRAPHIC:
117+
return new BibliographicRecord($record);
118+
119+
case Marc21::HOLDINGS:
120+
return new HoldingsRecord($record);
121+
122+
case Marc21::AUTHORITY:
123+
return new AuthorityRecord($record);
124+
}
125+
}
126+
61127
/*********************************************************
62128
* Iterator
63129
*********************************************************/
@@ -85,7 +151,7 @@ public function next()
85151
} else {
86152
$rec = isset($this->parser) ? $this->parser->next() : null;
87153
if ($rec) {
88-
$rec = new Record($rec);
154+
$rec = $this->recordFactory($rec);
89155
$this->_records[] = $rec;
90156
}
91157
}

src/Fields/Field.php

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,13 +36,36 @@ public function __get($key)
3636
}
3737
}
3838

39+
/**
40+
* Return concatenated string of the given subfields.
41+
*
42+
* @param string[] $codes
43+
* @param string $glue
44+
* @return string
45+
*/
46+
protected function toString($codes, $glue = ' ')
47+
{
48+
$parts = [];
49+
foreach ($this->field->getSubfields() as $sf) {
50+
if (in_array($sf->getCode(), $codes)) {
51+
$parts[] = trim($sf->getData());
52+
}
53+
}
54+
55+
return trim(implode($glue, $parts));
56+
}
57+
3958
/**
4059
* Return the data value of the *first* subfield with a given code.
4160
*/
4261
public function sf($code)
4362
{
44-
$x = $this->getSubfield($code);
45-
return $x->getData();
63+
$subfield = $this->getSubfield($code);
64+
if (!$subfield) {
65+
return null;
66+
}
67+
68+
return trim($subfield->getData());
4669
}
4770

4871
public static function makeFieldObject(Record $record, $tag, $pcre=false)

src/Fields/Isbn.php

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,7 @@ class Isbn extends Field implements FieldInterface
88
{
99
public function __toString()
1010
{
11-
$a = $this->field->getSubfield('a');
12-
if (!$a) {
13-
return '';
14-
}
15-
16-
return $a->getData();
11+
return $this->sf('a');
1712
}
1813

1914
public static function get(Record $record)

src/Fields/Subject.php

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -80,20 +80,9 @@ public function getControlNumber()
8080
return $value ?: null;
8181
}
8282

83-
public function getParts()
84-
{
85-
$parts = [];
86-
foreach ($this->field->getSubfields() as $c) {
87-
if (in_array($c->getCode(), ['a', 'b', 'x', 'y', 'z'])) {
88-
$parts[] = $c->getData();
89-
}
90-
}
91-
return $parts;
92-
}
93-
9483
public function getTerm()
9584
{
96-
return implode(self::$glue, $this->getParts());
85+
return $this->toString(['a', 'b', 'x', 'y', 'z'], self::$glue);
9786
}
9887

9988
public function __toString()

src/HoldingsRecord.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?php
2+
3+
namespace Scriptotek\Marc;
4+
5+
class HoldingsRecord extends Record
6+
{
7+
8+
}

src/Record.php

Lines changed: 3 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,6 @@
77
use Scriptotek\Marc\Exceptions\RecordNotFound;
88
use Scriptotek\Marc\Exceptions\UnknownRecordType;
99
use Scriptotek\Marc\Fields\ControlField;
10-
use Scriptotek\Marc\Fields\Isbn;
11-
use Scriptotek\Marc\Fields\Subject;
12-
use Scriptotek\Marc\Fields\SubjectInterface;
13-
use Scriptotek\Marc\Fields\Title;
1410

1511
/**
1612
* The MARC record wrapper.
@@ -42,7 +38,7 @@ public function __construct(File_MARC_Record $record)
4238
* Returns the first record found in the file $filename, or null if no records found.
4339
*
4440
* @param $filename
45-
* @return Record
41+
* @return BibliographicRecord|HoldingsRecord|AuthorityRecord
4642
* @throws RecordNotFound
4743
*/
4844
public static function fromFile($filename)
@@ -60,7 +56,7 @@ public static function fromFile($filename)
6056
* Returns the first record found in the string $data, or null if no records found.
6157
*
6258
* @param $data
63-
* @return Record
59+
* @return BibliographicRecord|HoldingsRecord|AuthorityRecord
6460
* @throws RecordNotFound
6561
*/
6662
public static function fromString($data)
@@ -101,50 +97,7 @@ public function query($spec)
10197
*/
10298
public function getType()
10399
{
104-
$leader = $this->record->getLeader();
105-
$recordType = substr($leader, 6, 1);
106-
107-
switch ($recordType) {
108-
case 'a': // Language material
109-
case 'c': // Notated music
110-
case 'd': // Manuscript notated music
111-
case 'e': // Cartographic material
112-
case 'f': // Manuscript cartographic material
113-
case 'g': // Projected medium
114-
case 'i': // Nonmusical sound recording
115-
case 'j': // Musical sound recording
116-
case 'k': // Two-dimensional nonprojectable graphic
117-
case 'm': // Computer file
118-
case 'o': // Kit
119-
case 'p': // Mixed materials
120-
case 'r': // Three-dimensional artifact or naturally occurring object
121-
case 't': // Manuscript language material
122-
return Marc21::BIBLIOGRAPHIC;
123-
case 'z':
124-
return Marc21::AUTHORITY;
125-
case 'u': // Unknown
126-
case 'v': // Multipart item holdings
127-
case 'x': // Single-part item holdings
128-
case 'y': // Serial item holdings
129-
return Marc21::HOLDINGS;
130-
default:
131-
throw new UnknownRecordType();
132-
}
133-
}
134-
135-
/**
136-
* Get the descriptive cataloging form value from LDR/18. Returns any of
137-
* the constants Marc21::NON_ISBD, Marc21::AACR2, Marc21::ISBD_PUNCTUATION_OMITTED,
138-
* Marc21::ISBD_PUNCTUATION_INCLUDED, Marc21::NON_ISBD_PUNCTUATION_OMITTED
139-
* or Marc21::UNKNOWN_CATALOGING_FORM.
140-
*
141-
* @return string
142-
* @throws UnknownRecordType
143-
*/
144-
public function getCatalogingForm()
145-
{
146-
$leader = $this->record->getLeader();
147-
return substr($leader, 18, 1);
100+
return Collection::getRecordType($this->record);
148101
}
149102

150103
/*************************************************************************
@@ -162,46 +115,6 @@ public function getId()
162115
return ControlField::get($this, '001');
163116
}
164117

165-
/**
166-
* Get an array of the 020 fields as `Isbn` objects.
167-
*
168-
* @return Isbn[]
169-
*/
170-
public function getIsbns()
171-
{
172-
return Isbn::get($this);
173-
}
174-
175-
/**
176-
* Get the 245 field as a `Title` object. Returns null if no such field was found.
177-
*
178-
* @return Title
179-
*/
180-
public function getTitle()
181-
{
182-
return Title::get($this);
183-
}
184-
185-
/**
186-
* Get an array of the 6XX fields as `SubjectInterface` objects, optionally
187-
* filtered by vocabulary and/or tag.
188-
*
189-
* @param string $vocabulary
190-
* @param string|string[] $tag
191-
* @return SubjectInterface[]
192-
*/
193-
public function getSubjects($vocabulary = null, $tag = null)
194-
{
195-
$tag = is_null($tag) ? [] : (is_array($tag) ? $tag : [$tag]);
196-
197-
return array_values(array_filter(Subject::get($this), function (SubjectInterface $subject) use ($vocabulary, $tag) {
198-
$a = is_null($vocabulary) || $vocabulary == $subject->getVocabulary();
199-
$b = empty($tag) || in_array($subject->getType(), $tag);
200-
201-
return $a && $b;
202-
}));
203-
}
204-
205118
/*************************************************************************
206119
* Support methods
207120
*************************************************************************/

0 commit comments

Comments
 (0)