Fix "Fatal error: Interface 'Icinga\Data\DatasourceInterface' not found in Icinga\Protocol\File\Reader"

fixes #6722
This commit is contained in:
Alexander Klimov 2014-07-21 14:14:13 +02:00
parent c5ecbf250d
commit cebd71b2ff
1 changed files with 130 additions and 232 deletions

View File

@ -4,44 +4,92 @@
namespace Icinga\Protocol\File;
use Exception;
use Icinga\Data\DatasourceInterface;
use FilterIterator;
use Iterator;
use Zend_Config;
use Icinga\Protocol\File\FileReaderException;
use Icinga\Util\File;
/**
* Class Reader
*
* Read file line by line
*
* @package Icinga\Protocol\File
*/
class Reader implements DatasourceInterface
class Reader extends FilterIterator
{
private static $EOLLen = null;
/**
* Name of the file to read
* A PCRE string with the fields to extract from the file's lines as named subpatterns
*
* @var string
*/
private $filename;
protected $fields;
/**
* Configuration for this Datasource
* An associative array of the current line's fields ($field => $value)
*
* @var \Zend_Config
* @var array
*/
private $config;
protected $currentData;
/**
* @param \Zend_Config $config
* Create a new reader
*
* @param Zend_Config $config
*
* @throws FileReaderException If a required $config directive (filename or fields) is missing
*/
public function __construct($config)
public function __construct(Zend_Config $config)
{
if (self::$EOLLen === null) {
self::$EOLLen = strlen(PHP_EOL);
foreach (array('filename', 'fields') as $key) {
if (! isset($config->{$key})) {
throw new FileReaderException('The directive `' . $key . '\' is required');
}
}
$this->config = $config;
$this->filename = $config->filename;
$this->fields = $config->fields;
$f = new File($config->filename);
$f->setFlags(
File::DROP_NEW_LINE |
File::READ_AHEAD |
File::SKIP_EMPTY
);
parent::__construct($f);
}
/**
* Return the current data
*
* @return array
*/
public function current()
{
return $this->currentData;
}
/**
* Accept lines matching the given PCRE pattern
*
* @return bool
*
* @throws FileReaderException If PHP failed parsing the PCRE pattern
*/
public function accept()
{
$data = array();
$matched = @preg_match(
$this->fields,
$this->getInnerIterator()->current(),
$data
);
if ($matched === false) {
throw new FileReaderException('Failed parsing regular expression!');
} else if ($matched === 1) {
foreach ($data as $key) {
if (is_int($key)) {
unset($data[$key]);
}
}
$this->currentData = $data;
return true;
}
return false;
}
/**
@ -54,10 +102,22 @@ class Reader implements DatasourceInterface
return new Query($this);
}
/**
* Return the number of available valid lines.
*
* @return int
*/
public function count()
{
return iterator_count($this);
}
/**
* Fetch result as an array of objects
*
* @return array
* @param Query $query
*
* @return array
*/
public function fetchAll(Query $query)
{
@ -68,10 +128,52 @@ class Reader implements DatasourceInterface
return $all;
}
/**
* Fetch result as a key/value pair array
*
* @param Query $query
*
* @return array
*/
public function fetchPairs(Query $query)
{
$skipLines = $query->getOffset();
$readLines = $query->getLimit();
if ($skipLines === null) {
$skipLines = 0;
}
$lines = array();
if ($query->sortDesc()) {
$count = $this->count($query);
if ($count <= $skipLines) {
return $lines;
} else if ($count < ($skipLines + $readLines)) {
$readLines = $count - $skipLines;
$skipLines = 0;
} else {
$skipLines = $count - ($skipLines + $readLines);
}
}
foreach ($this as $index => $line) {
if ($index >= $skipLines) {
if ($index >= $skipLines + $readLines) {
break;
}
$lines[] = $line;
}
}
if ($query->sortDesc()) {
$lines = array_reverse($lines);
}
return $lines;
}
/**
* Fetch first result row
*
* @return object
* @param Query $query
*
* @return object
*/
public function fetchRow(Query $query)
{
@ -85,7 +187,9 @@ class Reader implements DatasourceInterface
/**
* Fetch first result column
*
* @return array
* @param Query $query
*
* @return array
*/
public function fetchColumn(Query $query)
{
@ -102,7 +206,9 @@ class Reader implements DatasourceInterface
/**
* Fetch first column value from first result row
*
* @return mixed
* @param Query $query
*
* @return mixed
*/
public function fetchOne(Query $query)
{
@ -114,212 +220,4 @@ class Reader implements DatasourceInterface
}
return null;
}
/**
* Fetch result as a key/value pair array
*
* @return array
*/
public function fetchPairs(Query $query)
{
return $this->read($query);
}
/**
* If given $line matches the $query's PCRE pattern and contains all the strings in the $query's filters array,
* return an associative array of the matches of the PCRE pattern.
* Otherwise, return false.
* If preg_match returns false, it failed parsing the PCRE pattern.
* In that case, throw an exception.
*
* @param string $line
* @param Query $query
*
* @return array|bool
*
* @throws \Exception
*/
public function validateLine($line, Query $query)
{
$data = array();
$PCREResult = @preg_match($this->config->fields, $line, $data);
if ($PCREResult === false) {
throw new Exception('Failed parsing regular expression!');
} else if ($PCREResult === 1) {
foreach ($query->getFilters() as $filter) {
if (strpos($line, $filter) === false) {
return false;
}
}
foreach ($data as $key => $value) {
if (is_int($key)) {
unset($data[$key]);
}
}
return $data;
}
return false;
}
/**
* Skip and read as many lines as needed according to given $query.
*
* @param Query $query
*
* @return array result
*/
public function read(Query $query)
{
$skipLines = $query->getOffset();
$readLines = $query->getLimit();
if ($skipLines === null) {
$skipLines = 0;
}
return $this->{$query->sortDesc() ? 'readFromEnd' : 'readFromStart'}($skipLines, $readLines, $query);
}
/**
* Backend for $this->read
* Direction: LIFO
*/
public function readFromEnd($skipLines, $readLines, Query $query)
{
$lines = array();
$s = '';
$f = @fopen($this->filename, 'rb');
if ($f !== false) {
$buffer = '';
fseek($f, 0, SEEK_END);
if (ftell($f) === 0) {
return array();
}
while ($readLines === null || count($lines) < $readLines) {
$c = $this->fgetc($f, $buffer);
if ($c === false) {
$l = $this->validateLine($s, $query);
if (!($l === false || $skipLines)) {
$lines[] = $l;
}
break;
}
$s = $c . $s;
if (strpos($s, PHP_EOL) === 0) {
$l = $this->validateLine((string)substr($s, self::$EOLLen), $query);
if ($l !== false) {
if ($skipLines) {
$skipLines--;
} else {
$lines[] = $l;
}
}
$s = '';
}
}
}
return $lines;
}
/**
* Backend for $this->readFromEnd
*/
public function fgetc($file, &$buffer)
{
$strlen = strlen($buffer);
if ($strlen === 0) {
$pos = ftell($file);
if ($pos === 0) {
return false;
}
if ($pos < 4096) {
fseek($file, 0);
$buffer = fread($file, $pos);
fseek($file, 0);
} else {
fseek($file, -4096, SEEK_CUR);
$buffer = fread($file, 4096);
fseek($file, -4096, SEEK_CUR);
}
return $this->fgetc($file, $buffer);
} else {
$char = substr($buffer, -1);
$buffer = substr($buffer, 0, $strlen - 1);
return $char;
}
}
/**
* Backend for $this->read
* Direction: FIFO
*/
public function readFromStart($skipLines, $readLines, Query $query)
{
$lines = array();
$s = '';
$f = @fopen($this->filename, 'rb');
if ($f !== false) {
$buffer = '';
while ($readLines === null || count($lines) < $readLines) {
if (strlen($buffer) === 0) {
$buffer = fread($f, 4096);
if (strlen($buffer) === 0) {
$l = $this->validateLine($s, $query);
if (!($l === false || $skipLines)) {
$lines[] = $l;
}
break;
}
}
$s .= substr($buffer, 0, 1);
$buffer = substr($buffer, 1);
if (strpos($s, PHP_EOL) !== false) {
$l = $this->validateLine((string)substr($s, 0, strlen($s) - self::$EOLLen), $query);
if ($l !== false) {
if ($skipLines) {
$skipLines--;
} else {
$lines[] = $l;
}
}
$s = '';
}
}
}
return $lines;
}
/**
* Return the number of available valid lines.
*
* @param Query $query
*
* @return int
*/
public function count(Query $query) {
$lines = 0;
$s = '';
$f = @fopen($this->filename, 'rb');
if ($f !== false) {
$buffer = '';
while (true) {
if (strlen($buffer) === 0) {
$buffer = fread($f, 4096);
if (strlen($buffer) === 0) {
if ($this->validateLine($s, $query) !== false) {
$lines++;
}
break;
}
}
$s .= substr($buffer, 0, 1);
$buffer = substr($buffer, 1);
if (strpos($s, PHP_EOL) !== false) {
if ($this->validateLine((string)substr($s, 0, strlen($s) - self::$EOLLen), $query) !== false) {
$lines++;
}
$s = '';
}
}
}
return $lines;
}
}