1 | <?php |
||
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; |
||
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 | * By default we search for classes with any name |
||
53 | */ |
||
54 | 57 | public function __construct() { |
|
55 | 57 | $this->nameQuery = Strict::create()->valueLike('!.+!'); |
|
56 | 57 | $this->withPossibleDocComment(); |
|
57 | 57 | $this->withAnyModifier(); |
|
58 | 57 | } |
|
59 | |||
60 | |||
61 | /** |
||
62 | * @param QueryStrategy|string $name |
||
63 | * @return $this |
||
64 | */ |
||
65 | 15 | public function withName($name): self { |
|
66 | 15 | if (is_string($name)) { |
|
67 | 9 | $this->nameQuery = Strict::create()->valueIs($name); |
|
68 | 9 | } elseif ($name instanceof QueryStrategy) { |
|
69 | 6 | $this->nameQuery = $name; |
|
70 | } else { |
||
71 | 3 | throw new \InvalidArgumentException('Expect string or QueryInterface'); |
|
72 | } |
||
73 | |||
74 | 12 | return $this; |
|
75 | } |
||
76 | |||
77 | |||
78 | /** |
||
79 | * @return $this |
||
80 | */ |
||
81 | 3 | public function withDocComment(): self { |
|
82 | $this->docCommentChecker = function (Token $comment, QuerySequence $q) { |
||
83 | 3 | if ($comment->getType() !== T_DOC_COMMENT) { |
|
84 | 3 | $q->setValid(false); |
|
85 | } |
||
86 | 3 | }; |
|
87 | 3 | return $this; |
|
88 | } |
||
89 | |||
90 | |||
91 | /** |
||
92 | * @return $this |
||
93 | */ |
||
94 | 57 | public function withPossibleDocComment(): self { |
|
95 | $this->docCommentChecker = function () { |
||
96 | |||
97 | 48 | }; |
|
98 | 57 | return $this; |
|
99 | } |
||
100 | |||
101 | |||
102 | /** |
||
103 | * @return $this |
||
104 | */ |
||
105 | 3 | public function withoutDocComment(): self { |
|
106 | $this->docCommentChecker = function (Token $comment, QuerySequence $q) { |
||
107 | 3 | if ($comment->getType() === T_DOC_COMMENT) { |
|
108 | 3 | $q->setValid(false); |
|
109 | } |
||
110 | 3 | }; |
|
111 | 3 | return $this; |
|
112 | } |
||
113 | |||
114 | |||
115 | /** |
||
116 | * @return $this |
||
117 | */ |
||
118 | 3 | public function outputBody(): self { |
|
119 | 3 | $this->outputType = self::OUTPUT_BODY; |
|
120 | 3 | return $this; |
|
121 | } |
||
122 | |||
123 | |||
124 | /** |
||
125 | * @return $this |
||
126 | */ |
||
127 | 18 | public function outputFull(): self { |
|
131 | |||
132 | |||
133 | /** |
||
134 | * @inheritdoc |
||
135 | */ |
||
136 | 54 | public function __invoke(QuerySequence $querySequence) { |
|
137 | |||
138 | 54 | $comment = $querySequence->process(Possible::create()->typeIs(T_DOC_COMMENT)); |
|
139 | |||
140 | 54 | $querySequence->possible(T_WHITESPACE); |
|
141 | 54 | $modifier = $querySequence->process(Possible::create()->valueIs([ |
|
142 | 54 | 'abstract', |
|
143 | 'final', |
||
144 | ])); |
||
145 | |||
146 | 54 | $querySequence->possible(T_WHITESPACE); |
|
147 | 54 | $start = $querySequence->strict('class'); |
|
148 | 54 | $querySequence->strict(T_WHITESPACE); |
|
149 | 54 | $querySequence->process($this->nameQuery); |
|
150 | 54 | $startClassBody = $querySequence->search('{'); |
|
151 | 54 | $querySequence->moveToToken($startClassBody); |
|
152 | 54 | $body = $querySequence->section('{', '}'); |
|
153 | |||
154 | 54 | if ($modifier->isValid()) { |
|
155 | 21 | $start = $modifier; |
|
156 | } |
||
157 | |||
158 | 54 | if ($comment->isValid()) { |
|
159 | 15 | $start = $comment; |
|
160 | } |
||
161 | |||
162 | 54 | $docCommentChecker = $this->docCommentChecker; |
|
163 | 54 | $docCommentChecker($comment, $querySequence); |
|
164 | |||
165 | |||
166 | 54 | foreach ($this->modifierChecker as $checker) { |
|
167 | 54 | $checker($modifier, $querySequence); |
|
168 | } |
||
169 | |||
170 | |||
171 | 54 | if (!$querySequence->isValid()) { |
|
172 | 54 | return null; |
|
173 | } |
||
174 | |||
175 | # self::OUTPUT_FULL |
||
176 | 51 | $lastBodyToken = $body->getLast(); |
|
177 | 51 | if ($lastBodyToken === null) { |
|
178 | return null; |
||
179 | } |
||
180 | |||
181 | 51 | if ($this->outputType === self::OUTPUT_BODY) { |
|
182 | 3 | return $body->extractItems(1, -1); |
|
183 | } |
||
184 | |||
185 | |||
186 | 48 | return $querySequence->getCollection()->extractByTokens($start, $lastBodyToken); |
|
187 | } |
||
188 | |||
189 | |||
190 | /** |
||
191 | * @return $this |
||
192 | */ |
||
193 | 57 | public function withAnyModifier(): self { |
|
194 | 57 | $this->modifierChecker = []; |
|
195 | $this->modifierChecker[] = function () { |
||
196 | 54 | }; |
|
197 | 57 | return $this; |
|
198 | } |
||
199 | |||
200 | |||
201 | /** |
||
202 | * @param string $modifier |
||
203 | * @return $this |
||
204 | */ |
||
205 | 6 | public function withModifier(string $modifier): self { |
|
206 | |||
207 | $this->modifierChecker[] = function (Token $token, QuerySequence $q) use ($modifier) { |
||
208 | 6 | if ($token->getValue() !== $modifier) { |
|
209 | 6 | $q->setValid(false); |
|
210 | } |
||
211 | 6 | }; |
|
212 | |||
213 | |||
214 | 6 | return $this; |
|
215 | } |
||
216 | |||
217 | |||
218 | /** |
||
219 | * @param string $modifier |
||
220 | * @return $this |
||
221 | */ |
||
222 | public function withoutModifier(string $modifier): self { |
||
231 | |||
232 | |||
233 | } |