<?php
 declare(strict_types=1); namespace SpomkyLabs\Pki\X509\CertificationPath\Policy; use ArrayIterator; use Countable; use IteratorAggregate; use SpomkyLabs\Pki\X509\Certificate\Extension\CertificatePolicy\PolicyInformation; use SpomkyLabs\Pki\X509\Certificate\Extension\CertificatePolicy\PolicyQualifierInfo; use function count; use function in_array; final class PolicyNode implements IteratorAggregate, Countable { private array $children; private PolicyNode|null $parent = null; private function __construct( private readonly string $validPolicy, private readonly array $qualifiers, private array $expectedPolicies ) { $this->children = []; } public static function create(string $validPolicy, array $qualifiers, array $expectedPolicies): self { return new self($validPolicy, $qualifiers, $expectedPolicies); } public static function anyPolicyNode(): self { return self::create(PolicyInformation::OID_ANY_POLICY, [], [PolicyInformation::OID_ANY_POLICY]); } public function validPolicy(): string { return $this->validPolicy; } public function isAnyPolicy(): bool { return $this->validPolicy === PolicyInformation::OID_ANY_POLICY; } public function qualifiers(): array { return $this->qualifiers; } public function hasExpectedPolicy(string $oid): bool { return in_array($oid, $this->expectedPolicies, true); } public function expectedPolicies(): array { return $this->expectedPolicies; } public function setExpectedPolicies(string ...$oids): void { $this->expectedPolicies = $oids; } public function hasChildWithValidPolicy(string $oid): bool { foreach ($this->children as $node) { if ($node->validPolicy() === $oid) { return true; } } return false; } public function addChild(self $node): self { $id = spl_object_hash($node); $node->parent = $this; $this->children[$id] = $node; return $this; } public function children(): array { return array_values($this->children); } public function remove(): self { if ($this->parent !== null) { $id = spl_object_hash($this); unset($this->parent->children[$id], $this->parent); } return $this; } public function hasParent(): bool { return isset($this->parent); } public function parent(): ?self { return $this->parent; } public function parents(): array { if ($this->parent === null) { return []; } $nodes = $this->parent->parents(); $nodes[] = $this->parent; return array_reverse($nodes); } public function walkNodes(callable $fn): void { foreach ($this->children as $node) { $node->walkNodes($fn); } $fn($this); } public function nodeCount(): int { $c = 1; foreach ($this->children as $child) { $c += $child->nodeCount(); } return $c; } public function count(): int { return count($this->children); } public function getIterator(): ArrayIterator { return new ArrayIterator($this->children); } } 