- Move 12 markdown files from root to docs/ subdirectories - Organize documentation by category: • docs/troubleshooting/ (1 file) - Technical troubleshooting guides • docs/deployment/ (4 files) - Deployment and security documentation • docs/guides/ (3 files) - Feature-specific guides • docs/planning/ (4 files) - Planning and improvement proposals Root directory cleanup: - Reduced from 16 to 4 markdown files in root - Only essential project files remain: • CLAUDE.md (AI instructions) • README.md (Main project readme) • CLEANUP_PLAN.md (Current cleanup plan) • SRC_STRUCTURE_IMPROVEMENTS.md (Structure improvements) This improves: ✅ Documentation discoverability ✅ Logical organization by purpose ✅ Clean root directory ✅ Better maintainability
169 lines
6.0 KiB
PHP
169 lines
6.0 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Framework\Discovery\Plugins;
|
|
|
|
use App\Framework\Discovery\Analysis\DependencyAnalysisResult;
|
|
use App\Framework\Discovery\Analysis\DependencyAnalyzer;
|
|
use App\Framework\Discovery\DiscoveryDataCollector;
|
|
use App\Framework\Discovery\Results\DiscoveryRegistry;
|
|
use App\Framework\Discovery\ValueObjects\DiscoveredAttribute;
|
|
use App\Framework\Discovery\ValueObjects\FileContext;
|
|
use App\Framework\Filesystem\FilePath;
|
|
use App\Framework\Logging\Logger;
|
|
use App\Framework\Logging\ValueObjects\LogContext;
|
|
use App\Framework\Reflection\ReflectionProvider;
|
|
|
|
final readonly class DependencyAnalysisPlugin implements DiscoveryPlugin
|
|
{
|
|
private DependencyAnalyzer $analyzer;
|
|
|
|
public function __construct(
|
|
private ReflectionProvider $reflectionProvider,
|
|
private ?Logger $logger = null
|
|
) {
|
|
$this->analyzer = new DependencyAnalyzer($this->reflectionProvider, $this->logger);
|
|
}
|
|
|
|
/**
|
|
* Get the name of this plugin
|
|
*/
|
|
public function getName(): string
|
|
{
|
|
return 'dependency_analysis';
|
|
}
|
|
|
|
/**
|
|
* Check if this plugin can process the given file
|
|
*/
|
|
public function canProcess(FilePath $file, FileContext $context): bool
|
|
{
|
|
// Process all PHP files that contain classes
|
|
return $file->hasExtension('php') && !empty($context->getClassNames());
|
|
}
|
|
|
|
/**
|
|
* Process a file and collect dependency information
|
|
*/
|
|
public function processFile(FilePath $file, FileContext $context, DiscoveryDataCollector $collector): void
|
|
{
|
|
$classNames = $context->getClassNames();
|
|
|
|
foreach ($classNames as $className) {
|
|
// Create a discovered attribute for each class to track it
|
|
$attribute = DiscoveredAttribute::create(
|
|
className: $className,
|
|
attributeType: 'DependencyNode',
|
|
instance: null, // Will be filled during analysis
|
|
metadata: [
|
|
'file' => $file->toString(),
|
|
'discovered_at' => date('Y-m-d H:i:s'),
|
|
]
|
|
);
|
|
|
|
$collector->addAttribute($attribute);
|
|
}
|
|
|
|
$this->logger?->debug('Processed file for dependency analysis', LogContext::withData([
|
|
'file' => $file->toString(),
|
|
'classes_found' => count($classNames),
|
|
]));
|
|
}
|
|
|
|
/**
|
|
* Post-process the discovery results to perform dependency analysis
|
|
*/
|
|
public function postProcess(DiscoveryRegistry $registry): DiscoveryRegistry
|
|
{
|
|
$this->logger?->info('Starting post-processing dependency analysis');
|
|
|
|
// Extract all class names from the discovered attributes
|
|
$classNames = [];
|
|
foreach ($registry->getByType('DependencyNode') as $attribute) {
|
|
$classNames[] = $attribute->className;
|
|
}
|
|
|
|
if (empty($classNames)) {
|
|
$this->logger?->warning('No classes found for dependency analysis');
|
|
return $registry;
|
|
}
|
|
|
|
// Perform dependency analysis
|
|
$analysisResult = $this->analyzer->analyzeWithCircularDetection($classNames);
|
|
|
|
// Add analysis result to the registry
|
|
$analysisAttribute = DiscoveredAttribute::create(
|
|
className: 'DependencyAnalysisResult',
|
|
attributeType: 'DependencyAnalysis',
|
|
instance: $analysisResult,
|
|
metadata: [
|
|
'analysis_timestamp' => date('Y-m-d H:i:s'),
|
|
'classes_analyzed' => count($classNames),
|
|
'circular_dependencies' => $analysisResult->getCircularDependencyCount(),
|
|
'statistics' => $analysisResult->getStatistics(),
|
|
]
|
|
);
|
|
|
|
$updatedRegistry = $registry->add($analysisAttribute);
|
|
|
|
// Update individual class attributes with dependency information
|
|
$graph = $analysisResult->getGraph();
|
|
foreach ($registry->getByType('DependencyNode') as $attribute) {
|
|
$node = $graph->getNode(\App\Framework\Core\ValueObjects\ClassName::create($attribute->className));
|
|
if ($node !== null) {
|
|
$updatedAttribute = DiscoveredAttribute::create(
|
|
className: $attribute->className,
|
|
attributeType: 'DependencyNode',
|
|
instance: $node,
|
|
metadata: array_merge($attribute->metadata, [
|
|
'dependency_count' => $node->getDependencyCount(),
|
|
'dependent_count' => $node->getDependentCount(),
|
|
'complexity_score' => $node->getComplexityScore(),
|
|
'type' => $node->getType()->value,
|
|
])
|
|
);
|
|
|
|
$updatedRegistry = $updatedRegistry->replace($attribute, $updatedAttribute);
|
|
}
|
|
}
|
|
|
|
$this->logger?->info('Dependency analysis completed', LogContext::withData([
|
|
'classes_analyzed' => count($classNames),
|
|
'nodes_created' => $graph->getNodeCount(),
|
|
'edges_created' => $graph->getEdgeCount(),
|
|
'circular_dependencies' => $analysisResult->getCircularDependencyCount(),
|
|
]));
|
|
|
|
return $updatedRegistry;
|
|
}
|
|
|
|
/**
|
|
* Get the analysis result from the registry
|
|
*/
|
|
public function getAnalysisResult(DiscoveryRegistry $registry): ?DependencyAnalysisResult
|
|
{
|
|
$analysisAttributes = $registry->getByType('DependencyAnalysis');
|
|
if (empty($analysisAttributes)) {
|
|
return null;
|
|
}
|
|
|
|
$attribute = reset($analysisAttributes);
|
|
return $attribute->instance instanceof DependencyAnalysisResult ? $attribute->instance : null;
|
|
}
|
|
|
|
/**
|
|
* Get recommendations based on the analysis
|
|
*
|
|
* @return array<string, mixed>
|
|
*/
|
|
public function getRecommendations(DiscoveryRegistry $registry): array
|
|
{
|
|
$analysisResult = $this->getAnalysisResult($registry);
|
|
if ($analysisResult === null) {
|
|
return ['error' => 'No dependency analysis results found'];
|
|
}
|
|
|
|
return $this->analyzer->getRecommendations($analysisResult->getGraph());
|
|
}
|
|
} |