phpnuxbill/system/autoload/PEAR2/Net/RouterOS/Query.php
2017-03-11 02:51:06 +07:00

267 lines
8.4 KiB
PHP

<?php
/**
* RouterOS API client implementation.
*
* RouterOS is the flag product of the company MikroTik and is a powerful router software. One of its many abilities is to allow control over it via an API. This package provides a client for that API, in turn allowing you to use PHP to control RouterOS hosts.
*
* PHP version 5
*
* @category Net
* @package PEAR2_Net_RouterOS
* @author Vasil Rangelov <boen.robot@gmail.com>
* @copyright 2011 Vasil Rangelov
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @version 1.0.0b5
* @link http://pear2.php.net/PEAR2_Net_RouterOS
*/
/**
* The namespace declaration.
*/
namespace PEAR2\Net\RouterOS;
/**
* Refers to transmitter direction constants.
*/
use PEAR2\Net\Transmitter as T;
/**
* Represents a query for RouterOS requests.
*
* @category Net
* @package PEAR2_Net_RouterOS
* @author Vasil Rangelov <boen.robot@gmail.com>
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @link http://pear2.php.net/PEAR2_Net_RouterOS
*/
class Query
{
/**
* Checks if the property exists.
*/
const OP_EX = '';
/**
* Checks if the property does not exist.
*/
const OP_NEX = '-';
/**
* Checks if the property equals a certain value.
*/
const OP_EQ = '=';
/**
* Checks if the property is less than a certain value.
*/
const OP_LT = '<';
/**
* Checks if the property is greather than a certain value.
*/
const OP_GT = '>';
/**
* @var array An array of the words forming the query. Each value is an
* array with the first member being the predicate (operator and name),
* and the second member being the value for the predicate.
*/
protected $words = array();
/**
* This class is not to be instantiated normally, but by static methods
* instead. Use {@link static::where()} to create an instance of it.
*/
private function __construct()
{
}
/**
* Sanitizes the operator of a condition.
*
* @param string $operator The operator to sanitize.
*
* @return string The sanitized operator.
*/
protected static function sanitizeOperator($operator)
{
$operator = (string) $operator;
switch ($operator) {
case Query::OP_EX:
case Query::OP_NEX:
case Query::OP_EQ:
case Query::OP_LT:
case Query::OP_GT:
return $operator;
default:
throw new UnexpectedValueException(
'Unknown operator specified',
UnexpectedValueException::CODE_ACTION_UNKNOWN,
null,
$operator
);
}
}
/**
* Creates a new query with an initial condition.
*
* @param string $name The name of the property to test.
* @param string|resource|null $value Value of the property as a string
* or seekable stream. Not required for existence tests.
* If a seekable stream is provided, it is sent from its current
* posistion to its end, and the pointer is seeked back to its current
* position after sending.
* Non seekable streams, as well as all other types, are casted to a
* string.
* @param string $operator One of the OP_* constants.
* Describes the operation to perform.
*
* @return static A new query object.
*/
public static function where(
$name,
$value = null,
$operator = self::OP_EX
) {
$query = new static;
return $query->addWhere($name, $value, $operator);
}
/**
* Negates the query.
*
* @return $this The query object.
*/
public function not()
{
$this->words[] = array('#!', null);
return $this;
}
/**
* Adds a condition as an alternative to the query.
*
* @param string $name The name of the property to test.
* @param string|resource|null $value Value of the property as a string
* or seekable stream. Not required for existence tests.
* If a seekable stream is provided, it is sent from its current
* posistion to its end, and the pointer is seeked back to its current
* position after sending.
* Non seekable streams, as well as all other types, are casted to a
* string.
* @param string $operator One of the OP_* constants.
* Describes the operation to perform.
*
* @return $this The query object.
*/
public function orWhere($name, $value = null, $operator = self::OP_EX)
{
$this->addWhere($name, $value, $operator)->words[] = array('#|', null);
return $this;
}
/**
* Adds a condition in addition to the query.
*
* @param string $name The name of the property to test.
* @param string|resource|null $value Value of the property as a string
* or seekable stream. Not required for existence tests.
* If a seekable stream is provided, it is sent from its current
* posistion to its end, and the pointer is seeked back to its current
* position after sending.
* Non seekable streams, as well as all other types, are casted to a
* string.
* @param string $operator One of the OP_* constants.
* Describes the operation to perform.
*
* @return $this The query object.
*/
public function andWhere($name, $value = null, $operator = self::OP_EX)
{
$this->addWhere($name, $value, $operator)->words[] = array('#&', null);
return $this;
}
/**
* Sends the query over a communicator.
*
* @param Communicator $com The communicator to send the query over.
*
* @return int The number of bytes sent.
*/
public function send(Communicator $com)
{
if ($com->getTransmitter()->isPersistent()) {
$old = $com->getTransmitter()->lock(T\Stream::DIRECTION_SEND);
$bytes = $this->_send($com);
$com->getTransmitter()->lock($old, true);
return $bytes;
}
return $this->_send($com);
}
/**
* Sends the query over a communicator.
*
* The only difference with the non private equivalent is that this one does
* not do locking.
*
* @param Communicator $com The communicator to send the query over.
*
* @return int The number of bytes sent.
*/
private function _send(Communicator $com)
{
if (!$com->getTransmitter()->isAcceptingData()) {
throw new SocketException(
'Transmitter is invalid. Sending aborted.',
SocketException::CODE_QUERY_SEND_FAIL
);
}
$bytes = 0;
foreach ($this->words as $queryWord) {
list($predicate, $value) = $queryWord;
$prefix = '?' . $predicate;
if (null === $value) {
$bytes += $com->sendWord($prefix);
} else {
$prefix .= '=';
if (is_string($value)) {
$bytes += $com->sendWord($prefix . $value);
} else {
$bytes += $com->sendWordFromStream($prefix, $value);
}
}
}
return $bytes;
}
/**
* Adds a condition.
*
* @param string $name The name of the property to test.
* @param string|resource|null $value Value of the property as a string
* or seekable stream. Not required for existence tests.
* If a seekable stream is provided, it is sent from its current
* posistion to its end, and the pointer is seeked back to its current
* position after sending.
* Non seekable streams, as well as all other types, are casted to a
* string.
* @param string $operator One of the ACTION_* constants.
* Describes the operation to perform.
*
* @return $this The query object.
*/
protected function addWhere($name, $value, $operator)
{
$this->words[] = array(
static::sanitizeOperator($operator)
. Message::sanitizeAttributeName($name),
(null === $value ? null : Message::sanitizeAttributeValue($value))
);
return $this;
}
}