Completed
Push — master ( 5289fb...a19420 )
by Shcherbak
02:04
created

ArgumentsPattern   A

Complexity

Total Complexity 26

Size/Duplication

Total Lines 176
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 5

Test Coverage

Coverage 98.57%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 26
c 1
b 0
f 0
lcom 2
cbo 5
dl 0
loc 176
ccs 69
cts 70
cp 0.9857
rs 10

8 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 3 1
D __invoke() 0 39 10
A withArgument() 0 9 2
A withoutArgument() 0 8 1
C getArguments() 0 31 7
A getEndArray() 0 15 3
A outputFull() 0 4 1
A outputArgument() 0 4 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 ArgumentsPattern 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
    /**
27
     *
28
     */
29 30
    public function __construct() {
30 30
      $this->outputFull();
31 30
    }
32
33
34
    /**
35
     * @param QuerySequence $querySequence
36
     * @return Collection|null
37
     * @throws \Exception
38
     */
39 30
    public function __invoke(QuerySequence $querySequence) {
40 30
      $section = $querySequence->section('(', ')');
41 30
      if ($section->count() === 0) {
42 24
        return null;
43
      }
44
45 30
      $section->slice(1, -1);
46
47 30
      if (empty($this->argumentCheck) and $this->outputArgument === null) {
48 15
        return $section;
49
      }
50
51
52
      /** @var Collection[] $arguments */
53 27
      $arguments = $this->getArguments($section);
54
55 27
      foreach ($this->argumentCheck as $index => $check) {
56
57 18
        $argumentTokens = isset($arguments[$index]) ? $arguments[$index] : new Collection();;
58 18
        $result = $check($argumentTokens);
59
60 24
        if (!is_bool($result)) {
61 3
          throw new \Exception('Argument check function should return boolean');
62
        }
63
64 15
        if ($result === false) {
65 15
          return null;
66
        }
67 16
      }
68
69 24
      if ($this->outputArgument !== null) {
70 9
        $argumentCollection = !empty($arguments[$this->outputArgument]) ? $arguments[$this->outputArgument] : null;
71
72 9
        return $argumentCollection;
73
      }
74
75
      # output full
76 15
      return $section;
77
    }
78
79
80
    /**
81
     * @param int $int
82
     * @param callable $check
83
     * @return $this
84
     */
85 18
    public function withArgument($int, callable $check = null) {
86 18
      if ($check === null) {
87
        $check = function (Collection $argumentTokens) {
88 12
          return $argumentTokens->count() !== 0;
89 12
        };
90 8
      }
91 18
      $this->argumentCheck[$int] = $check;
92 18
      return $this;
93
    }
94
95
96
    /**
97
     * @param int $int
98
     * @return $this
99
     */
100
    public function withoutArgument($int) {
101 3
      $check = function (Collection $argumentTokens) {
102 3
        return $argumentTokens->count() === 0;
103 3
      };
104
105 3
      $this->argumentCheck[$int] = $check;
106 3
      return $this;
107
    }
108
109
110
    /**
111
     * @param $section
112
     * @return array
113
     */
114 27
    protected function getArguments(Collection $section) {
115
      /** @var Token $skipToToken */
116 27
      $skipToToken = null;
117 27
      $argumentIndex = 1;
118 27
      $arguments = [];
119 27
      $tokensNum = ($section->count() - 1);
120 27
      for ($tokenIndex = 0; $tokenIndex <= $tokensNum; $tokenIndex++) {
121
122 27
        $token = $section->offsetGet($tokenIndex);
123
124 27
        if ($token === null) {
125
          return null;
126
        }
127
128 27
        if ($skipToToken === null or $token->getIndex() >= $skipToToken->getIndex()) {
129 27
          if ($token->getValue() === ',') {
130 27
            $argumentIndex++;
131 27
            continue;
132
          }
133 27
          $skipToToken = $this->getEndArray($token, $section, $tokenIndex);
134 18
        }
135
136
137 27
        if (!isset($arguments[$argumentIndex])) {
138 27
          $arguments[$argumentIndex] = new Collection();
139 18
        }
140 27
        $arguments[$argumentIndex][] = $token;
141 18
      }
142
143 27
      return $arguments;
144
    }
145
146
147
    /**
148
     * @param Token $token
149
     * @param Collection $section
150
     * @param $index
151
     * @return Token
152
     */
153 27
    private function getEndArray(Token $token, Collection $section, $index) {
154
      // # check if we have array start
155
156 27
      if ($token->getValue() === '[') {
157 15
        $result = (new Section())->setDelimiters('[', ']')->process($section, $index);
158 15
        return $result->getToken();
159
      }
160
161 27
      if ($token->getValue() === '(') {
162 6
        $result = (new Section())->setDelimiters('(', ')')->process($section, $index);
163 6
        return $result->getToken();
164
      }
165
166 27
      return null;
167
    }
168
169
170
    /**
171
     * @return $this
172
     */
173 30
    public function outputFull() {
174 30
      $this->outputArgument = null;
175 30
      return $this;
176
    }
177
178
179
    /**
180
     * @param $int
181
     * @return $this
182
     */
183 9
    public function outputArgument($int) {
184 9
      $this->outputArgument = $int;
185 9
      return $this;
186
    }
187
188
  }