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

ClassPattern::__invoke()   B

Complexity

Conditions 6
Paths 24

Size

Total Lines 48
Code Lines 26

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 30
CRAP Score 6

Importance

Changes 8
Bugs 4 Features 3
Metric Value
c 8
b 4
f 3
dl 0
loc 48
ccs 30
cts 30
cp 1
rs 8.551
cc 6
eloc 26
nc 24
nop 1
crap 6
1
<?php
2
3
  namespace Funivan\PhpTokenizer\Pattern\Patterns;
4
5
  use Funivan\PhpTokenizer\QuerySequence\QuerySequence;
6
  use Funivan\PhpTokenizer\Strategy\Possible;
7
  use Funivan\PhpTokenizer\Strategy\QueryStrategy;
8
  use Funivan\PhpTokenizer\Strategy\Strict;
9
  use Funivan\PhpTokenizer\Token;
10
11
  /**
12
   * PatternMatcher used to finding classes in tour source code
13
   *
14
   */
15
  class ClassPattern implements PatternInterface {
16
17
    /**
18
     * Result of this pattern will be body of the class
19
     */
20
    const OUTPUT_BODY = 1;
21
22
    /**
23
     * Result of this pattern will be full class
24
     */
25
    const OUTPUT_FULL = 2;
26
27
28
    /**
29
     * @var QueryStrategy
30
     */
31
    private $nameQuery = null;
32
33
    /**
34
     * @var callable
35
     */
36
    private $docCommentChecker;
37
38
    /**
39
     * @var callable[]
40
     */
41
    private $modifierChecker;
42
43
    /**
44
     * @var int
45
     */
46
    private $outputType = self::OUTPUT_BODY;
47
48
49
    /**
50
     * By default we search for classes with any name
51
     */
52 57
    public function __construct() {
53 57
      $this->nameQuery = Strict::create()->valueLike('!.+!');
54 57
      $this->withPossibleDocComment();
55 57
      $this->withAnyModifier();
56 57
    }
57
58
59
    /**
60
     * @codeCoverageIgnore
61
     * @deprecated
62
     * @param string $name
63
     * @return $this
64
     */
65
    public function nameIs($name) {
66
      trigger_error('Deprecated. Use withName', E_USER_DEPRECATED);
67
      return $this->withName($name);
68
    }
69
70
71
    /**
72
     * @param QueryStrategy|string $name
73
     * @return $this
74
     */
75 15
    public function withName($name) {
76 15
      if (is_string($name)) {
77 9
        $this->nameQuery = Strict::create()->valueIs($name);
78 10
      } elseif ($name instanceof QueryStrategy) {
79 6
        $this->nameQuery = $name;
80 4
      } else {
81 3
        throw new \InvalidArgumentException('Expect string or QueryInterface');
82
      }
83
84 12
      return $this;
85
    }
86
87
88
    /**
89
     * @return $this
90
     */
91 3
    public function withDocComment() {
92
      $this->docCommentChecker = function (Token $comment, QuerySequence $q) {
93 3
        if ($comment->getType() !== T_DOC_COMMENT) {
94 3
          $q->setValid(false);
95 2
        }
96 3
      };
97 3
      return $this;
98
    }
99
100
101
    /**
102
     * @return $this
103
     */
104 57
    public function withPossibleDocComment() {
105
      $this->docCommentChecker = function () {
106
107 48
      };
108 57
      return $this;
109
    }
110
111
112
    /**
113
     * @return $this
114
     */
115 3
    public function withoutDocComment() {
116
      $this->docCommentChecker = function (Token $comment, QuerySequence $q) {
117 3
        if ($comment->getType() === T_DOC_COMMENT) {
118 3
          $q->setValid(false);
119 2
        }
120 3
      };
121 3
      return $this;
122
    }
123
124
125
    /**
126
     * @return $this
127
     */
128 3
    public function outputBody() {
129 3
      $this->outputType = self::OUTPUT_BODY;
130 3
      return $this;
131
    }
132
133
134
    /**
135
     * @return $this
136
     */
137 21
    public function outputFull() {
138 21
      $this->outputType = self::OUTPUT_FULL;
139 21
      return $this;
140
    }
141
142
143
    /**
144
     * @codeCoverageIgnore
145
     * @deprecated
146
     * @param QueryStrategy $strategy
147
     * @return $this
148
     */
149
    public function whereName(QueryStrategy $strategy) {
150
      trigger_error('Deprecated. Use withName', E_USER_DEPRECATED);
151
      return $this->withName($strategy);
152
    }
153
154
155
    /**
156
     * @inheritdoc
157
     */
158 54
    public function __invoke(QuerySequence $querySequence) {
159
160
161 54
      $comment = $querySequence->process(Possible::create()->typeIs(T_DOC_COMMENT));
162
163 54
      $querySequence->possible(T_WHITESPACE);
164 54
      $modifier = $querySequence->process(Possible::create()->valueIs([
165 54
        'abstract',
166 36
        'final',
167 36
      ]));
168
169 54
      $querySequence->possible(T_WHITESPACE);
170 54
      $start = $querySequence->strict('class');
171 54
      $querySequence->strict(T_WHITESPACE);
172 54
      $querySequence->process($this->nameQuery);
173 54
      $startClassBody = $querySequence->search('{');
174 54
      $querySequence->moveToToken($startClassBody);
175 54
      $body = $querySequence->section('{', '}');
176
177 54
      if ($modifier->isValid()) {
178 21
        $start = $modifier;
179 14
      }
180
181 54
      if ($comment->isValid()) {
182 15
        $start = $comment;
183 10
      }
184
185 54
      $docCommentChecker = $this->docCommentChecker;
186 54
      $docCommentChecker($comment, $querySequence);
187
188
189 54
      foreach ($this->modifierChecker as $checker) {
190 54
        $checker($modifier, $querySequence);
191 36
      }
192
193
194 54
      if (!$querySequence->isValid()) {
195 54
        return null;
196
      }
197
198
199 51
      if ($this->outputType === self::OUTPUT_BODY) {
200 30
        return $body->extractItems(1, -1);
201
      }
202
203
      # self::OUTPUT_FULL
204 21
      return $querySequence->getCollection()->extractByTokens($start, $body->getLast());
205
    }
206
207
208
    /**
209
     * @return $this
210
     */
211 57
    public function withAnyModifier() {
212 57
      $this->modifierChecker = [];
213
      $this->modifierChecker[] = function () {
214 54
      };
215 57
      return $this;
216
    }
217
218
219
    /**
220
     * @param string $modifier
221
     * @return $this
222
     */
223 6
    public function withModifier($modifier) {
224
225
      $this->modifierChecker[] = function (Token $token, QuerySequence $q) use ($modifier) {
226 6
        if ($token->getValue() !== $modifier) {
227 6
          $q->setValid(false);
228 4
        }
229 6
      };
230
231
232 6
      return $this;
233
    }
234
235
236
    /**
237
     * @param string $modifier
238
     * @return $this
239
     */
240
    public function withoutModifier($modifier) {
241
242 3
      $this->modifierChecker[] = function (Token $token, QuerySequence $q) use ($modifier) {
243 3
        if ($token->getValue() === $modifier) {
244 3
          $q->setValid(false);
245 2
        }
246 3
      };
247 3
      return $this;
248
    }
249
250
251
  }