Passed
Push — develop ( ead434...0a8e77 )
by Vasil
03:53
created

Query::__debugInfo()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * ~~summary~~
5
 *
6
 * ~~description~~
7
 *
8
 * PHP version 5
9
 *
10
 * @category  Net
11
 * @package   PEAR2_Net_RouterOS
12
 * @author    Vasil Rangelov <[email protected]>
13
 * @copyright 2011 Vasil Rangelov
14
 * @license   http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
15
 * @version   GIT: $Id$
16
 * @link      http://pear2.php.net/PEAR2_Net_RouterOS
17
 */
18
/**
19
 * The namespace declaration.
20
 */
21
namespace PEAR2\Net\RouterOS;
22
23
/**
24
 * Refers to transmitter direction constants.
25
 */
26
use PEAR2\Net\Transmitter as T;
27
28
/**
29
 * Represents a query for RouterOS requests.
30
 *
31
 * @category Net
32
 * @package  PEAR2_Net_RouterOS
33
 * @author   Vasil Rangelov <[email protected]>
34
 * @license  http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
35
 * @link     http://pear2.php.net/PEAR2_Net_RouterOS
36
 */
37
class Query
38
{
39
40
    /**
41
     * Checks if the property exists.
42
     */
43
    const OP_EX = '';
44
45
    /**
46
     * Checks if the property does not exist.
47
     */
48
    const OP_NEX = '-';
49
50
    /**
51
     * Checks if the property equals a certain value.
52
     */
53
    const OP_EQ = '=';
54
55
    /**
56
     * Checks if the property is less than a certain value.
57
     */
58
    const OP_LT = '<';
59
60
    /**
61
     * Checks if the property is greater than a certain value.
62
     */
63
    const OP_GT = '>';
64
65
    /**
66
     * An array of the words forming the query.
67
     *
68
     * Each value is an array with the first member being the predicate
69
     * (operator and name), and the second member being the value
70
     * for the predicate.
71
     *
72
     * @var array<string,string|null>[]
73
     */
74
    protected $words = array();
75
76
    /**
77
     * This class is not to be instantiated normally, but by static methods
78
     * instead. Use {@link static::where()} to create an instance of it.
79
     */
80
    protected function __construct()
81
    {
82
    }
83
84
    /**
85
     * Sanitizes the operator of a condition.
86
     *
87
     * @param string $operator The operator to sanitize.
88
     *
89
     * @return string The sanitized operator.
90
     */
91
    protected static function sanitizeOperator($operator)
92
    {
93
        $operator = (string) $operator;
94
        switch ($operator) {
95
        case Query::OP_EX:
96
        case Query::OP_NEX:
97
        case Query::OP_EQ:
98
        case Query::OP_LT:
99
        case Query::OP_GT:
100
            return $operator;
101
        default:
102
            throw new UnexpectedValueException(
103
                'Unknown operator specified',
104
                UnexpectedValueException::CODE_ACTION_UNKNOWN,
105
                null,
106
                $operator
107
            );
108
        }
109
    }
110
111
    /**
112
     * Creates a new query with an initial condition.
113
     *
114
     * @param string               $name     The name of the property to test.
115
     * @param string|resource|null $value    Value of the property as a string
116
     *     or seekable stream. Not required for existence tests.
117
     *     If a seekable stream is provided, it is sent from its current
118
     *     position to its end, and the pointer is seeked back to its current
119
     *     position after sending.
120
     *     Non seekable streams, as well as all other types, are casted to a
121
     *     string.
122
     * @param string               $operator One of the OP_* constants.
123
     *     Describes the operation to perform.
124
     *
125
     * @return static A new query object.
126
     */
127
    public static function where(
128
        $name,
129
        $value = null,
130
        $operator = self::OP_EX
131
    ) {
132
        $query = new static;
133
        return $query->addWhere($name, $value, $operator);
134
    }
135
136
    /**
137
     * Negates the query.
138
     *
139
     * @return $this The query object.
140
     */
141
    public function not()
142
    {
143
        $this->words[] = array('#!', null);
144
        return $this;
145
    }
146
147
    /**
148
     * Adds a condition as an alternative to the query.
149
     *
150
     * @param string               $name     The name of the property to test.
151
     * @param string|resource|null $value    Value of the property as a string
152
     *     or seekable stream. Not required for existence tests.
153
     *     If a seekable stream is provided, it is sent from its current
154
     *     position to its end, and the pointer is seeked back to its current
155
     *     position after sending.
156
     *     Non seekable streams, as well as all other types, are casted to a
157
     *     string.
158
     * @param string               $operator One of the OP_* constants.
159
     *     Describes the operation to perform.
160
     *
161
     * @return $this The query object.
162
     */
163
    public function orWhere($name, $value = null, $operator = self::OP_EX)
164
    {
165
        $this->addWhere($name, $value, $operator)->words[] = array('#|', null);
166
        return $this;
167
    }
168
169
    /**
170
     * Adds a condition in addition to the query.
171
     *
172
     * @param string               $name     The name of the property to test.
173
     * @param string|resource|null $value    Value of the property as a string
174
     *     or seekable stream. Not required for existence tests.
175
     *     If a seekable stream is provided, it is sent from its current
176
     *     position to its end, and the pointer is seeked back to its current
177
     *     position after sending.
178
     *     Non seekable streams, as well as all other types, are casted to a
179
     *     string.
180
     * @param string               $operator One of the OP_* constants.
181
     *     Describes the operation to perform.
182
     *
183
     * @return $this The query object.
184
     */
185
    public function andWhere($name, $value = null, $operator = self::OP_EX)
186
    {
187
        $this->addWhere($name, $value, $operator)->words[] = array('#&', null);
188
        return $this;
189
    }
190
191
    /**
192
     * Sends the query over a communicator.
193
     *
194
     * @param Communicator $com The communicator to send the query over.
195
     *
196
     * @return int The number of bytes sent.
197
     */
198
    public function send(Communicator $com)
199
    {
200
        if ($com->getTransmitter()->isPersistent()) {
201
            $old = $com->getTransmitter()->lock(T\Stream::DIRECTION_SEND);
202
            $bytes = $this->_send($com);
203
            $com->getTransmitter()->lock($old, true);
204
            return $bytes;
205
        }
206
        return $this->_send($com);
207
    }
208
209
    /**
210
     * Sends the query over a communicator.
211
     *
212
     * The only difference with the non private equivalent is that this one does
213
     * not do locking.
214
     *
215
     * @param Communicator $com The communicator to send the query over.
216
     *
217
     * @return int The number of bytes sent.
218
     */
219
    private function _send(Communicator $com)
220
    {
221
        if (!$com->getTransmitter()->isAcceptingData()) {
222
            throw new SocketException(
223
                'Transmitter is invalid. Sending aborted.',
224
                SocketException::CODE_QUERY_SEND_FAIL
225
            );
226
        }
227
        $bytes = 0;
228
        foreach ($this->words as $queryWord) {
229
            list($predicate, $value) = $queryWord;
230
            $prefix = '?' . $predicate;
231
            if (null === $value) {
232
                $bytes += $com->sendWord($prefix);
233
            } else {
234
                $prefix .= '=';
235
                $bytes += $com->sendWord($prefix, $value);
236
            }
237
        }
238
        return $bytes;
239
    }
240
241
    /**
242
     * Verifies the query.
243
     *
244
     * Verifies the query against a communicator, i.e. whether the query
245
     * could successfully be sent (assuming the connection is still opened).
246
     *
247
     * @param Communicator $com The Communicator to check against.
248
     *
249
     * @return $this The query object itself.
250
     *
251
     * @throws LengthException If the resulting length of an API word is not
252
     *     supported.
253
     */
254
    public function verify(Communicator $com)
255
    {
256
        foreach ($this->words as $queryWord) {
257
            list($predicate, $value) = $queryWord;
258
            if (null === $value) {
259
                $com::verifyLengthSupport(strlen('?' . $predicate));
260
            } elseif (is_string($value)) {
261
                $com::verifyLengthSupport(
262
                    strlen('?' . $predicate . '=' . $value)
263
                );
264
            } else {
265
                $com::verifyLengthSupport(
266
                    strlen('?' . $predicate . '=') +
0 ignored issues
show
Bug introduced by
strlen('?' . $predicate ...bleStreamLength($value) of type double is incompatible with the type integer expected by parameter $length of PEAR2\Net\RouterOS\Commu...::verifyLengthSupport(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

266
                    /** @scrutinizer ignore-type */ strlen('?' . $predicate . '=') +
Loading history...
267
                    $com::seekableStreamLength($value)
268
                );
269
            }
270
        }
271
        return $this;
272
    }
273
274
    /**
275
     * Get actionable debug info.
276
     *
277
     * This is a magic method available to PHP 5.6 and above, due to which
278
     * output of var_dump() will be more actionable.
279
     *
280
     * You can still call it in earlier versions to get the object as a plain array.
281
     *
282
     * @return array The info, as an associative array.
283
     */
284
    public function __debugInfo()
285
    {
286
        return $this->words;
287
    }
288
289
    /**
290
     * Adds a condition.
291
     *
292
     * @param string               $name     The name of the property to test.
293
     * @param string|resource|null $value    Value of the property as a string
294
     *     or seekable stream. Not required for existence tests.
295
     *     If a seekable stream is provided, it is sent from its current
296
     *     position to its end, and the pointer is seeked back to its current
297
     *     position after sending.
298
     *     Non seekable streams, as well as all other types, are casted to a
299
     *     string.
300
     * @param string               $operator One of the ACTION_* constants.
301
     *     Describes the operation to perform.
302
     *
303
     * @return $this The query object.
304
     */
305
    protected function addWhere($name, $value, $operator)
306
    {
307
        $this->words[] = array(
308
            static::sanitizeOperator($operator)
309
            . Message::sanitizeAttributeName($name),
310
            (null === $value ? null : Message::sanitizeAttributeValue($value))
311
        );
312
        return $this;
313
    }
314
}
315