* @license http://www.apache.org/licenses/LICENSE-2.0 * @link http://phpsx.org */ class Documentor implements ResolverInterface { /** @var ContextFactory */ private $contextFactory; /** @var TypeResolver */ private $typeResolver; public function __construct() { $this->contextFactory = new ContextFactory(); $this->typeResolver = new TypeResolver(); } /** * @inheritDoc */ public function resolveClass(\ReflectionClass $reflection): ?TypeInterface { if ($reflection->implementsInterface(RecordInterface::class)) { $tag = $this->getTag('extends', $reflection->getDocComment()); if (!empty($tag)) { $context = $this->contextFactory->createFromReflector($reflection); $type = $this->buildType($this->typeResolver->resolve($tag, $context)); return $type; } else { throw new ParserException('Could not determine type of map'); } } else { $tag = $this->getTag('extends', $reflection->getDocComment()); if (!empty($tag)) { $parent = $reflection->getParentClass(); if (!$parent instanceof \ReflectionClass) { // we have no parent class return TypeFactory::getStruct(); } $values = $this->getTemplateValues($reflection, $tag); $keys = $this->getTemplateKeys($parent); $template = array_combine($keys, $values); $reference = TypeFactory::getReference(); $reference->setRef($parent->getName()); if (!empty($template)) { $reference->setTemplate($template); } return $reference; } else { return TypeFactory::getStruct(); } } } /** * @inheritDoc */ public function resolveProperty(\ReflectionProperty $reflection): ?TypeInterface { $tag = $this->getTag('var', $reflection->getDocComment()); if (!empty($tag)) { $context = $this->contextFactory->createFromReflector($reflection); $type = $this->buildType($this->typeResolver->resolve($tag, $context)); if ($type instanceof ScalarType) { $properties = $reflection->getDeclaringClass()->getDefaultProperties(); if (isset($properties[$reflection->getName()])) { $type->setConst($properties[$reflection->getName()]); } } return $type; } return null; } private function buildType(Type $type): ?TypeInterface { if ($type instanceof Types\Object_) { $fqsen = (string) $type->getFqsen(); if ($fqsen === '\\' . Date::class) { return TypeFactory::getString()->setFormat(TypeAbstract::FORMAT_DATE); } elseif ($fqsen === '\\' . DateTime::class || $fqsen === '\\' . \DateTime::class) { return TypeFactory::getString()->setFormat(TypeAbstract::FORMAT_DATETIME); } elseif ($fqsen === '\\' . Time::class) { return TypeFactory::getString()->setFormat(TypeAbstract::FORMAT_TIME); } elseif ($fqsen === '\\' . Duration::class || $fqsen === '\\' . \DateInterval::class) { return TypeFactory::getString()->setFormat(TypeAbstract::FORMAT_DURATION); } elseif ($fqsen === '\\' . Uri::class) { return TypeFactory::getString()->setFormat(TypeAbstract::FORMAT_URI); } elseif (!empty($fqsen)) { if (class_exists($fqsen)) { return TypeFactory::getReference($fqsen); } else { return TypeFactory::getGeneric($type->getFqsen()->getName()); } } } elseif ($type instanceof Types\Collection) { $value = $type->getValueType(); $additionalProperties = $this->buildType($value); if ($additionalProperties instanceof TypeInterface) { return TypeFactory::getMap($additionalProperties); } else { throw new ParserException('Map without type hint'); } } elseif ($type instanceof Types\AbstractList) { $value = $type->getValueType(); $items = $this->buildType($value); if ($items instanceof TypeInterface) { return TypeFactory::getArray($items); } else { throw new ParserException('Array without type hint'); } } elseif ($type instanceof Types\Boolean) { return TypeFactory::getBoolean(); } elseif ($type instanceof Types\Integer) { return TypeFactory::getInteger(); } elseif ($type instanceof Types\Float_) { return TypeFactory::getNumber(); } elseif ($type instanceof Types\String_) { return TypeFactory::getString(); } elseif ($type instanceof Types\Mixed_) { return TypeFactory::getAny(); } elseif ($type instanceof Types\Resource_) { return TypeFactory::getString()->setFormat(TypeAbstract::FORMAT_BINARY); } elseif ($type instanceof Types\Nullable) { return $this->buildType($type->getActualType()); } elseif ($type instanceof Types\Compound) { $oneOf = []; foreach ($type as $typ) { $property = $this->buildType($typ); if ($property instanceof TypeInterface) { $oneOf[] = $property; } } if (count($oneOf) > 1) { return TypeFactory::getUnion($oneOf); } else { return reset($oneOf); } } return null; } private function getTag(string $tag, string $comment): ?string { preg_match('/@' . $tag . ' (.*)\R/', $comment, $matches); return $matches[1] ?? null; } private function getTemplateValues(\ReflectionClass $reflection, string $tag) { $values = []; $context = $this->contextFactory->createFromReflector($reflection); $type = $this->typeResolver->resolve($tag, $context); if ($type instanceof Types\Collection) { $value = $type->getValueType(); if ($value instanceof Types\Object_) { $values[] = (string) $value->getFqsen(); } } return $values; } private function getTemplateKeys(\ReflectionClass $reflection) { $tag = $this->getTag('template', $reflection->getDocComment()); $keys = array_map('trim', explode(',', $tag)); // currently we can handle only one type, since we pare also only one value return array_slice($keys, 0, 1); } } __halt_compiler();----SIGNATURE:----h2+FxFd9nW755QUPeSqQHzWBzvS+kakMiC76CccoHnWy438kdvDKeKfeLmmZ0vugYF2mub3f27MScEsEzjou9rmLKWiO+B0su/1fzGPydjUHJWbI7dLeCjOwfvJO0jt6wn+YIrv1k50LEsvS+qmChdaPQ7HB8EWZxasqry5vY3g6t9dzohHSbDtPm/0Qk7Gfso6USAPOfeFiIwkZRZse039xJ5l4HlgJv9CUNI21zWPBIB70/IHzRavAaWunOOhcOyNgYOCDT/ImOMkMFO9Qr049tQj8RqwmMV7j5XFC4SwnHDK3mebcohvS7PXQY0zoZB9i35+gB9cBNy5ASt0cc3U+w8+6mC3EEYvzMj879iwlpSB5U4zb+UaIlNPUk0DU5hqDbrMr7tQhj4Vb2M32NVpjNFLd1RSa4oVeeAVLAQqHJm5lzJ7g51Njf7FB7vHB23nstUTeCumhq2J6w8etCqk2k/uqbk7S5jbKjUyFaLZaAv4/mFum0hlptrXh82bePIQjWt/mUO7S7D114RXIIPNtftKzsIecxRjAhbawZYg/DcOwQKxMzwEOhfZWyStX64sDfJf0WqgXDLRPQgEUi7wNIc+NalWfcIYD8+tTm3gYbiy0gPh6zNS8RfGlPtIg8pJeQXDs9NQdgRKX37zmOpTX+S+u+epxKSbhmbYOHXo=----ATTACHMENT:----OTkxMTg5NTQ1NTg0MzYwOCA2NDIwNTE2MjEyMjc3OTU1IDU1Mjc4OTUwODQzNzUyNTY=