QuerySequence::process()   C
last analyzed

Complexity

Conditions 7
Paths 6

Size

Total Lines 28
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 7

Importance

Changes 0
Metric Value
dl 0
loc 28
ccs 15
cts 15
cp 1
rs 6.7272
c 0
b 0
f 0
cc 7
eloc 15
nc 6
nop 1
crap 7
1
<?php
2
3
  declare(strict_types=1);
4
5
  namespace Funivan\PhpTokenizer\QuerySequence;
6
7
  use Funivan\PhpTokenizer\Collection;
8
  use Funivan\PhpTokenizer\Exception\InvalidArgumentException;
9
  use Funivan\PhpTokenizer\Strategy\Move;
10
  use Funivan\PhpTokenizer\Strategy\Possible;
11
  use Funivan\PhpTokenizer\Strategy\QueryStrategy;
12
  use Funivan\PhpTokenizer\Strategy\Search;
13
  use Funivan\PhpTokenizer\Strategy\StrategyInterface;
14
  use Funivan\PhpTokenizer\Strategy\Strict;
15
  use Funivan\PhpTokenizer\Token;
16
17
  /**
18
   * Start from specific position and check token from this position according to strategies
19
   */
20
  class QuerySequence implements QuerySequenceInterface {
21
22
    /**
23
     * @var bool
24
     */
25
    private $valid = true;
26
27
    /**
28
     * @var int
29
     */
30
    private $position;
31
32
    /**
33
     * @var Collection
34
     */
35
    private $collection;
36
37
    /**
38
     * @var
39
     */
40
    private $skipWhitespaces = false;
41
42
43
    /**
44
     * @inheritdoc
45
     */
46 387
    public function __construct(Collection $collection, $initialPosition = 0) {
47 387
      $this->collection = $collection;
48 387
      $this->position = $initialPosition;
49 387
    }
50
51
52
    /**
53
     * @return Collection
54
     */
55 111
    public function getCollection() {
56 111
      return $this->collection;
57
    }
58
59
60
    /**
61
     * @param int $position
62
     * @return QuerySequence
63
     */
64 339
    public function setPosition($position) {
65 339
      $this->position = $position;
66 339
      return $this;
67
    }
68
69
70
    /**
71
     * @return int
72
     */
73 348
    public function getPosition() {
74 348
      return $this->position;
75
    }
76
77
78
    /**
79
     * Strict validation of condition
80
     *
81
     * @param int|string|Strict $condition
82
     * @return Token
83
     */
84 285
    public function strict($condition) {
85 285
      $query = $this->buildStrategyCondition($condition, Strict::create());
86 276
      return $this->process($query);
87
    }
88
89
90
    /**
91
     * Check if token possible valid for our condition
92
     *
93
     * @param int|string|Possible $condition
94
     * @return Token
95
     */
96 177
    public function possible($condition) {
97 177
      $query = $this->buildStrategyCondition($condition, Possible::create());
98 165
      return $this->process($query);
99
    }
100
101
102
    /**
103
     * @param string $start
104
     * @param string $end
105
     * @return Collection
106
     */
107 180
    public function section($start, $end) {
108
109 180
      $token = $this->strict($start);
110 180
      if (!$token->isValid()) {
111
        # cant find start position
112 180
        return new Collection();
113
      }
114
115 171
      $this->moveToToken($token);
116
117 171
      $section = new \Funivan\PhpTokenizer\Strategy\Section();
118 171
      $section->setDelimiters($start, $end);
119 171
      $lastToken = $this->process($section);
120 171
      if (!$lastToken->isValid()) {
121
        return new Collection();
122
      }
123
124 171
      return $this->collection->extractByTokens($token, $lastToken);
125
    }
126
127
128
    /**
129
     * By default we search forward
130
     *
131
     * @param int|string|Search $condition
132
     * @param null $direction
133
     * @return Token
134
     */
135 75
    public function search($condition, $direction = null) {
136 75
      $strategy = Search::create();
137 75
      if ($direction !== null) {
138 6
        $strategy->setDirection($direction);
139
      }
140 75
      $query = $this->buildStrategyCondition($condition, $strategy);
141 75
      return $this->process($query);
142
    }
143
144
145
    /**
146
     * Relative move
147
     * +10 move forward 10 tokens
148
     * -5 move backward 5 tokens
149
     *
150
     * @param int $steps
151
     * @return Token
152
     */
153 15
    public function move($steps) {
154 15
      return $this->process(Move::create($steps));
155
    }
156
157
158
    /**
159
     * Move to specific position
160
     *
161
     * @param Token $token
162
     * @return Token|null
163
     */
164 180
    public function moveToToken(Token $token) {
165
166 180
      if (!$token->isValid()) {
167 57
        $this->setValid(false);
168 57
        return new Token();
169
      }
170
171 177
      $tokenIndex = $token->getIndex();
172
173
174 177
      foreach ($this->collection as $index => $collectionToken) {
175 177
        if ($collectionToken->getIndex() === $tokenIndex) {
176 177
          $this->setPosition($index);
177 177
          return $collectionToken;
178
        }
179
      }
180
181 3
      $this->setValid(false);
182 3
      return new Token();
183
    }
184
185
186
    /**
187
     * Array may contain Int, String or any StrategyInterface object
188
     *
189
     * @param array $conditions
190
     * @return Collection
191
     */
192 75
    public function sequence(array $conditions) {
193 75
      $range = new Collection();
194 75
      foreach ($conditions as $value) {
195 75
        $range[] = $this->checkFromSequence($value);
196
      }
197
198 75
      return $range;
199
    }
200
201
202
    /**
203
     * @param string|int|StrategyInterface $value
204
     * @return Token
205
     */
206 75
    private function checkFromSequence($value) {
207 75
      if ($value instanceof StrategyInterface) {
208 51
        $query = $value;
209
      } else {
210 45
        $query = $this->buildStrategyCondition($value, Strict::create());
211
      }
212
213 75
      return $this->process($query);
214
    }
215
216
217
    /**
218
     * @inheritdoc
219
     */
220 348
    public function process(StrategyInterface $strategy) {
221
222 348
      if ($this->isValid() === false) {
223 249
        return new Token();
224
      }
225
226 348
      $result = $strategy->process($this->collection, $this->getPosition());
227
228 348
      if ($result->isValid() === false) {
229 318
        $this->setValid(false);
230 318
        return new Token();
231
      }
232
233 333
      $position = $result->getNexTokenIndex();
234 333
      $this->setPosition($position);
235
236 333
      $token = $result->getToken();
237 333
      if ($token === null) {
238 192
        $token = new Token();
239
      }
240
241 333
      if ($this->skipWhitespaces and isset($this->collection[$position]) and $this->collection[$position]->getType() === T_WHITESPACE) {
242
        # skip whitespaces in next check
243 39
        $this->setPosition($position + 1);
244
      }
245
246 333
      return $token;
247
    }
248
249
250
    /**
251
     *
252
     * @param StrategyInterface|string|int $value
253
     * @param QueryStrategy $defaultStrategy
254
     * @return QueryStrategy
255
     */
256 333
    private function buildStrategyCondition($value, QueryStrategy $defaultStrategy) {
257
258 333
      if ($value instanceof $defaultStrategy) {
259 21
        return $value;
260
      }
261
262 321
      $query = $defaultStrategy;
263
264 321
      if (is_string($value)) {
265 282
        $query->valueIs($value);
266 282
        return $query;
267
      }
268
269 222
      if ($value === null) {
270 27
        $query->valueIs([]);
271 27
        return $query;
272
      }
273
274 216
      if (is_int($value)) {
275 195
        $query->typeIs($value);
276 195
        return $query;
277
      }
278
279
280 21
      throw new InvalidArgumentException('Invalid token condition. Expect string or int or StrategyInterface');
281
    }
282
283
284
    /**
285
     * @param boolean $valid
286
     * @return $this
287
     */
288 327
    public function setValid($valid) {
289 327
      if (!is_bool($valid)) {
290 3
        throw new InvalidArgumentException('Invalid flag. Expect boolean. Given:' . gettype($valid));
291
      }
292 324
      $this->valid = $valid;
293 324
      return $this;
294
    }
295
296
297
    /**
298
     * @return Token
299
     */
300
    public function getToken() {
301
      $position = $this->getPosition();
302
      $token = $this->getCollection()->offsetGet($position);
303
304
      if ($token !== null) {
305
        return $token;
306
      }
307
308
      return new Token();
309
    }
310
311
312
    /**
313
     * Indicate state of all conditions
314
     *
315
     * @return bool
316
     */
317 354
    public function isValid() {
318 354
      return ($this->valid === true);
319
    }
320
321
322
    /**
323
     * @param boolean $skipWhitespaces
324
     * @return $this
325
     */
326 42
    public function setSkipWhitespaces($skipWhitespaces) {
327 42
      $this->skipWhitespaces = $skipWhitespaces;
328 42
      return $this;
329
    }
330
331
  }