WizdomWeb/app/Utilities/NamespaceUpdater.php

130 lines
4.7 KiB
PHP

<?php
namespace WizdomNetworks\WizeWeb\Utilities;
use WizdomNetworks\WizeWeb\Utilities\Logger;
use WizdomNetworks\WizeWeb\Utilities\ErrorHandler;
/**
* NamespaceUpdater Utility
*
* Provides functionality to update namespaces across PHP files within a given directory.
*/
class NamespaceUpdater
{
/**
* Update namespaces in PHP files within a directory.
*
* @param string $basePath The base directory to scan for PHP files.
* @param string|null $autoloadNamespace The PSR-4 autoload namespace (optional).
*/
public function updateNamespaces(string $basePath, ?string $autoloadNamespace = null): void
{
$basePath = rtrim($basePath, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;
$namespaceBase = $autoloadNamespace ?? $this->getNamespaceFromComposer($basePath) ?? 'App\\';
$namespaceBase = rtrim($namespaceBase, '\\') . '\\';
try {
$phpFiles = $this->findPhpFiles($basePath);
foreach ($phpFiles as $filePath) {
$this->updateNamespace($filePath, $namespaceBase, $basePath);
}
Logger::info("Namespace update complete.");
} catch (\Throwable $e) {
Logger::error("Failed to update namespaces: " . $e->getMessage());
ErrorHandler::exception($e);
}
}
/**
* Retrieve the PSR-4 namespace from composer.json.
*
* @param string $basePath The base path of the project.
* @return string|null The namespace or null if not found.
*/
private function getNamespaceFromComposer(string $basePath): ?string
{
try {
$composerPath = $basePath . 'composer.json';
if (!file_exists($composerPath)) {
Logger::warning("composer.json not found. Using default namespace.");
return null;
}
$composerConfig = json_decode(file_get_contents($composerPath), true);
return $composerConfig['autoload']['psr-4'][array_key_first($composerConfig['autoload']['psr-4'])] ?? null;
} catch (\Throwable $e) {
Logger::error("Failed to read composer.json: " . $e->getMessage());
ErrorHandler::exception($e);
return null;
}
}
/**
* Find all PHP files in a directory, excluding the vendor directory.
*
* @param string $directory The directory to scan.
* @return array The list of PHP file paths.
*/
private function findPhpFiles(string $directory): array
{
$files = [];
try {
$iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($directory));
foreach ($iterator as $file) {
if ($file->getExtension() === 'php' && strpos($file->getPathname(), DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR) === false) {
$files[] = $file->getPathname();
}
}
} catch (\Throwable $e) {
Logger::error("Failed to find PHP files in directory: $directory | Error: " . $e->getMessage());
ErrorHandler::exception($e);
}
return $files;
}
/**
* Update the namespace in a specific PHP file.
*
* @param string $filePath The file to update.
* @param string $namespaceBase The base namespace to use.
* @param string $basePath The base path of the project.
*/
private function updateNamespace(string $filePath, string $namespaceBase, string $basePath): void
{
try {
$relativePath = str_replace($basePath, '', $filePath);
if (strpos($relativePath, 'app/') === 0) {
$relativePath = substr($relativePath, strlen('app/'));
}
$namespaceParts = explode(DIRECTORY_SEPARATOR, dirname($relativePath));
$namespace = $namespaceBase . implode('\\', $namespaceParts);
$content = file_get_contents($filePath);
if (!preg_match('/^namespace\s+[^;]+;/m', $content)) {
Logger::info("Skipping file without namespace: $filePath");
return;
}
if (preg_match('/^namespace\s+' . preg_quote($namespace, '/') . ';$/m', $content)) {
Logger::info("Namespace already correct in file: $filePath");
return;
}
$content = preg_replace('/^namespace\s+[^;]+;/m', "namespace $namespace;", $content);
file_put_contents($filePath, $content);
Logger::info("Updated namespace in file: $filePath");
} catch (\Throwable $e) {
Logger::error("Failed to update namespace in file: $filePath | Error: " . $e->getMessage());
ErrorHandler::exception($e);
}
}
}