Skip to content

Commit cc13c00

Browse files
committed
Initial commit
0 parents  commit cc13c00

32 files changed

+10756
-0
lines changed

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
composer.lock
2+
vendor

.styleci.yml

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
preset: psr2
2+
3+
enabled:
4+
- long_array_syntax
5+
- concat_with_spaces
6+

.travis.yml

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
language: php
2+
3+
php:
4+
- 5.3
5+
- 5.4
6+
- 5.5
7+
- 5.6
8+
- 5.7
9+
- hhvm
10+
11+
before_script:
12+
- composer install --dev -o -n
13+
14+
script:
15+
- vendor/bin/phpunit --testdox # --coverage-clover build/logs/clover.xml
16+
17+
# after_script:
18+
# - php vendor/bin/coveralls -v

README.md

+94
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
# scriptotek/marc
2+
3+
This is a small package that provides a simple interface to parsing
4+
MARC records using the [File_MARC package](https://github.com/pear/File_MARC).
5+
6+
The package has only been tested with XML encoded MARC 21.
7+
It should likely support everything File_MARC supports, but that
8+
remains to be tested.
9+
10+
## Installation using Composer:
11+
12+
```
13+
composer require scriptotek/marc dev-master
14+
```
15+
16+
## Usage examples
17+
18+
### Records from a file or string
19+
20+
```php
21+
use Scriptotek\Marc\Collection;
22+
23+
$collection = Collection::fromFile($someFileName);
24+
foreach ($collection->records as $record) {
25+
echo $record->getField('250')->getSubfield('a') . "\n";
26+
}
27+
```
28+
It should detect if the data is Binary MARC or XML.
29+
If you have the data as a string, use
30+
`Collection::fromFile()` instead.
31+
32+
### Records from SRU/OAI-PMH response
33+
34+
The package makes it easy to handle records from an SRU or OAI/PMH response.
35+
36+
```php
37+
$response = file_get_contents('http://lx2.loc.gov:210/NLSBPH?' . http_build_query(array(
38+
'operation' => 'searchRetrieve',
39+
'version' => '1.1',
40+
'query' => 'dc.publisher=CNIB%20AND%20dc.date=2005',
41+
'maximumRecords' => '10',
42+
'recordSchema' => 'marcxml'
43+
));
44+
45+
$collection = Collection::fromSruResponse($response);
46+
foreach ($collection->records as $record) {
47+
echo $record->getField('250')->getSubfield('a') . "\n";
48+
}
49+
50+
```
51+
52+
### Using MARC spec
53+
54+
To easily look up a MARC (sub)field, you can use the MARC spec syntax provided
55+
by the [php-marc-spec package](https://github.com/MARCspec/php-marc-spec):
56+
57+
```php
58+
use Scriptotek\Marc\Collection;
59+
60+
$collection = Collection::from($someMarcDataOrFile);
61+
62+
foreach ($collection->records as $record) {
63+
echo $record->get('250$a');
64+
}
65+
```
66+
67+
### Convenience methods for handling common fields
68+
69+
The `Record` class has been extended with a few convenience methods to make
70+
handling of everyday tasks easier, in the spirit of
71+
[pymarc](https://github.com/edsu/pymarc). These generally make some
72+
assumptions, for instance that a compound subject string should be joined using
73+
a colon character.
74+
These assumptions may or may not meet *your* expectations. You should inspect
75+
the relevant field class before using it.
76+
77+
```php
78+
use Scriptotek\Marc\Record;
79+
80+
$source = '<?xml version="1.0" encoding="UTF-8" ?>
81+
<record xmlns="info:lc/xmlns/marcxchange-v1">
82+
<leader>99999cam a2299999 u 4500</leader>
83+
<controlfield tag="001">98218834x</controlfield>
84+
<datafield tag="020" ind1=" " ind2=" ">
85+
<subfield code="a">8200424421</subfield>
86+
<subfield code="q">h.</subfield>
87+
<subfield code="c">Nkr 98.00</subfield>
88+
</datafield>
89+
</record>';
90+
91+
$record = Record::from($source);
92+
echo $record->isbns[0];
93+
94+
```

composer.json

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
{
2+
"name": "scriptotek/marc",
3+
"type": "library",
4+
"description": "Simple interface to parsing MARC records using File_MARC",
5+
"keywords": ["marc"],
6+
"license": "GNU-LGPL",
7+
"authors": [
8+
{
9+
"name": "Dan Michael O. Heggø",
10+
"email": "[email protected]"
11+
}
12+
],
13+
"repositories": [{
14+
"type": "pear",
15+
"url": "http://pear.php.net"
16+
}],
17+
"minimum-stability": "dev",
18+
"require": {
19+
"php": ">=5.3",
20+
"ck/File_MARC_Reference": "dev-master",
21+
"pear-pear.php.net/File_MARC": "*",
22+
"pear-pear.php.net/validate_ispn": "*",
23+
"pear/pear_exception": "1.0.0"
24+
},
25+
"require-dev": {
26+
"phpunit/phpunit": "3.7.*",
27+
"satooshi/php-coveralls": "~0.6"
28+
},
29+
"autoload": {
30+
"psr-4": {
31+
"Scriptotek\\Marc\\": "src/"
32+
}
33+
},
34+
"scripts": {
35+
"test": "phpunit"
36+
}
37+
}

phpunit.xml

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<phpunit bootstrap="vendor/autoload.php" colors="true" stopOnError="true" stopOnFailure="false">
2+
<testsuites>
3+
<testsuite name="TestSuite">
4+
<directory>tests/</directory>
5+
</testsuite>
6+
</testsuites>
7+
</phpunit>

src/Collection.php

+73
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
<?php
2+
3+
namespace Scriptotek\Marc;
4+
5+
use Scriptotek\Marc\Importers\Importer;
6+
use Scriptotek\Marc\Importers\OaiPmhResponse;
7+
use Scriptotek\Marc\Importers\SruResponse;
8+
9+
class Collection
10+
{
11+
12+
protected $parser;
13+
protected $_records;
14+
15+
public static function fromFile($filename)
16+
{
17+
$importer = new Importer($filename, true);
18+
return $importer->getCollection();
19+
}
20+
21+
public static function fromString($data)
22+
{
23+
$importer = new Importer($data, false);
24+
return $importer->getCollection();
25+
}
26+
27+
public static function fromOaiPmhResponse($data)
28+
{
29+
$importer = new OaiPmhResponse($data);
30+
return $importer->getCollection();
31+
}
32+
33+
public static function fromSruResponse($data)
34+
{
35+
$importer = new SruResponse($data);
36+
return $importer->getCollection();
37+
}
38+
39+
function __construct(\Factory $factory = null)
40+
{
41+
$this->factory = $factory ?: new Factory();
42+
}
43+
44+
public function parse($source, $isXml, $ns = '', $isPrefix = true)
45+
{
46+
if ($isXml) {
47+
$this->parser = $this->factory->make('File_MARCXML', $source, \File_MARCXML::SOURCE_STRING, $ns, $isPrefix);
48+
} else {
49+
$this->parser = $this->factory->make('File_MARC', $source, \File_MARC::SOURCE_STRING);
50+
}
51+
52+
}
53+
54+
public function __get($key='')
55+
{
56+
if ($key == 'records') {
57+
// re-instantiaces..
58+
if (is_null($this->parser)) {
59+
return array();
60+
}
61+
if (is_null($this->_records)) {
62+
$this->_records = new Records($this->parser);
63+
}
64+
return $this->_records;
65+
}
66+
}
67+
68+
public function __call($name, $arguments)
69+
{
70+
return call_user_func_array(array($this->parser, $name), $arguments);
71+
}
72+
73+
}

src/Factory.php

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?php
2+
3+
namespace Scriptotek\Marc;
4+
5+
class Factory
6+
{
7+
8+
protected function _make($className, $args)
9+
{
10+
$reflectionClass = new \ReflectionClass($className);
11+
$instance = $reflectionClass->newInstanceArgs($args);
12+
return $instance;
13+
}
14+
15+
public function make()
16+
{
17+
$args = func_get_args();
18+
$className = array_shift($args);
19+
return $this->_make($className, $args);
20+
}
21+
22+
public function makeField()
23+
{
24+
$args = func_get_args();
25+
$className = 'Scriptotek\\Marc\\Fields\\' . array_shift($args);
26+
return $this->_make($className, $args);
27+
}
28+
29+
}

src/Fields/Field.php

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
3+
namespace Scriptotek\Marc\Fields;
4+
5+
class Field {
6+
7+
protected $field;
8+
9+
public function __construct(\File_MARC_Field $field)
10+
{
11+
$this->field = $field;
12+
}
13+
14+
public function __call($name, $args)
15+
{
16+
return call_user_func_array(array($this->field, $name), $args);
17+
}
18+
19+
public function __get($key)
20+
{
21+
$method = 'get' . ucfirst($key);
22+
if (method_exists($this, $method)) {
23+
return call_user_func(array($this, $method));
24+
}
25+
// TODO: Throw something!
26+
}
27+
28+
}

src/Fields/Isbn.php

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?php
2+
3+
namespace Scriptotek\Marc\Fields;
4+
5+
class Isbn extends Field {
6+
7+
public function __toString()
8+
{
9+
$a = $this->field->getSubfield('a');
10+
if (!$a) {
11+
return null;
12+
}
13+
14+
// TODO: Other subfields?
15+
return $a->getData();
16+
}
17+
18+
}

src/Fields/Subject.php

+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<?php
2+
3+
namespace Scriptotek\Marc\Fields;
4+
5+
class Subject extends Field {
6+
7+
public $stringGlue = ' : ';
8+
9+
protected $vocabularies = [
10+
'0' => 'lcsh', // 0: Library of Congress Subject Headings
11+
'1' => 'lccsh', // 1: LC subject headings for children's literature
12+
'2' => 'mesh', // 2: Medical Subject Headings
13+
'3' => 'atg', // 3: National Agricultural Library subject authority file (?)
14+
// 4: Source not specified
15+
'5' => 'cash', // 5: Canadian Subject Headings
16+
'6' => 'rvm', // 6: Répertoire de vedettes-matière
17+
// 7: Source specified in subfield $2
18+
];
19+
20+
public function getVocabulary()
21+
{
22+
$ind2 = $this->field->getIndicator(2);
23+
$sf2 = $this->field->getSubfield('2');
24+
if (isset($this->vocabularies[$ind2])) {
25+
return $this->vocabularies[$ind2];
26+
}
27+
if ($sf2) {
28+
return $sf2->getData();
29+
}
30+
return null;
31+
}
32+
33+
public function __toString()
34+
{
35+
$parts = [];
36+
foreach ($this->field->getSubfields() as $c) {
37+
if (in_array($c->getCode(), ['a', 'b', 'x', 'y', 'z'])) {
38+
$parts[] = $c->getData();
39+
}
40+
}
41+
return implode($this->stringGlue, $parts);
42+
}
43+
44+
}

src/Fields/Title.php

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?php
2+
3+
namespace Scriptotek\Marc\Fields;
4+
5+
class Title extends Field {
6+
7+
public function __toString()
8+
{
9+
$a = $this->field->getSubfield('a');
10+
if (!$a) {
11+
return null;
12+
}
13+
$a = $a->getData();
14+
15+
// TODO:
16+
// foreach ($this->field->getSubfields('b') as $b) {
17+
18+
// }
19+
20+
return $a;
21+
}
22+
23+
}

0 commit comments

Comments
 (0)