170 lines
5.5 KiB
PHP
170 lines
5.5 KiB
PHP
<?php
|
|
|
|
namespace WizdomNetworks\WizeWeb\Utils;
|
|
|
|
/**
|
|
* Utility class to inspect declared classes and autoloading in the application.
|
|
*/
|
|
class ClassInspector
|
|
{
|
|
/**
|
|
* Get all declared classes within a given namespace.
|
|
*
|
|
* @param string $namespace The namespace to filter by.
|
|
* @return array An array of fully qualified class names in the namespace.
|
|
*/
|
|
public static function getClassesInNamespace(string $namespace): array
|
|
{
|
|
$classes = get_declared_classes();
|
|
$namespaceClasses = [];
|
|
|
|
foreach ($classes as $class) {
|
|
if (str_starts_with($class, $namespace . '\\')) {
|
|
$namespaceClasses[] = $class;
|
|
}
|
|
}
|
|
|
|
return $namespaceClasses;
|
|
}
|
|
|
|
/**
|
|
* Detect the top-level namespace of the current application.
|
|
* Assumes PSR-4 autoloading and looks at composer.json.
|
|
*
|
|
* @return string|null The detected namespace, or null if not found.
|
|
*/
|
|
public static function getTopLevelNamespace(): ?string
|
|
{
|
|
$composerFile = __DIR__ . '/../../composer.json'; // Adjust path as needed
|
|
|
|
if (!file_exists($composerFile)) {
|
|
return null;
|
|
}
|
|
|
|
$composerData = json_decode(file_get_contents($composerFile), true);
|
|
if (!isset($composerData['autoload']['psr-4'])) {
|
|
return null;
|
|
}
|
|
|
|
$namespaces = array_keys($composerData['autoload']['psr-4']);
|
|
return rtrim($namespaces[0], '\\'); // Return the first namespace as the top-level
|
|
}
|
|
|
|
/**
|
|
* Compare declared classes with all possible classes in the namespace directory.
|
|
*
|
|
* @param string $namespace The namespace to inspect.
|
|
* @param string $baseDir The base directory for the namespace.
|
|
* @return array An array with loaded and not-loaded class information.
|
|
*/
|
|
public static function compareLoadedClasses(string $namespace, string $baseDir): array
|
|
{
|
|
$loadedClasses = self::getClassesInNamespace($namespace);
|
|
|
|
// Get all possible classes from the directory
|
|
$allClasses = [];
|
|
$iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($baseDir));
|
|
foreach ($iterator as $file) {
|
|
if ($file->getExtension() === 'php') {
|
|
$relativePath = str_replace([$baseDir, '/', '.php'], ['', '\\', ''], $file->getPathname());
|
|
$className = $namespace . '\\' . $relativePath;
|
|
$className = str_replace('\\\\', '\\', $className); // Remove double backslashes
|
|
$allClasses[$className] = $file->getPathname();
|
|
}
|
|
}
|
|
|
|
// Separate loaded and not loaded
|
|
$classDetails = [];
|
|
foreach ($allClasses as $className => $path) {
|
|
$status = class_exists($className, true) ? 'Loaded' : 'Not Loaded';
|
|
$classDetails[] = [
|
|
'class' => self::getClassNameOnly($className),
|
|
'path' => $path,
|
|
'status' => $status,
|
|
];
|
|
}
|
|
|
|
return $classDetails;
|
|
}
|
|
|
|
|
|
/**
|
|
* Extract the class name from a fully qualified class name.
|
|
*
|
|
* @param string $class Fully qualified class name.
|
|
* @return string The class name without the namespace.
|
|
*/
|
|
private static function getClassNameOnly(string $class): string
|
|
{
|
|
$parts = explode('\\', $class);
|
|
return end($parts);
|
|
}
|
|
|
|
/**
|
|
* Display the results in a table format.
|
|
*
|
|
* @param string $namespace The namespace to inspect.
|
|
* @param string $baseDir The base directory for the namespace.
|
|
* @param bool $useHtml Whether to generate the table as HTML (default: true).
|
|
* @return void
|
|
*/
|
|
public static function displayClassTable(string $namespace, string $baseDir, bool $useHtml = true): void
|
|
{
|
|
$classDetails = self::compareLoadedClasses($namespace, $baseDir);
|
|
|
|
if ($useHtml) {
|
|
// Generate HTML table
|
|
echo "<table border='1' cellspacing='0' cellpadding='5'>";
|
|
echo "<thead>";
|
|
echo "<tr><th>Class</th><th>Path</th><th>Status</th></tr>";
|
|
echo "</thead>";
|
|
echo "<tbody>";
|
|
|
|
foreach ($classDetails as $detail) {
|
|
echo "<tr>";
|
|
echo "<td>{$detail['class']}</td>";
|
|
echo "<td>{$detail['path']}</td>";
|
|
echo "<td>{$detail['status']}</td>";
|
|
echo "</tr>";
|
|
}
|
|
|
|
echo "</tbody>";
|
|
echo "</table>";
|
|
} else {
|
|
// Generate plain text table
|
|
echo str_pad("Class", 30) . str_pad("Path", 50) . "Status\n";
|
|
echo str_repeat("-", 100) . "\n";
|
|
|
|
foreach ($classDetails as $detail) {
|
|
echo str_pad($detail['class'], 30) .
|
|
str_pad($detail['path'], 50) .
|
|
$detail['status'] . "\n";
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Debug all classes in the top-level namespace, showing a table of results.
|
|
*
|
|
* @param bool $useHtml Whether to generate the table as HTML (default: true).
|
|
* @return void
|
|
*/
|
|
public static function debugTopLevelNamespace(bool $useHtml = true): void
|
|
{
|
|
$namespace = self::getTopLevelNamespace();
|
|
if (!$namespace) {
|
|
echo "Top-level namespace could not be determined.\n";
|
|
return;
|
|
}
|
|
|
|
// Assume PSR-4 base directory is app/ (adjust if needed)
|
|
$baseDir = realpath(__DIR__ . '/../../app');
|
|
if (!$baseDir) {
|
|
echo "Base directory could not be resolved.\n";
|
|
return;
|
|
}
|
|
|
|
self::displayClassTable($namespace, $baseDir, $useHtml);
|
|
}
|
|
}
|