. */ namespace Irstea\NgModelGeneratorBundle\Models\Types; use Irstea\NgModelGeneratorBundle\Exceptions\DomainException; /** * Class Ref. */ class Reference extends AbstractType implements Deferred { private const UNRESOLVED = 0; private const RESOLVING = 1; private const RESOLVED = 2; /** @var Type */ private $target; /** @var string */ private $name; /** @var int */ private $state = self::UNRESOLVED; /** * Reference constructor. */ public function __construct(string $name = 'anonymous reference') { $this->name = $name; $this->target = Unresolved::get(); } /** * Get target. */ public function getTarget(): Type { return $this->target; } /** * {@inheritdoc} */ public function resolveWith(callable $callback): Type { switch ($this->state) { case self::UNRESOLVED: $this->state = self::RESOLVING; return $this->resolve($callback()); case self::RESOLVING: return $this; case self::RESOLVED: return $this->target; default: throw new DomainException('invalid reference state: ' . $this->state); } } /** * {@inheritdoc} */ public function resolve(Type $result): Type { if ($this->state !== self::RESOLVED) { $this->state = self::RESOLVED; $this->target = $result; } return $this->target; } /** * {@inheritdoc} */ private function dereference(): Type { return $this->target instanceof self ? $this->target->dereference() : $this->target; } /** * {@inheritdoc} */ public function getUsage(): string { return $this->dereference()->getUsage(); } /** * {@inheritdoc} */ public function castToStringOrStringArray(string $expr): string { return $this->dereference()->castToStringOrStringArray($expr); } /** * {@inheritdoc} */ public function checkType(string $expr, bool $explicit = false): string { return $this->dereference()->checkType($expr, $explicit); } /** * {@inheritdoc} */ public function getIterator() { yield $this->target; } /** * @return mixed */ public function jsonSerialize() { return spl_object_hash($this); } /** * {@inheritdoc} */ public function __toString() { return '&' . $this->name; } /** * {@inheritdoc} */ public function findType(string $typeClass): ?Type { return parent::findType($typeClass) ?: $this->target->findType($typeClass); } }