Completed
Push — master ( 1bff1a...f9631c )
by Shcherbak
02:38
created

ParametersPattern::outputFull()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

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