diff --git a/src/Client.php b/src/Client.php index ecb9d31..df7c434 100644 --- a/src/Client.php +++ b/src/Client.php @@ -143,7 +143,7 @@ class Client implements Interfaces\ClientInterface { // By default response is empty $response = []; - // We have to wait a !done or !fatal + // We have to wait a !done or !fatal $lastReply = false; // Read answer from socket in loop @@ -177,6 +177,16 @@ class Client implements Interfaces\ClientInterface } /** + * Read using Iterators to improve performance on large dataset + * + * @return \RouterOS\ResponseIterator + */ + public function readAsIterator(): ResponseIterator + { + return new ResponseIterator($this); + } + + /** * This method was created by memory save reasons, it convert response * from RouterOS to readable array in safe way. * @@ -226,7 +236,7 @@ class Client implements Interfaces\ClientInterface * @param array $response Response data * @return array Array with parsed data */ - protected function parseResponse(array $response): array + public function parseResponse(array $response): array { $result = []; $i = -1; diff --git a/src/Interfaces/ClientInterface.php b/src/Interfaces/ClientInterface.php index a87e4c6..c6e4dba 100644 --- a/src/Interfaces/ClientInterface.php +++ b/src/Interfaces/ClientInterface.php @@ -58,7 +58,7 @@ interface ClientInterface * @param bool $parse * @return mixed */ - public function read(bool $parse = true); + public function read(bool $parse); /** * Send write query to RouterOS (with or without tag) diff --git a/src/ResponseIterator.php b/src/ResponseIterator.php new file mode 100644 index 0000000..6654d50 --- /dev/null +++ b/src/ResponseIterator.php @@ -0,0 +1,210 @@ +rewind(); + + // Save client as parameter of object + $this->client = $client; + + // Read RAW data from client + $raw = $client->read(false); + + // This RAW should't be an error + $positions = array_keys($raw, '!re'); + $count = count($raw); + $result = []; + + if (isset($positions[1])) { + + foreach ($positions as $key => $position) { + + // Get length of future block + $length = isset($positions[$key + 1]) + ? $positions[$key + 1] - $position + 1 + : $count - $position; + + // Convert array to simple items, save as result + $result[] = array_slice($raw, $position, $length); + } + + } else { + $result = [$raw]; + } + + $this->raw = $result; + } + + /** + * Move forward to next element + */ + public function next() + { + ++$this->current; + } + + /** + * Return the current element + * + * @return mixed + */ + public function current() + { + if (isset($this->parsed[$this->current])) { + return $this->parsed[$this->current]; + } + + if (isset($this->raw[$this->current])) { + return $this->client->parseResponse($this->raw[$this->current])[0]; + } + + return null; + } + + /** + * Return the key of the current element + * + * @return mixed + */ + public function key() + { + return $this->current; + } + + /** + * Checks if current position is valid + * + * @return bool + */ + public function valid(): bool + { + return isset($this->raw[$this->current]); + } + + /** + * Count elements of an object + * + * @return int + */ + public function count(): int + { + return count($this->raw); + } + + /** + * Rewind the Iterator to the first element + */ + public function rewind() + { + $this->current = 0; + } + + /** + * Offset to set + * + * @param mixed $offset + * @param mixed $value + */ + public function offsetSet($offset, $value) + { + if (null === $offset) { + $this->parsed[] = $value; + } else { + $this->parsed[$offset] = $value; + } + } + + /** + * Whether a offset exists + * + * @param mixed $offset + * @return bool + */ + public function offsetExists($offset): bool + { + return isset($this->raw[$offset]) && $this->raw[$offset] !== ['!re']; + } + + /** + * Offset to unset + * + * @param mixed $offset + */ + public function offsetUnset($offset) + { + unset($this->parsed[$offset], $this->raw[$offset]); + } + + /** + * Offset to retrieve + * + * @param mixed $offset + * @return bool|mixed + */ + public function offsetGet($offset) + { + if (isset($this->parsed[$offset])) { + return $this->parsed[$offset]; + } + + if (isset($this->raw[$offset]) && $this->raw[$offset] !== null) { + $f = $this->client->parseResponse($this->raw[$offset]); + if ($f !== []) { + return $this->parsed[$offset] = $f[0]; + } + } + + return false; + } +}