Skip to content

Commit 6a2c88f

Browse files
committed
refactor: Replace Record::get with Record::query [BC]
Breaking change: Replace `Record::get()` with `Record::query()`, which returns a `QueryResult` object rather than an array of strings. This allows access to the marc fields / subfields matched by the query.
1 parent 11c58ce commit 6a2c88f

File tree

4 files changed

+220
-11
lines changed

4 files changed

+220
-11
lines changed

README.md

Lines changed: 41 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -54,21 +54,55 @@ foreach ($collection->records as $record) {
5454

5555
```
5656

57-
## Querying with MARC spec
57+
If you only have a single record, you can also use `Record::fromFile` or
58+
`Record::fromString`. These use the `Collection` methods under the hood,
59+
but returns a single `Record` object.
5860

59-
Using the `Record::get()` method you can query a record using the MARC spec
60-
syntax provided by the [php-marc-spec package](https://github.com/MARCspec/php-marc-spec):
6161

6262
```php
63-
use Scriptotek\Marc\Collection;
63+
use Scriptotek\Marc\Record;
64+
65+
$record = Record::fromFile($someFileName);
66+
```
6467

65-
$collection = Collection::fromFile($someMarcFile);
68+
## Querying with MARCspec
6669

67-
foreach ($collection->records as $record) {
68-
echo $record->get('250$a');
70+
Use the `Record::query()` method to query a record using the
71+
[MARCspec](http://marcspec.github.io/) language as implemented in the
72+
[php-marc-spec package](https://github.com/MARCspec/php-marc-spec) package.
73+
The method returns a `QueryResult` object, which is a small wrapper around
74+
`File_MARC_Reference`.
75+
76+
Example: To loop over all `650` fields having `$2 noubomn`:
77+
78+
```php
79+
foreach ($record->query('650{2=\noubomn}') as $field) {
80+
echo $field->getSubfield('a')->getData();
6981
}
7082
```
7183

84+
or we could reference the subfield directly, like so:
85+
86+
```php
87+
foreach ($record->query('650$a{2=\noubomn}') as $subfield) {
88+
echo $subfield->getData();
89+
}
90+
```
91+
92+
You can retrieve single results using `first()`, which returns the first match,
93+
or `null` if no matches were found:
94+
95+
```php
96+
$record->query('250$a')->first();
97+
```
98+
99+
In the same way, `text()` returns the data content of the first match, or `null`
100+
if no matches were found:
101+
102+
```php
103+
$record->query('250$a')->text();
104+
```
105+
72106
## Convenience methods on the Record class
73107

74108
The `Record` class of File_MARC has been extended with a few

src/QueryResult.php

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
<?php
2+
3+
namespace Scriptotek\Marc;
4+
5+
use ArrayAccess;
6+
use ArrayIterator;
7+
use Countable;
8+
use File_MARC_Reference;
9+
use IteratorAggregate;
10+
use Traversable;
11+
12+
class QueryResult implements IteratorAggregate, ArrayAccess, Countable
13+
{
14+
protected $ref;
15+
16+
/**
17+
* QueryResult constructor.
18+
* @param File_MARC_Reference $spec
19+
*/
20+
public function __construct(File_MARC_Reference $ref)
21+
{
22+
$this->ref = $ref;
23+
}
24+
25+
public function getReference()
26+
{
27+
return $this->ref;
28+
}
29+
30+
/**
31+
* Get the first result (field or subfield), or null if no results.
32+
*
33+
* @return File_MARC_Field|File_MARC_Subfield|null
34+
*/
35+
public function first()
36+
{
37+
return isset($this->ref->data[0]) ? $this->ref->data[0] : null;
38+
}
39+
40+
/**
41+
* Get the text content of the first result, or null if no results.
42+
*
43+
* @return string
44+
*/
45+
public function text()
46+
{
47+
return isset($this->ref->content[0]) ? $this->ref->content[0] : null;
48+
}
49+
50+
/**
51+
* Retrieve an external iterator
52+
* @link http://php.net/manual/en/iteratoraggregate.getiterator.php
53+
* @return Traversable
54+
*/
55+
public function getIterator()
56+
{
57+
return new ArrayIterator($this->ref->data);
58+
}
59+
60+
/**
61+
* Whether a offset exists
62+
* @link http://php.net/manual/en/arrayaccess.offsetexists.php
63+
* @param mixed $offset An offset to check for.
64+
* @return boolean true on success or false on failure.
65+
*/
66+
public function offsetExists($offset)
67+
{
68+
return isset($this->ref->data[$offset]);
69+
}
70+
71+
/**
72+
* Offset to retrieve
73+
* @link http://php.net/manual/en/arrayaccess.offsetget.php
74+
* @param mixed $offset The offset to retrieve.
75+
* @return File_MARC_Field|File_MARC_Subfield
76+
*/
77+
public function offsetGet($offset)
78+
{
79+
return $this->ref->data[$offset];
80+
}
81+
82+
/**
83+
* Offset to set
84+
* @link http://php.net/manual/en/arrayaccess.offsetset.php
85+
* @param mixed $offset The offset to assign the value to.
86+
* @param mixed $value The value to set.
87+
*/
88+
public function offsetSet($offset, $value)
89+
{
90+
$this->ref->data[$offset] = $value;
91+
}
92+
93+
/**
94+
* Offset to unset
95+
* @link http://php.net/manual/en/arrayaccess.offsetunset.php
96+
* @param mixed $offset The offset to unset.
97+
*/
98+
public function offsetUnset($offset)
99+
{
100+
unset($this->ref->data[$offset]);
101+
}
102+
103+
/**
104+
* Count elements of an object
105+
* @link http://php.net/manual/en/countable.count.php
106+
* @return int The number of results
107+
*/
108+
public function count()
109+
{
110+
return count($this->ref->data[$offset]);
111+
}
112+
}

src/Record.php

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
namespace Scriptotek\Marc;
44

5+
use File_MARC_Reference;
6+
57
class Record
68
{
79
protected $record;
@@ -143,11 +145,13 @@ protected function makeField($model, \File_MARC_Field $field)
143145
return $this->factory->makeField($model, $field);
144146
}
145147

146-
public function get($spec)
148+
/**
149+
* @param string $spec The MARCspec string
150+
* @return QueryResult
151+
*/
152+
public function query($spec)
147153
{
148-
$reference = new \File_MARC_Reference($spec, $this->record);
149-
150-
return $reference->content ?: array();
154+
return new QueryResult(new File_MARC_Reference($spec, $this->record));
151155
}
152156

153157
public function __call($name, $args)

tests/QueryResultTest.php

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
<?php
2+
3+
use Scriptotek\Marc\Record;
4+
use Scriptotek\Marc\QueryResult;
5+
6+
class QueryResultTest extends \PHPUnit_Framework_TestCase
7+
{
8+
9+
protected $record;
10+
11+
public function setUp()
12+
{
13+
$this->record = Record::fromString('<?xml version="1.0" encoding="UTF-8" ?>
14+
<record xmlns="http://www.loc.gov/MARC21/slim">
15+
<leader>99999cam a2299999 u 4500</leader>
16+
<controlfield tag="001">98218834x</controlfield>
17+
<datafield tag="020" ind1=" " ind2=" ">
18+
<subfield code="a">8200424421</subfield>
19+
<subfield code="q">h.</subfield>
20+
<subfield code="c">Nkr 98.00</subfield>
21+
</datafield>
22+
<datafield tag="020" ind1=" " ind2=" ">
23+
<subfield code="a">9788200424420</subfield>
24+
<subfield code="q">ib.</subfield>
25+
</datafield>
26+
</record>');
27+
}
28+
29+
public function testInitialization()
30+
{
31+
$result = $this->record->query('020');
32+
$this->assertInstanceOf(QueryResult::class, $result);
33+
}
34+
35+
public function testFirstField()
36+
{
37+
$result = $this->record->query('020{$a}')->first();
38+
$this->assertInstanceOf('File_MARC_Field', $result);
39+
}
40+
41+
public function testFirstSubfield()
42+
{
43+
$result = $this->record->query('020$a')->first();
44+
$this->assertInstanceOf('File_MARC_Subfield', $result);
45+
}
46+
47+
public function testText()
48+
{
49+
$result = $this->record->query('020$a')->text();
50+
$this->assertEquals('8200424421', $result);
51+
}
52+
53+
public function testTextPattern()
54+
{
55+
$result = $this->record->query('020$a{$q=\ib.}')->text();
56+
$this->assertEquals('9788200424420', $result);
57+
}
58+
59+
}

0 commit comments

Comments
 (0)