Completed
Push — master ( 42a9f8...195519 )
by Shcherbak
38:40 queued 23:39
created

ClassPattern::withName()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 11
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 1
CRAP Score 3

Importance

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