*/ private array $dependencies; /** @var array */ private array $dependents; public function __construct( private ClassName $className, private DependencyType $type, array $dependencies = [], array $dependents = [] ) { $this->dependencies = $dependencies; $this->dependents = $dependents; } /** * Create a new dependency node */ public static function create( ClassName $className, DependencyType $type ): self { return new self($className, $type); } /** * Get the class name this node represents */ public function getClassName(): ClassName { return $this->className; } /** * Get the dependency type (service, value object, etc.) */ public function getType(): DependencyType { return $this->type; } /** * Get all direct dependencies * * @return array */ public function getDependencies(): array { return $this->dependencies; } /** * Get all classes that depend on this class * * @return array */ public function getDependents(): array { return $this->dependents; } /** * Add a dependency to this node */ public function withDependency(DependencyEdge $dependency): self { return new self( $this->className, $this->type, [...$this->dependencies, $dependency], $this->dependents ); } /** * Add a dependent to this node */ public function withDependent(DependencyEdge $dependent): self { return new self( $this->className, $this->type, $this->dependencies, [...$this->dependents, $dependent] ); } /** * Get the dependency count */ public function getDependencyCount(): int { return count($this->dependencies); } /** * Get the dependent count */ public function getDependentCount(): int { return count($this->dependents); } /** * Check if this node has circular dependencies */ public function hasCircularDependency(): bool { foreach ($this->dependencies as $dependency) { if ($dependency->getTarget()->equals($this->className)) { return true; } } return false; } /** * Get complexity score based on dependency and dependent counts */ public function getComplexityScore(): float { $dependencyWeight = count($this->dependencies) * 0.7; $dependentWeight = count($this->dependents) * 0.3; return $dependencyWeight + $dependentWeight; } /** * Check if this is a leaf node (no dependencies) */ public function isLeaf(): bool { return empty($this->dependencies); } /** * Check if this is a root node (no dependents) */ public function isRoot(): bool { return empty($this->dependents); } /** * Get dependency names only * * @return array */ public function getDependencyNames(): array { return array_map( fn (DependencyEdge $edge) => $edge->getTarget()->toString(), $this->dependencies ); } /** * Get dependent names only * * @return array */ public function getDependentNames(): array { return array_map( fn (DependencyEdge $edge) => $edge->getSource()->toString(), $this->dependents ); } /** * Convert to array for serialization * * @return array */ public function toArray(): array { return [ 'class_name' => $this->className->toString(), 'type' => $this->type->value, 'dependency_count' => $this->getDependencyCount(), 'dependent_count' => $this->getDependentCount(), 'complexity_score' => $this->getComplexityScore(), 'is_leaf' => $this->isLeaf(), 'is_root' => $this->isRoot(), 'has_circular_dependency' => $this->hasCircularDependency(), 'dependencies' => array_map( fn (DependencyEdge $edge) => $edge->toArray(), $this->dependencies ), 'dependents' => array_map( fn (DependencyEdge $edge) => $edge->toArray(), $this->dependents ), ]; } /** * Convert to string representation */ public function toString(): string { return sprintf( '%s (%s) [deps: %d, dependents: %d, complexity: %.1f]', $this->className->getShortName(), $this->type->value, $this->getDependencyCount(), $this->getDependentCount(), $this->getComplexityScore() ); } public function __toString(): string { return $this->toString(); } }