1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace TypeHints\Unused\Parser; |
4
|
|
|
|
5
|
|
|
use Illuminate\Filesystem\Filesystem; |
6
|
|
|
use TypeHints\Unused\Parser\Action\ParserActionInterface; |
7
|
|
|
|
8
|
|
|
class ViewParser implements ParserInterface |
9
|
|
|
{ |
10
|
|
|
/** |
11
|
|
|
* @var ParserActionInterface |
12
|
|
|
*/ |
13
|
|
|
protected $action; |
14
|
|
|
|
15
|
|
|
/** |
16
|
|
|
* @var array |
17
|
|
|
*/ |
18
|
|
|
protected $parent = []; |
19
|
|
|
|
20
|
|
|
/** |
21
|
|
|
* @var array |
22
|
|
|
*/ |
23
|
|
|
protected $children = []; |
24
|
|
|
|
25
|
|
|
/** |
26
|
|
|
* @var array |
27
|
|
|
*/ |
28
|
|
|
protected $childrenViews = []; |
29
|
|
|
|
30
|
|
|
/** |
31
|
|
|
* @var array |
32
|
|
|
*/ |
33
|
|
|
protected $viewAliases = [ |
34
|
|
|
'View::make(', |
35
|
|
|
'view(', |
36
|
|
|
'view->make(', |
37
|
|
|
]; |
38
|
|
|
|
39
|
|
|
/** |
40
|
|
|
* @var array |
41
|
|
|
*/ |
42
|
|
|
protected $ignoredStrings = [ |
43
|
|
|
'(', |
44
|
|
|
')', |
45
|
|
|
';', |
46
|
|
|
"'", |
47
|
|
|
]; |
48
|
|
|
|
49
|
|
|
/** |
50
|
|
|
* @var array |
51
|
|
|
*/ |
52
|
|
|
protected $bladeDirectives = [ |
53
|
|
|
'@include(', |
54
|
|
|
'@includeIf(', |
55
|
|
|
'@extends(', |
56
|
|
|
'Blade::include(', |
57
|
|
|
]; |
58
|
|
|
|
59
|
|
|
/** |
60
|
|
|
* @var array |
61
|
|
|
*/ |
62
|
|
|
protected $statementBladeDirectives = [ |
63
|
|
|
'@includeWhen(', |
64
|
|
|
'@includeUnless(', |
65
|
|
|
'@includeFirst(', |
66
|
|
|
]; |
67
|
|
|
|
68
|
|
|
/** |
69
|
|
|
* @param ParserActionInterface |
70
|
|
|
*/ |
71
|
|
|
public function __construct(ParserActionInterface $action) |
72
|
|
|
{ |
73
|
|
|
$this->action = $action; |
74
|
|
|
} |
75
|
|
|
|
76
|
|
|
/** |
77
|
|
|
* @return ParserInterface |
78
|
|
|
*/ |
79
|
|
|
public function parse(): ParserInterface |
80
|
|
|
{ |
81
|
|
|
$this->parent = $this->retrieveViewsFromMethod(); |
82
|
|
|
|
83
|
|
|
if ($this->parent) { |
84
|
|
|
$this->retrieveChildrenFromNestedViews(); |
85
|
|
|
} |
86
|
|
|
|
87
|
|
|
return $this; |
88
|
|
|
} |
89
|
|
|
|
90
|
|
|
public function retrieveChildrenFromNestedViews(): void |
91
|
|
|
{ |
92
|
|
|
$this->children = $this->loopForNestedViews($this->parent); |
93
|
|
|
|
94
|
|
|
$this->resolveChildrenHierarchy($this->children); |
95
|
|
|
} |
96
|
|
|
|
97
|
|
|
/** |
98
|
|
|
* @param array $children |
99
|
|
|
*/ |
100
|
|
|
public function resolveChildrenHierarchy(array $children): void |
101
|
|
|
{ |
102
|
|
|
collect($children)->each(function ($value, $key) { |
103
|
|
|
if (is_string($key)) { |
104
|
|
|
$this->childrenViews[] = $key; |
105
|
|
|
} |
106
|
|
|
|
107
|
|
|
return $this->resolveChildrenHierarchy($value); |
|
|
|
|
108
|
|
|
}); |
109
|
|
|
} |
110
|
|
|
|
111
|
|
|
public function loopForNestedViews($views): array |
112
|
|
|
{ |
113
|
|
|
$generated = []; |
114
|
|
|
|
115
|
|
|
if (!is_array($views)) { |
116
|
|
|
return $this->loopForNestedViews($this->retrieveNestedViews($views)); |
117
|
|
|
} |
118
|
|
|
|
119
|
|
|
foreach ($views as $view) { |
120
|
|
|
if (!empty($this->loopForNestedViews($view))) { |
121
|
|
|
$generated[$view][] = $this->loopForNestedViews($view); |
122
|
|
|
} else { |
123
|
|
|
$generated[$view] = $this->loopForNestedViews($view); |
124
|
|
|
} |
125
|
|
|
} |
126
|
|
|
|
127
|
|
|
return $generated; |
128
|
|
|
} |
129
|
|
|
|
130
|
|
|
/** |
131
|
|
|
* @return array |
132
|
|
|
*/ |
133
|
|
|
protected function retrieveViewsFromMethod(): array |
134
|
|
|
{ |
135
|
|
|
$views = []; |
136
|
|
|
|
137
|
|
|
$content = $this->action->getContent(); |
|
|
|
|
138
|
|
|
|
139
|
|
|
if (!$content) { |
140
|
|
|
return []; |
141
|
|
|
} |
142
|
|
|
|
143
|
|
|
if (array_key_exists('view', ($content))) { |
144
|
|
|
$views[] = $content['view']; |
145
|
|
|
|
146
|
|
|
return $views; |
147
|
|
|
} |
148
|
|
|
|
149
|
|
|
foreach ($content as $key => $line) { |
150
|
|
|
foreach ($this->viewAliases as $viewAlias) { |
151
|
|
|
if (strpos($line, $viewAlias) !== false) { |
152
|
|
|
$view = $this->getViewFromLine($line, $viewAlias); |
153
|
|
|
|
154
|
|
|
if (empty($view)) { |
155
|
|
|
$view = $this->getViewFromLine($content[$key + 1], $viewAlias); |
156
|
|
|
} |
157
|
|
|
|
158
|
|
|
$views[] = $this->retrieveViewFromLine($view, $viewAlias); |
159
|
|
|
} |
160
|
|
|
} |
161
|
|
|
} |
162
|
|
|
|
163
|
|
|
return $views; |
164
|
|
|
} |
165
|
|
|
|
166
|
|
|
protected function getViewFromLine($line, $viewAlias) |
167
|
|
|
{ |
168
|
|
|
$line = trim($line); |
169
|
|
|
|
170
|
|
|
if (strpos($line, $viewAlias) === false) { |
171
|
|
|
return $line; |
172
|
|
|
} |
173
|
|
|
|
174
|
|
|
return substr($line, strpos($line, $viewAlias) + strlen($viewAlias)); |
175
|
|
|
} |
176
|
|
|
|
177
|
|
|
/** |
178
|
|
|
* @param string $line |
179
|
|
|
* @param string $viewAlias |
180
|
|
|
* |
181
|
|
|
* @return string |
182
|
|
|
*/ |
183
|
|
|
protected function retrieveViewFromLine(string $view, string $viewAlias): string |
|
|
|
|
184
|
|
|
{ |
185
|
|
|
if (strpos($view, ')') !== false) { |
186
|
|
|
$view = substr($view, 0, strpos($view, ')')); |
187
|
|
|
} |
188
|
|
|
|
189
|
|
|
if (($position = strpos($view, ',')) !== false) { |
190
|
|
|
$view = substr($view, 0, $position); |
191
|
|
|
} |
192
|
|
|
|
193
|
|
|
foreach ($this->ignoredStrings as $string) { |
194
|
|
|
$view = str_replace($string, '', $view); |
195
|
|
|
} |
196
|
|
|
|
197
|
|
|
return trim($view); |
198
|
|
|
} |
199
|
|
|
|
200
|
|
|
/** |
201
|
|
|
* @param string $view |
202
|
|
|
* |
203
|
|
|
* @return array |
204
|
|
|
*/ |
205
|
|
|
protected function retrieveNestedViews(string $view): array |
206
|
|
|
{ |
207
|
|
|
$views = []; |
208
|
|
|
|
209
|
|
|
$content = $this->getViewContent($view); |
210
|
|
|
|
211
|
|
|
foreach ($this->bladeDirectives as $key => $bladeDirective) { |
212
|
|
|
$positions = $this->getPositionOfBladeDirectives($bladeDirective, $content); |
213
|
|
|
|
214
|
|
|
foreach ($positions as $position) { |
215
|
|
|
$view = $this->getViewFromLine($content, $bladeDirective); |
216
|
|
|
|
217
|
|
|
$views[] = $this->retrieveViewFromLine($view, $bladeDirective); |
218
|
|
|
} |
219
|
|
|
} |
220
|
|
|
|
221
|
|
|
return $views; |
222
|
|
|
} |
223
|
|
|
|
224
|
|
|
/** |
225
|
|
|
* @param string $bladeDirective |
226
|
|
|
* @param string $content |
227
|
|
|
* |
228
|
|
|
* @return array |
229
|
|
|
*/ |
230
|
|
|
protected function getPositionOfBladeDirectives(string $bladeDirective, ?string $content): array |
231
|
|
|
{ |
232
|
|
|
$positions = []; |
233
|
|
|
|
234
|
|
|
$lastPos = 0; |
235
|
|
|
|
236
|
|
|
while (($lastPos = strpos($content, $bladeDirective, $lastPos)) !== false) { |
237
|
|
|
$positions[] = $lastPos; |
238
|
|
|
$lastPos = $lastPos + strlen($bladeDirective); |
239
|
|
|
} |
240
|
|
|
|
241
|
|
|
return $positions; |
242
|
|
|
} |
243
|
|
|
|
244
|
|
|
/** |
245
|
|
|
* @param string $view |
246
|
|
|
* |
247
|
|
|
* @return string |
248
|
|
|
*/ |
249
|
|
|
public function getViewContent(string $view): ?string |
250
|
|
|
{ |
251
|
|
|
$filesystem = new Filesystem(); |
252
|
|
|
|
253
|
|
|
foreach (config('view.paths') as $viewPath) { |
|
|
|
|
254
|
|
|
$path = $viewPath.'/'.str_replace('.', '/', $view).'.blade.php'; |
255
|
|
|
|
256
|
|
|
if (!$filesystem->exists($path)) { |
257
|
|
|
// View Is Missing |
258
|
|
|
break; |
259
|
|
|
} |
260
|
|
|
|
261
|
|
|
return $filesystem->get($path); |
262
|
|
|
} |
263
|
|
|
|
264
|
|
|
return null; |
265
|
|
|
} |
266
|
|
|
|
267
|
|
|
/** |
268
|
|
|
* @return array |
269
|
|
|
*/ |
270
|
|
|
public function getViews(): array |
271
|
|
|
{ |
272
|
|
|
return collect(array_merge($this->childrenViews, $this->parent)) |
273
|
|
|
->unique() |
274
|
|
|
->flatMap(function ($view) { |
275
|
|
|
return [ |
276
|
|
|
$view => 0, |
277
|
|
|
]; |
278
|
|
|
})->toArray(); |
279
|
|
|
} |
280
|
|
|
|
281
|
|
|
/** |
282
|
|
|
* @return ParserActionInterface |
283
|
|
|
*/ |
284
|
|
|
public function getAction(): ParserActionInterface |
285
|
|
|
{ |
286
|
|
|
return $this->action; |
287
|
|
|
} |
288
|
|
|
|
289
|
|
|
/** |
290
|
|
|
* @return array |
291
|
|
|
*/ |
292
|
|
|
public function getParent(): array |
293
|
|
|
{ |
294
|
|
|
return $this->parent; |
295
|
|
|
} |
296
|
|
|
|
297
|
|
|
/** |
298
|
|
|
* @return array |
299
|
|
|
*/ |
300
|
|
|
public function getChildren(): array |
301
|
|
|
{ |
302
|
|
|
return $this->children; |
303
|
|
|
} |
304
|
|
|
} |
305
|
|
|
|
This check looks for function or method calls that always return null and whose return value is used.
The method
getObject()
can return nothing but null, so it makes no sense to use the return value.The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.