Completed
Push — master ( dc020a...4c5edf )
by Shcherbak
04:07 queued 01:47
created

ParametersPattern::getEndArray()   B

Complexity

Conditions 4
Paths 4

Size

Total Lines 23
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 13
CRAP Score 4

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 23
ccs 13
cts 13
cp 1
rs 8.7972
cc 4
eloc 12
nc 4
nop 3
crap 4
1
<?php
2
3
  namespace Funivan\PhpTokenizer\Pattern\Patterns;
4
5
  use Funivan\PhpTokenizer\Collection;
6
  use Funivan\PhpTokenizer\QuerySequence\QuerySequence;
7
  use Funivan\PhpTokenizer\Strategy\Section;
8
  use Funivan\PhpTokenizer\Token;
9
10
  /**
11
   * Find method in code
12
   */
13
  class ParametersPattern implements PatternInterface {
14
15
    /**
16
     * @var array
17
     */
18
    private $argumentCheck = [];
19
20
    /**
21
     * @var int|null
22
     */
23
    private $outputArgument = null;
24
25
    /**
26
     * @var bool
27
     */
28
    private $fullSearch = true;
29
30
31
    /**
32
     *
33
     */
34 24
    public function __construct() {
35 24
      $this->outputFull();
36 24
      $this->startFromFunction();
37 24
    }
38
39
40
    /**
41
     * @return $this
42
     */
43 3
    public function startFromParenthesis() {
44 3
      $this->fullSearch = false;
45 3
      return $this;
46
    }
47
48
49
    /**
50
     * @return $this
51
     */
52 24
    public function startFromFunction() {
53 24
      $this->fullSearch = true;
54 24
      return $this;
55
    }
56
57
58
    /**
59
     * @param QuerySequence $querySequence
60
     * @return Collection|null
61
     * @throws \Exception
62
     */
63 24
    public function __invoke(QuerySequence $querySequence) {
64 24
      if ($this->fullSearch) {
65 21
        $querySequence->strict(T_FUNCTION);
66 21
        $querySequence->possible(T_WHITESPACE);
67 21
        $querySequence->possible(T_STRING);
68 21
        $querySequence->possible(T_WHITESPACE);
69 14
      }
70
71 24
      $section = $querySequence->section('(', ')');
72 24
      if ($section->count() === 0) {
73 21
        return null;
74
      }
75
76 24
      $section->slice(1, -1);
77
78 24
      if (empty($this->argumentCheck) and $this->outputArgument === null) {
79 15
        return $section;
80
      }
81
82
83
      /** @var Collection[] $arguments */
84 21
      $arguments = $this->getArguments($section);
85
86 21
      foreach ($this->argumentCheck as $index => $check) {
87
88 15
        $argumentTokens = isset($arguments[$index]) ? $arguments[$index] : new Collection();;
89 15
        $result = $check($argumentTokens);
90
91 15
        if (!is_bool($result)) {
92 3
          throw new \Exception('Argument check function should return boolean');
93
        }
94
95 12
        if ($result === false) {
96 12
          return null;
97
        }
98 12
      }
99
100 18
      if ($this->outputArgument !== null) {
101 6
        $argumentCollection = !empty($arguments[$this->outputArgument]) ? $arguments[$this->outputArgument] : null;
102
103 6
        return $argumentCollection;
104
      }
105
106
      # output full
107 12
      return $section;
108
    }
109
110
111
    /**
112
     * @param int $int
113
     * @param callable $check
114
     * @return $this
115
     */
116 15
    public function withArgument($int, callable $check = null) {
117 15
      if ($check === null) {
118
        $check = function (Collection $argumentTokens) {
119 9
          return $argumentTokens->count() !== 0;
120 9
        };
121 6
      }
122 15
      $this->argumentCheck[$int] = $check;
123 15
      return $this;
124
    }
125
126
127
    /**
128
     * @param int $int
129
     * @return $this
130
     */
131
    public function withoutArgument($int) {
132 3
      $check = function (Collection $argumentTokens) {
133 3
        return $argumentTokens->count() === 0;
134 3
      };
135
136 3
      $this->argumentCheck[$int] = $check;
137 3
      return $this;
138
    }
139
140
141
    /**
142
     * @param $section
143
     * @return array
144
     */
145 21
    protected function getArguments(Collection $section) {
146
      /** @var Token $skipToToken */
147 21
      $skipToToken = null;
148 21
      $argumentIndex = 1;
149 21
      $arguments = [];
150 21
      $tokensNum = ($section->count() - 1);
151 21
      for ($tokenIndex = 0; $tokenIndex <= $tokensNum; $tokenIndex++) {
152
153 21
        $token = $section->offsetGet($tokenIndex);
154
155 21
        if ($token === null) {
156
          return null;
157
        }
158
159 21
        if ($skipToToken === null or $token->getIndex() >= $skipToToken->getIndex()) {
160 21
          if ($token->getValue() === ',') {
161 21
            $argumentIndex++;
162 21
            continue;
163
          }
164 21
          $skipToToken = $this->getEndArray($token, $section, $tokenIndex);
165 14
        }
166
167
168 21
        if (!isset($arguments[$argumentIndex])) {
169 21
          $arguments[$argumentIndex] = new Collection();
170 14
        }
171 21
        $arguments[$argumentIndex][] = $token;
172 14
      }
173
174 21
      return $arguments;
175
    }
176
177
178
    /**
179
     * @param Token $token
180
     * @param Collection $section
181
     * @param $index
182
     * @return Token
183
     */
184 21
    private function getEndArray(Token $token, Collection $section, $index) {
185
      // # check if we have array start
186
187 21
      if ($token->getValue() === '[') {
188 15
        $result = (new Section())->setDelimiters('[', ']')->process($section, $index);
189 15
        return $result->getToken();
190
      }
191
192 21
      if ($token->getValue() === 'array') {
193
194
        # skip whitespace
195 3
        $nextIndex = ($index + 1);
196 3
        $nextToken = $section->offsetGet($nextIndex);
197 3
        if ($nextToken->getType() === T_WHITESPACE) {
198 3
          $nextIndex = ($index + 2);
199 2
        }
200
201 3
        $result = (new Section())->setDelimiters('(', ')')->process($section, $nextIndex);
202 3
        return $result->getToken();
203
      }
204
205 21
      return null;
206
    }
207
208
209
    /**
210
     * @return $this
211
     */
212 24
    public function outputFull() {
213 24
      $this->outputArgument = null;
214 24
      return $this;
215
    }
216
217
218
    /**
219
     * @param $int
220
     * @return $this
221
     */
222 6
    public function outputArgument($int) {
223 6
      $this->outputArgument = $int;
224 6
      return $this;
225
    }
226
227
  }