get_id() . '-EXCEPTION')) { return; } $lines = explode("\n", $contents); foreach ($lines as $line_number => $line) { $actual_line_number = $line_number + 1; // Skip if line has exception comment if (str_contains($line, '@' . $this->get_id() . '-EXCEPTION')) { continue; } // Skip use statements - those are fine if (preg_match('/^\s*use\s+/', $line)) { continue; } // Skip namespace declarations if (preg_match('/^\s*namespace\s+/', $line)) { continue; } // Skip comments $trimmed = trim($line); if (str_starts_with($trimmed, '//') || str_starts_with($trimmed, '*') || str_starts_with($trimmed, '/*')) { continue; } // Look for inline FQCN references to App\RSpade\Core\Models\ // Pattern 1: \App\RSpade\Core\Models\Something (backslash-prefixed) // Pattern 2: 'App\RSpade\Core\Models\Something' or "..." (string references) // Check for backslash-prefixed FQCN in code if (preg_match('/\\\\App\\\\RSpade\\\\Core\\\\Models\\\\(\w+)/', $line, $matches)) { $model_name = $matches[1]; $this->add_violation( $file_path, $actual_line_number, "Inline FQCN reference to framework model '\\App\\RSpade\\Core\\Models\\{$model_name}' prevents model overrides", trim($line), $this->build_suggestion($model_name), 'high' ); continue; } // Check for string references (for dynamic class usage) if (preg_match('/[\'"]App\\\\RSpade\\\\Core\\\\Models\\\\(\w+)[\'"]/', $line, $matches)) { $model_name = $matches[1]; $this->add_violation( $file_path, $actual_line_number, "String FQCN reference to framework model 'App\\RSpade\\Core\\Models\\{$model_name}' prevents model overrides", trim($line), $this->build_suggestion($model_name, true), 'high' ); } } } /** * Build suggestion for fixing the violation */ private function build_suggestion(string $model_name, bool $is_string = false): string { $suggestions = []; $suggestions[] = "Framework models should be referenced by short class name to allow developer overrides."; $suggestions[] = ""; if ($is_string) { $suggestions[] = "Change:"; $suggestions[] = " \$class = 'App\\RSpade\\Core\\Models\\{$model_name}';"; $suggestions[] = ""; $suggestions[] = "To:"; $suggestions[] = " \$class = '{$model_name}';"; } else { $suggestions[] = "Change:"; $suggestions[] = " \\App\\RSpade\\Core\\Models\\{$model_name}::method()"; $suggestions[] = ""; $suggestions[] = "To:"; $suggestions[] = " \\{$model_name}::method()"; } $suggestions[] = ""; $suggestions[] = "This allows developers to override {$model_name} by creating:"; $suggestions[] = " /rsx/models/" . strtolower(str_replace('_Model', '', $model_name)) . "_model.php"; $suggestions[] = ""; $suggestions[] = "Note: 'use App\\RSpade\\Core\\Models\\{$model_name};' statements are allowed"; $suggestions[] = "because PHP resolves them at parse time before the override system."; return implode("\n", $suggestions); } }