Commit 98d9506d authored by David Maus's avatar David Maus
Browse files

Adjust directory structure and coding style

parent 4076f763
.build
dist
.tmp
nbproject
review
vendor
\#*#
.#*#
*~
\#*
.\#*
TAGS
ChangeLog
vendor
review
build
composer.phar
composer.lock
test.php
syntax: glob
.build
.dist
nbproject
review
tmp
vendor
\#*#
.#*#
TAGS
\ No newline at end of file
<project name="local" default="help">
<target name="help">
<echo message="This component has no local build targets." />
</target>
</project>
<!-- vim: set tabstop=2 shiftwidth=2 expandtab: -->
project.name=PicaReader
project.channel=hab20.hab.de/service/pear
project.majorVersion=0
project.minorVersion=1
project.patchLevel=0
project.snapshot=true
component.type=php-library
component.version=11
This diff is collapsed.
{
"name": "hab/picareader",
"description": "Classes for reading Pica+ records encoded in Pica, PicaXML and PicaPlain",
"type": "library",
"license": "GPL-3.0+",
"authors": [
{
"name": "David Maus",
"email": "maus@hab.de",
"role": "Developer"
}
],
"support": {
"email": "maus@hab.de"
},
"repositories": [
{ "type": "vcs", "url": "http://github.com/dmj/PicaRecord"}
],
"require": {
"hab/picarecord": "dev-next"
},
"autoload": {
"psr-0": {
"HAB\\Pica": "src/"
}
}
}
<?xml version="1.0" encoding="UTF-8"?>
<package packagerversion="1.9.1" version="2.0"
xmlns="http://pear.php.net/dtd/package-2.0"
xmlns:tasks="http://pear.php.net/dtd/tasks-1.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0
http://pear.php.net/dtd/tasks-1.0.xsd
http://pear.php.net/dtd/package-2.0
http://pear.php.net/dtd/package-2.0.xsd">
<name>${project.name}</name>
<channel>${project.channel}</channel>
<summary>Classes for reading Pica+ records</summary>
<description>
This package provides classes for reading Pica+ records encoded in
PicaXML or PicaPlain.
</description>
<lead>
<name>David Maus</name>
<user>dmaus</user>
<email>maus@hab.de</email>
<active>yes</active>
</lead>
<date>${build.date}</date>
<time>${build.time}</time>
<version>
<release>${project.version}</release>
<api>${project.majorVersion}.${project.minorVersion}</api>
</version>
<stability>
<release>${project.stability}</release>
<api>stable</api>
</stability>
<license>GNU General Public License v3</license>
<notes>
No notes.
</notes>
<contents>
<dir baseinstalldir="/" name="/">
${contents}
</dir>
</contents>
<dependencies>
<required>
<php>
<min>5.3.0</min>
</php>
<pearinstaller>
<min>1.9.4</min>
</pearinstaller>
<package>
<name>Autoloader</name>
<channel>pear.phix-project.org</channel>
<min>3.0.0</min>
<max>3.999.9999</max>
</package>
<package>
<name>PicaRecord</name>
<channel>hab20.hab.de/service/pear</channel>
<min>0.1.0</min>
<max>0.999.9999</max>
</package>
</required>
</dependencies>
<phprelease />
<changelog>
<release>
<version>
<release>0.1.0</release>
<api>0.1</api>
</version>
<stability>
<release>stable</release>
<api>stable</api>
</stability>
<date>2012-02-15</date>
<license>GNU General Public License v3</license>
<notes>
</notes>
</release>
</changelog>
</package>
<!-- vim: set tabstop=2 shiftwidth=2 expandtab: -->
<?xml version="1.0" encoding="utf-8"?>
<phpunit bootstrap="tests/bootstrap.php" strict="true">
<testsuites>
<testsuite name="Unit Tests">
<directory suffix="Test.php">tests</directory>
</testsuite>
</testsuites>
<filter>
<blacklist>
<directory suffix=".php">vendor</directory>
<directory suffix=".php">tests</directory>
</blacklist>
<whitelist addUncoveredFilesFromWhitelist="true">
<directory suffix=".php">bin</directory>
<directory suffix=".php">src</directory>
</whitelist>
</filter>
<logging>
<log type="coverage-html" target="review/code-coverage"/>
</logging>
</phpunit>
<?xml version="1.0"?>
<phpunit bootstrap="src/tests/unit-tests/bootstrap.php">
<testsuites>
<testsuite name="Unit Tests">
<directory suffix="Test.php">src/tests/unit-tests</directory>
</testsuite>
</testsuites>
<filter>
<blacklist>
<directory suffix=".php">vendor</directory>
<directory suffix=".php">src/tests</directory>
</blacklist>
<whitelist addUncoveredFilesFromWhitelist="true">
<directory suffix=".php">src/bin</directory>
<directory suffix=".php">src/php</directory>
</whitelist>
</filter>
<logging>
<log type="coverage-html" target="review/code-coverage"/>
<log type="coverage-clover" target="review/logs/phpunit.xml"/>
<log type="json" target="review/logs/phpunit.json"/>
<log type="tap" target="review/logs/phpunit.tap"/>
<log type="junit" target="review/logs/phpunit-junit.xml"/>
<log type="testdox-html" target="review/testdox.html"/>
<log type="testdox-text" target="review/testdox.txt"/>
</logging>
</phpunit>
<!-- vim: set tabstop=4 shiftwidth=4 expandtab: -->
......@@ -20,31 +20,27 @@
*
* @package PicaReader
* @author David Maus <maus@hab.de>
* @copyright Copyright (c) 2012 by Herzog August Bibliothek Wolfenbüttel
* @copyright Copyright (c) 2012, 2013 by Herzog August Bibliothek Wolfenbüttel
* @license http://www.gnu.org/licenses/gpl.html GNU General Public License v3
*/
namespace HAB\Pica\Parser;
/**
* Parser for Pica+ records encoded in PicaPlain.
*
* @package PicaReader
* @author David Maus <maus@hab.de>
* @copyright Copyright (c) 2012 by Herzog August Bibliothek Wolfenbüttel
* @license http://www.gnu.org/licenses/gpl.html GNU General Public License v3
*/
use RuntimeException;
class PicaPlainParser
{
/**
* Return array representation of the field encoded in a line.
*
* @throws \RuntimeException Invalid characters in line
* @throws RuntimeException Invalid characters in line
*
* @param string $line PicaPlain record line
* @return array Array representation of the encoded field
* @return array
*/
public static function parseField ($line) {
public static function parseField ($line)
{
$field = array('subfields' => array());
$match = array();
if (preg_match('#^([012][0-9]{2}[A-Z@])(/([0-9]{2}))? (\$.*)$#Du', $line, $match)) {
......@@ -52,7 +48,7 @@ class PicaPlainParser
'occurrence' => $match[3] ?: null,
'subfields' => self::parseSubfields($match[4]));;
} else {
throw new \RuntimeException("Invalid characters in PicaPlain record at line: {$line}");
throw new RuntimeException("Invalid characters in PicaPlain record at line: {$line}");
}
return $field;
}
......@@ -61,9 +57,10 @@ class PicaPlainParser
* Return array of array representations of the subfields encode in argument.
*
* @param string $str Encoded subfields
* @return array Array representions of the encoded subfields
* @return array
*/
public static function parseSubfields ($str) {
public static function parseSubfields ($str)
{
$subfields = array();
$subfield = null;
$pos = 0;
......
......@@ -20,7 +20,7 @@
*
* @package PicaReader
* @author David Maus <maus@hab.de>
* @copyright Copyright (c) 2012 by Herzog August Bibliothek Wolfenbüttel
* @copyright Copyright (c) 2012, 2013 by Herzog August Bibliothek Wolfenbüttel
* @license http://www.gnu.org/licenses/gpl.html GNU General Public License v3
*/
......@@ -28,15 +28,8 @@ namespace HAB\Pica\Reader;
use HAB\Pica\Parser\PicaPlainParser;
/**
* Reader for Pica+ records encoded in PicaPlain.
*
* @package PicaReader
* @author David Maus <maus@hab.de>
* @copyright Copyright (c) 2012 by Herzog August Bibliothek Wolfenbüttel
* @license http://www.gnu.org/licenses/gpl.html GNU General Public License v3
*/
class PicaPlainReader extends Reader {
class PicaPlainReader extends Reader
{
/**
* Current input data.
......@@ -51,19 +44,17 @@ class PicaPlainReader extends Reader {
* @param string $data Input data
* @return void
*/
public function open ($data) {
public function open ($data)
{
parent::open($data);
$this->_data = preg_split("/(?:\n\r|[\n\r])/", $data);
}
/**
* Read the next record in input data.
*
* @see \HAB\Pica\Reader\Reader::next()
*
* @return array|false Array representation of the record or FALSE if no more records
* {@inheritDoc}
*/
protected function next () {
protected function next ()
{
$record = false;
if (current($this->_data) !== false) {
$record = array('fields' => array());
......@@ -81,17 +72,9 @@ class PicaPlainReader extends Reader {
*
* @return void
*/
public function close () {
public function close ()
{
parent::close();
$this->_data = null;
}
/**
* Return the number of the line currently parsed.
*
* @return integer Number of currently parsed line
*/
protected function getCurrentLineNumber () {
return key($this->_data);
}
}
<?php
/**
* The PicaXmlReader class file.
*
* This file is part of PicaReader.
*
* PicaReader is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PicaReader is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with PicaReader. If not, see <http://www.gnu.org/licenses/>.
*
* @package PicaReader
* @author David Maus <maus@hab.de>
* @copyright Copyright (c) 2012 by Herzog August Bibliothek Wolfenbüttel
* @license http://www.gnu.org/licenses/gpl.html GNU General Public License v3
*/
namespace HAB\Pica\Reader;
use XMLReader;
class PicaXmlReader extends Reader
{
/**
* @var string XML namespace URI of PicaXML
*/
const PICAXML_NAMESPACE_URI = 'info:srw/schema/5/picaXML-v1.0';
/**
* @var XMLReader XML Reader instance
*/
private $_xmlReader;
/**
* Constructor.
*
* @return void
*/
public function __construct ()
{
parent::__construct();
$this->_xmlReader = new XMLReader();
}
/**
* Prepare the reader for reading data.
*
* @param string|resource $input
* @return void
*/
public function open ($input)
{
if (is_resource($input)) {
$input = stream_get_contents($input);
}
$this->_xmlReader->XML($input);
parent::open($input);
}
/**
* Close current input data.
*
* @return void
*/
public function close ()
{
$this->_xmlReader->close();
parent::close();
}
/**
* {@inheritDoc}
*/
protected function next ()
{
if ($this->forwardTo('record', self::PICAXML_NAMESPACE_URI)) {
$record = array('fields' => array());
while (!$this->atElementEnd('record', self::PICAXML_NAMESPACE_URI) && $this->_xmlReader->read()) {
if ($this->atElement('datafield', self::PICAXML_NAMESPACE_URI)) {
$record['fields'] []= $this->readField();
}
}
} else {
$record = false;
}
return $record;
}
/**
* Return array representation of datafield at cursor.
*
* The cursor is expected to be positioned on the opening field element.
*
* @return array
*/
protected function readField ()
{
$field = array('tag' => $this->_xmlReader->getAttribute('tag'),
'occurrence' => $this->_xmlReader->getAttribute('occurrence'),
'subfields' => array());
while (!$this->atElementEnd('datafield', self::PICAXML_NAMESPACE_URI) && $this->_xmlReader->read()) {
if ($this->atElement('subfield', self::PICAXML_NAMESPACE_URI)) {
$subfield = array('code' => $this->_xmlReader->getAttribute('code'), 'value' => '');
while (!$this->atElementEnd('subfield', self::PICAXML_NAMESPACE_URI) && $this->_xmlReader->read()) {
switch ($this->_xmlReader->nodeType) {
case XMLReader::TEXT:
case XMLReader::SIGNIFICANT_WHITESPACE:
case XMLReader::CDATA:
$subfield['value'] .= $this->_xmlReader->value;
break;
}
}
$field['subfields'] []= $subfield;
}
}
return $field;
}
/**
* Move cursor forward to named element.
*
* The cursor is not moved if it is already positioned at the named
* element. Returns true if cursor is at specified element and false if
* cursor reached the end of the document
*
* @param string $name Element local name
* @param string $uri Namespace URI
* @return boolean
*/
protected function forwardTo ($name, $uri)
{
while (!$this->atElement($name, $uri) && $this->_xmlReader->read()) { }
return ($this->_xmlReader->nodeType === XMLReader::ELEMENT);
}
/**
* Return true if the cursor is positioned at the named element.
*
* @param string $name Element local name
* @param string $uri Namespace URI
* @return boolean
*/
protected function atElement ($name, $uri)
{
return ($this->_xmlReader->nodeType === XMLReader::ELEMENT &&
$this->_xmlReader->localName === $name &&
$this->_xmlReader->namespaceURI === $uri);
}
/**
* Return TRUE if the cursor is positioned at the end of the named element.
*
* @param string $name Element local name
* @param string $uri Namespace URI
* @return boolean
*/
protected function atElementEnd ($name, $uri)
{
return ($this->_xmlReader->nodeType === XMLReader::END_ELEMENT &&
$this->_xmlReader->localName === $name &&
$this->_xmlReader->namespaceURI === $uri);
}
}
<?php
/**
* The Reader class file.
*
* This file is part of PicaReader.
*
* PicaReader is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PicaReader is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with PicaReader. If not, see <http://www.gnu.org/licenses/>.
*
* @package PicaReader
* @author David Maus <maus@hab.de>
* @copyright Copyright (c) 2012, 2013 by Herzog August Bibliothek Wolfenbüttel
* @license http://www.gnu.org/licenses/gpl.html GNU General Public License v3
*/
namespace HAB\Pica\Reader;
use Exception;
use RuntimeException;
use HAB\Pica\Record\Record;
abstract class Reader
{
/**
* TRUE if the reader was opened with input data.
*
* @var boolean
*/
protected $_isOpen = false;
/**
* Filter function or NULL if none set.
*
* @see Reader::setFilter()
*
* @var callback|null
*/
protected $_filter = null;
/**
* Constructor.
*
* @return void
*/
public function __construct ()
{}
/**
* Open the reader with input data.
*
* @return void
*/
public function open ($data)
{
if ($this->isOpen()) {
$this->close();
}
$this->_isOpen = true;
}
/**
* Return next record in input data or FALSE if no more records.
*
* This function uses the Record::factory() method to create a record and
* applies a possible filter function to the input data.
*
* @see Reader::setFilter()
* @see Record::factory()
*
* @throws RuntimeException Error creating a record instance via factory function
* @return Record|false
*/
public function read ()
{
$record = $this->next();
if (is_array($record)) {
$record = $this->applyFilter($record);
if (is_array($record)) {
try {
return Record::factory($record);
} catch (Exception $e) {
throw new RuntimeException("Error creating record instance in Record::factory()", -1, $e);
}
}
}
return false;
}
/**
* Set a filter function.
*
* A filter function is every valid callback function that takes the array
* representation of a record as only argument and returns a possibly