Files
michaelschiemer/src/Framework/Discovery/Plugins/DependencyAnalysisPlugin.php
Michael Schiemer 5050c7d73a docs: consolidate documentation into organized structure
- 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
2025-10-05 11:05:04 +02:00

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());
}
}