77
88final class NonExistingBladeTemplateSniff implements Sniff
99{
10- private const INVALID_METHOD_CALL = 'Invalid method call ' ;
11-
1210 public const CODE_TEMPLATE_NOT_FOUND = 'TemplateNotFound ' ;
1311 public const CODE_UNKNOWN_VIEW_NAMESPACE = 'UnknownViewNamespace ' ;
1412
15- // @include
16- private const INCLUDE_BLADE_DIRECTIVE = '/@(include|component|extends)\( \'([^ \']++) \'/ ' ;
17-
18- // @includeIf
19- private const CONDITIONAL_INCLUDE_BLADE_DIRECTIVE = '/@(includeIf|includeWhen)\([^,]++,\s*+ \'([^ \']++) \'/ ' ;
20-
2113 /** @var list<non-empty-string> The same as for config('view.paths') */
2214 public array $ viewPaths = [
2315 'resources/views ' ,
@@ -32,6 +24,15 @@ final class NonExistingBladeTemplateSniff implements Sniff
3224 /** @var array<string, bool> */
3325 private array $ checkedFiles = [];
3426
27+ private BladeTemplateExtractor $ bladeExtractor ;
28+ private PhpViewExtractor $ phpExtractor ;
29+
30+ public function __construct ()
31+ {
32+ $ this ->bladeExtractor = new BladeTemplateExtractor ();
33+ $ this ->phpExtractor = new PhpViewExtractor ();
34+ }
35+
3536 /** @inheritDoc */
3637 public function register (): array
3738 {
@@ -56,68 +57,24 @@ public function process(File $phpcsFile, $stackPtr): int // phpcs:ignore Generic
5657 $ tokenContent = $ token ['content ' ];
5758
5859 // Handle Blade directives (found in T_INLINE_HTML tokens)
59- if ($ this ->isBladeIncludeDirective ($ tokenContent )) {
60- $ this ->validateTemplateName ($ this ->getBladeTemplateName ($ tokenContent ), $ phpcsFile , $ position );
61- } elseif ($ this ->isConditionalBladeIncludeDirective ($ tokenContent )) {
62- $ this ->validateTemplateName ($ this ->getConditionalBladeTemplateName ($ tokenContent ), $ phpcsFile , $ position );
63- }
64- // Handle PHP code (found in T_STRING tokens)
65- elseif ($ token ['type ' ] === 'T_STRING ' ) {
66- if ($ this ->isViewFacade ($ tokens , $ position )) {
67- $ this ->validateTemplateName ($ this ->getViewFacadeTemplateName ($ tokens , $ position ), $ phpcsFile , $ position );
68- } elseif ($ this ->isViewFunctionFactory ($ tokens , $ position )) {
69- $ this ->validateTemplateName ($ this ->getViewFunctionFactoryTemplateName ($ tokens , $ position ), $ phpcsFile , $ position );
70- } elseif ($ this ->isViewFunction ($ tokens , $ position )) {
71- $ this ->validateTemplateName ($ this ->getViewFunctionTemplateName ($ tokens , $ position ), $ phpcsFile , $ position );
60+ if ($ this ->bladeExtractor ->isBladeIncludeDirective ($ tokenContent )) {
61+ $ this ->validateTemplateName ($ this ->bladeExtractor ->getBladeTemplateName ($ tokenContent ), $ phpcsFile , $ position );
62+ } elseif ($ this ->bladeExtractor ->isConditionalBladeIncludeDirective ($ tokenContent )) {
63+ $ this ->validateTemplateName ($ this ->bladeExtractor ->getConditionalBladeTemplateName ($ tokenContent ), $ phpcsFile , $ position );
64+ } elseif ($ this ->bladeExtractor ->isEachBladeDirective ($ tokenContent )) {
65+ $ this ->validateTemplateName ($ this ->bladeExtractor ->getEachBladeTemplateName ($ tokenContent ), $ phpcsFile , $ position );
66+ } elseif ($ this ->bladeExtractor ->isFirstBladeDirective ($ tokenContent )) {
67+ $ this ->validateTemplateName ($ this ->bladeExtractor ->getFirstBladeTemplateName ($ tokenContent ), $ phpcsFile , $ position );
68+ } elseif ($ token ['type ' ] === 'T_STRING ' ) { // Handle PHP code (found in T_STRING tokens)
69+ if ($ this ->phpExtractor ->isViewFunction ($ tokens , $ position )) {
70+ $ this ->validateTemplateName ($ this ->phpExtractor ->getViewFunctionTemplateName ($ tokens , $ position ), $ phpcsFile , $ position );
7271 }
7372 }
7473 }
7574
7675 return 0 ;
7776 }
7877
79- private function isBladeIncludeDirective (string $ tokenContent ): bool
80- {
81- return preg_match (self ::INCLUDE_BLADE_DIRECTIVE , $ tokenContent ) === 1 ;
82- }
83-
84- private function isConditionalBladeIncludeDirective (string $ tokenContent ): bool
85- {
86- return preg_match (self ::CONDITIONAL_INCLUDE_BLADE_DIRECTIVE , $ tokenContent ) === 1 ;
87- }
88-
89- private function getBladeTemplateName (string $ tokenContent ): string
90- {
91- if (!$ this ->isBladeIncludeDirective ($ tokenContent )) {
92- throw new \BadMethodCallException (self ::INVALID_METHOD_CALL );
93- }
94-
95- $ matches = [];
96- preg_match (self ::INCLUDE_BLADE_DIRECTIVE , $ tokenContent , $ matches );
97-
98- if (!isset ($ matches [2 ])) {
99- throw new \BadMethodCallException (self ::INVALID_METHOD_CALL );
100- }
101-
102- return (string ) $ matches [2 ];
103- }
104-
105- private function getConditionalBladeTemplateName (string $ tokenContent ): string
106- {
107- if (!$ this ->isConditionalBladeIncludeDirective ($ tokenContent )) {
108- throw new \BadMethodCallException (self ::INVALID_METHOD_CALL );
109- }
110-
111- $ matches = [];
112- preg_match (self ::CONDITIONAL_INCLUDE_BLADE_DIRECTIVE , $ tokenContent , $ matches );
113-
114- if (!isset ($ matches [2 ])) {
115- throw new \BadMethodCallException (self ::INVALID_METHOD_CALL );
116- }
117-
118- return (string ) $ matches [2 ];
119- }
120-
12178 /**
12279 * @param string $templateName In dot notation
12380 * @throws \OutOfBoundsException
@@ -232,89 +189,4 @@ private function validateTemplateName(string $templateName, File $phpcsFile, int
232189 $ this ->reportUnknownViewNamespace ($ phpcsFile , $ stackPtr , $ templateName );
233190 }
234191 }
235-
236- /** @param array<array<string>> $tokens */
237- private function isViewFacade (array $ tokens , int $ position ): bool
238- {
239- if (!isset ($ tokens [$ position + 3 ])) {
240- return false ;
241- }
242-
243- return ($ tokens [$ position ]['content ' ] === 'View ' || $ tokens [$ position ]['content ' ] === 'ViewFacade ' ) &&
244- $ tokens [$ position + 1 ]['type ' ] === 'T_DOUBLE_COLON ' &&
245- $ tokens [$ position + 2 ]['content ' ] === 'make ' &&
246- $ tokens [$ position + 3 ]['type ' ] === 'T_CONSTANT_ENCAPSED_STRING ' ;
247- }
248-
249- /** @param array<array<string>> $tokens */
250- private function getViewFacadeTemplateName (array $ tokens , int $ position ): string // phpcs:ignore SlevomatCodingStandard.Complexity.Cognitive.ComplexityTooHigh
251- {
252- if (!$ this ->isViewFacade ($ tokens , $ position )) {
253- throw new \BadMethodCallException (self ::INVALID_METHOD_CALL );
254- }
255-
256- $ maxLookupPosition = $ position + 14 ;
257- for ($ lookupPosition = $ position + 4 ; $ lookupPosition < $ maxLookupPosition && isset ($ tokens [$ lookupPosition ]); $ lookupPosition ++) {
258- if ($ tokens [$ lookupPosition ]['type ' ] !== 'T_WHITESPACE ' ) {
259- return mb_trim ($ tokens [$ lookupPosition ]['content ' ], '\'" ' );
260- }
261- }
262-
263- throw new \BadMethodCallException ('Unable to find the template name ' );
264- }
265-
266- /** @param array<array<string>> $tokens */
267- private function isViewFunctionFactory (array $ tokens , int $ position ): bool
268- {
269- if (!isset ($ tokens [$ position + 6 ])) {
270- return false ;
271- }
272-
273- return $ tokens [$ position ]['content ' ] === 'view ' &&
274- $ tokens [$ position + 1 ]['content ' ] === '( ' &&
275- $ tokens [$ position + 2 ]['content ' ] === ') ' &&
276- $ tokens [$ position + 3 ]['content ' ] === '-> ' &&
277- $ tokens [$ position + 4 ]['content ' ] === 'make ' &&
278- $ tokens [$ position + 6 ]['type ' ] !== 'T_VARIABLE ' ;
279- }
280-
281- /** @param array<array<string>> $tokens */
282- private function getViewFunctionFactoryTemplateName (array $ tokens , int $ position ): string // phpcs:ignore SlevomatCodingStandard.Complexity.Cognitive.ComplexityTooHigh
283- {
284- if (!$ this ->isViewFunctionFactory ($ tokens , $ position )) {
285- throw new \BadMethodCallException (self ::INVALID_METHOD_CALL );
286- }
287-
288- $ maxLookupPosition = $ position + 16 ;
289- for ($ lookupPosition = $ position + 6 ; $ lookupPosition < $ maxLookupPosition && isset ($ tokens [$ lookupPosition ]); $ lookupPosition ++) {
290- if ($ tokens [$ lookupPosition ]['type ' ] !== 'T_WHITESPACE ' ) {
291- return mb_trim ($ tokens [$ lookupPosition ]['content ' ], '\'" ' );
292- }
293- }
294-
295- throw new \BadMethodCallException ('Unable to find the template name ' );
296- }
297-
298- /** @param array<array<string>> $tokens */
299- private function isViewFunction (array $ tokens , int $ position ): bool
300- {
301- if (!isset ($ tokens [$ position - 1 ], $ tokens [$ position + 2 ])) {
302- return false ;
303- }
304-
305- return $ tokens [$ position - 1 ]['type ' ] === 'T_WHITESPACE ' &&
306- $ tokens [$ position ]['content ' ] === 'view ' &&
307- $ tokens [$ position + 1 ]['content ' ] === '( ' &&
308- $ tokens [$ position + 2 ]['type ' ] === 'T_CONSTANT_ENCAPSED_STRING ' ;
309- }
310-
311- /** @param array<array<string>> $tokens */
312- private function getViewFunctionTemplateName (array $ tokens , int $ position ): string
313- {
314- if (!$ this ->isViewFunction ($ tokens , $ position )) {
315- throw new \BadMethodCallException (self ::INVALID_METHOD_CALL );
316- }
317-
318- return mb_trim ($ tokens [$ position + 2 ]['content ' ], '\'" ' );
319- }
320192}
0 commit comments