- Add comprehensive health check system with multiple endpoints - Add Prometheus metrics endpoint - Add production logging configurations (5 strategies) - Add complete deployment documentation suite: * QUICKSTART.md - 30-minute deployment guide * DEPLOYMENT_CHECKLIST.md - Printable verification checklist * DEPLOYMENT_WORKFLOW.md - Complete deployment lifecycle * PRODUCTION_DEPLOYMENT.md - Comprehensive technical reference * production-logging.md - Logging configuration guide * ANSIBLE_DEPLOYMENT.md - Infrastructure as Code automation * README.md - Navigation hub * DEPLOYMENT_SUMMARY.md - Executive summary - Add deployment scripts and automation - Add DEPLOYMENT_PLAN.md - Concrete plan for immediate deployment - Update README with production-ready features All production infrastructure is now complete and ready for deployment.
229 lines
5.3 KiB
PHP
229 lines
5.3 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Framework\Discovery\ValueObjects;
|
|
|
|
use App\Framework\Core\ValueObjects\ClassName;
|
|
|
|
final readonly class DependencyNode
|
|
{
|
|
/** @var array<DependencyEdge> */
|
|
private array $dependencies;
|
|
|
|
/** @var array<DependencyEdge> */
|
|
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<DependencyEdge>
|
|
*/
|
|
public function getDependencies(): array
|
|
{
|
|
return $this->dependencies;
|
|
}
|
|
|
|
/**
|
|
* Get all classes that depend on this class
|
|
*
|
|
* @return array<DependencyEdge>
|
|
*/
|
|
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<string>
|
|
*/
|
|
public function getDependencyNames(): array
|
|
{
|
|
return array_map(
|
|
fn (DependencyEdge $edge) => $edge->getTarget()->toString(),
|
|
$this->dependencies
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Get dependent names only
|
|
*
|
|
* @return array<string>
|
|
*/
|
|
public function getDependentNames(): array
|
|
{
|
|
return array_map(
|
|
fn (DependencyEdge $edge) => $edge->getSource()->toString(),
|
|
$this->dependents
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Convert to array for serialization
|
|
*
|
|
* @return array<string, mixed>
|
|
*/
|
|
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();
|
|
}
|
|
}
|