fix(structure): Correct case-sensitivity for Linux compatibility
Rename folders to match PHP PSR-4 autoloading conventions: - schemas → Schemas - shared → Shared - Wordpress → WordPress (in all locations) Fixes deployment issues on Linux servers where filesystem is case-sensitive. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
225
Shared/Infrastructure/Validators/TemplateCallsValidator.php
Normal file
225
Shared/Infrastructure/Validators/TemplateCallsValidator.php
Normal file
@@ -0,0 +1,225 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace ROITheme\Shared\Infrastructure\Validators;
|
||||
|
||||
/**
|
||||
* Validador de llamadas a roi_render_component() en templates
|
||||
*
|
||||
* Verifica que:
|
||||
* - Los nombres de componentes usen kebab-case (guiones, no underscores)
|
||||
* - Los componentes llamados estén registrados en functions-addon.php
|
||||
* - No haya llamadas con nombres inválidos
|
||||
*/
|
||||
final class TemplateCallsValidator implements PhaseValidatorInterface
|
||||
{
|
||||
public function getPhaseNumber(): int|string
|
||||
{
|
||||
return 'templates';
|
||||
}
|
||||
|
||||
public function getPhaseDescription(): string
|
||||
{
|
||||
return 'Template Calls (roi_render_component)';
|
||||
}
|
||||
|
||||
public function validate(string $componentName, string $themePath): ValidationResult
|
||||
{
|
||||
$result = new ValidationResult();
|
||||
$result->addInfo("Validando llamadas a roi_render_component() para: {$componentName}");
|
||||
|
||||
// 1. Obtener componentes registrados en functions-addon.php
|
||||
$registeredComponents = $this->getRegisteredComponents($themePath);
|
||||
$result->addInfo("Componentes registrados: " . count($registeredComponents));
|
||||
|
||||
// 2. Buscar todas las llamadas en templates
|
||||
$templateFiles = $this->getTemplateFiles($themePath);
|
||||
$allCalls = [];
|
||||
$invalidCalls = [];
|
||||
$unregisteredCalls = [];
|
||||
|
||||
foreach ($templateFiles as $file) {
|
||||
$calls = $this->findRenderCalls($file);
|
||||
foreach ($calls as $call) {
|
||||
$allCalls[] = [
|
||||
'file' => basename($file),
|
||||
'line' => $call['line'],
|
||||
'component' => $call['component']
|
||||
];
|
||||
|
||||
// Verificar si usa underscore en lugar de guión
|
||||
if (strpos($call['component'], '_') !== false) {
|
||||
$invalidCalls[] = $call + ['file' => basename($file)];
|
||||
}
|
||||
|
||||
// Verificar si está registrado
|
||||
if (!in_array($call['component'], $registeredComponents)) {
|
||||
// Solo marcar como no registrado si no tiene underscore
|
||||
// (los de underscore ya se marcan como inválidos)
|
||||
if (strpos($call['component'], '_') === false) {
|
||||
$unregisteredCalls[] = $call + ['file' => basename($file)];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Verificar específicamente el componente que se está validando
|
||||
$componentFound = false;
|
||||
$componentCallsCorrect = true;
|
||||
|
||||
foreach ($allCalls as $call) {
|
||||
// Buscar variantes del componente (con guión o underscore)
|
||||
$kebabName = $componentName;
|
||||
$snakeName = str_replace('-', '_', $componentName);
|
||||
|
||||
if ($call['component'] === $kebabName) {
|
||||
$componentFound = true;
|
||||
$result->addInfo("✓ Componente '{$componentName}' llamado correctamente en {$call['file']}:{$call['line']}");
|
||||
} elseif ($call['component'] === $snakeName) {
|
||||
$componentFound = true;
|
||||
$componentCallsCorrect = false;
|
||||
$result->addError(
|
||||
"Llamada incorrecta en {$call['file']}:{$call['line']}: " .
|
||||
"usa '{$snakeName}' (underscore) en lugar de '{$kebabName}' (kebab-case)"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// 4. Reportar errores generales de formato
|
||||
foreach ($invalidCalls as $call) {
|
||||
// Solo reportar si no es el componente actual (ya se reportó arriba)
|
||||
$snakeName = str_replace('-', '_', $componentName);
|
||||
if ($call['component'] !== $snakeName) {
|
||||
$suggestedName = str_replace('_', '-', $call['component']);
|
||||
$result->addWarning(
|
||||
"Llamada con underscore en {$call['file']}:{$call['line']}: " .
|
||||
"'{$call['component']}' debería ser '{$suggestedName}'"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// 5. Reportar componentes no registrados
|
||||
foreach ($unregisteredCalls as $call) {
|
||||
$result->addWarning(
|
||||
"Componente no registrado en {$call['file']}:{$call['line']}: '{$call['component']}'"
|
||||
);
|
||||
}
|
||||
|
||||
// 6. Advertir si el componente no se llama en ningún template
|
||||
if (!$componentFound) {
|
||||
$result->addWarning(
|
||||
"El componente '{$componentName}' no se llama en ningún template. " .
|
||||
"Verifica que esté incluido en single.php, header.php, footer.php u otro template."
|
||||
);
|
||||
}
|
||||
|
||||
// Estadísticas
|
||||
$result->setStat('Templates escaneados', count($templateFiles));
|
||||
$result->setStat('Llamadas totales encontradas', count($allCalls));
|
||||
$result->setStat('Componentes registrados', count($registeredComponents));
|
||||
|
||||
if (!empty($invalidCalls)) {
|
||||
$result->setStat('Llamadas con underscore (error)', count($invalidCalls));
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtiene la lista de componentes registrados en functions-addon.php
|
||||
*/
|
||||
private function getRegisteredComponents(string $themePath): array
|
||||
{
|
||||
$functionsFile = $themePath . '/functions-addon.php';
|
||||
$components = [];
|
||||
|
||||
if (!file_exists($functionsFile)) {
|
||||
return $components;
|
||||
}
|
||||
|
||||
$content = file_get_contents($functionsFile);
|
||||
|
||||
// Buscar patrones: case 'nombre-componente':
|
||||
if (preg_match_all("/case\s+'([a-z0-9-]+)':/", $content, $matches)) {
|
||||
$components = $matches[1];
|
||||
}
|
||||
|
||||
return array_unique($components);
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtiene los archivos de template PHP del tema
|
||||
*/
|
||||
private function getTemplateFiles(string $themePath): array
|
||||
{
|
||||
$templates = [];
|
||||
|
||||
// Archivos principales de template
|
||||
$mainTemplates = [
|
||||
'header.php',
|
||||
'footer.php',
|
||||
'single.php',
|
||||
'page.php',
|
||||
'index.php',
|
||||
'archive.php',
|
||||
'search.php',
|
||||
'sidebar.php',
|
||||
'404.php',
|
||||
'front-page.php',
|
||||
'home.php',
|
||||
];
|
||||
|
||||
foreach ($mainTemplates as $template) {
|
||||
$path = $themePath . '/' . $template;
|
||||
if (file_exists($path)) {
|
||||
$templates[] = $path;
|
||||
}
|
||||
}
|
||||
|
||||
// Buscar en template-parts/
|
||||
$templatePartsDir = $themePath . '/template-parts';
|
||||
if (is_dir($templatePartsDir)) {
|
||||
$iterator = new \RecursiveIteratorIterator(
|
||||
new \RecursiveDirectoryIterator($templatePartsDir)
|
||||
);
|
||||
|
||||
foreach ($iterator as $file) {
|
||||
if ($file->isFile() && $file->getExtension() === 'php') {
|
||||
$templates[] = $file->getPathname();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Buscar templates personalizados (page-*.php, single-*.php)
|
||||
$customTemplates = glob($themePath . '/{page-*.php,single-*.php}', GLOB_BRACE);
|
||||
if ($customTemplates) {
|
||||
$templates = array_merge($templates, $customTemplates);
|
||||
}
|
||||
|
||||
return $templates;
|
||||
}
|
||||
|
||||
/**
|
||||
* Busca llamadas a roi_render_component() en un archivo
|
||||
*/
|
||||
private function findRenderCalls(string $filePath): array
|
||||
{
|
||||
$calls = [];
|
||||
$content = file_get_contents($filePath);
|
||||
$lines = explode("\n", $content);
|
||||
|
||||
foreach ($lines as $lineNum => $line) {
|
||||
// Buscar: roi_render_component('nombre') o roi_render_component("nombre")
|
||||
if (preg_match_all("/roi_render_component\s*\(\s*['\"]([^'\"]+)['\"]\s*\)/", $line, $matches, PREG_SET_ORDER)) {
|
||||
foreach ($matches as $match) {
|
||||
$calls[] = [
|
||||
'line' => $lineNum + 1,
|
||||
'component' => $match[1]
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $calls;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user