klitsche/dog

View on GitHub
src/Elements/Class_.php

Summary

Maintainability
C
1 day
Test Coverage
B
85%
<?php

declare(strict_types=1);

namespace Klitsche\Dog\Elements;

use Klitsche\Dog\Enrichers\DataAwareInterface;
use Klitsche\Dog\Enrichers\DataTrait;
use Klitsche\Dog\ProjectInterface;
use phpDocumentor\Reflection\DocBlock;
use phpDocumentor\Reflection\Fqsen;
use phpDocumentor\Reflection\Location;
use phpDocumentor\Reflection\Php;

class Class_ implements ElementInterface, FqsenAwareInterface, DocBlockAwareInterface, ProjectAwareInterface, DataAwareInterface
{
    use DocBlockTrait;
    use ProjectTrait;
    use FqsenTrait;
    use DataTrait;

    public const TYPE = 'Class';

    private Php\Class_ $php;

    private ElementInterface $owner;

    private array $constants;
    private array $properties;
    private array $methods;

    public function __construct(ProjectInterface $project, ElementInterface $owner, Php\Class_ $php)
    {
        $this->setProject($project);
        $this->php = $php;
        $this->owner = $owner;
    }

    public function getId(): string
    {
        return (string) $this->getFqsen();
    }

    public function getElementType(): string
    {
        return self::TYPE;
    }

    public function getOwner(): ?ElementInterface
    {
        return $this->owner;
    }

    public function getPhp(): Php\Class_
    {
        return $this->php;
    }

    public function getName(): string
    {
        return $this->php->getName();
    }

    public function getFile(): File
    {
        return $this->getOwner()->getFile();
    }

    public function getDocBlock(): ?DocBlock
    {
        return $this->php->getDocBlock();
    }

    public function getFqsen(): Fqsen
    {
        return $this->php->getFqsen();
    }

    public function getParent(): ?Fqsen
    {
        return $this->php->getParent();
    }

    public function getLocation(): Location
    {
        return $this->php->getLocation();
    }

    public function isFinal(): bool
    {
        return $this->php->isFinal();
    }

    public function isAbstract(): bool
    {
        return $this->php->isAbstract();
    }

    /**
     * @return Method[]
     */
    public function getMethods(): array
    {
        if (isset($this->methods) === false) {
            $this->methods = [];
            foreach ($this->php->getMethods() as $method) {
                $this->methods[$method->getName()] = new Method(
                    $this->getProject(),
                    $this,
                    $method,
                    $this->findMethodTag($method)
                );
            }
            foreach ($this->getDocBlockTags() as $tag) {
                if ($tag instanceof DocBlock\Tags\Method &&
                    array_key_exists($tag->getMethodName(), $this->methods) === false) {
                    $this->methods[$tag->getMethodName()] = new Method($this->getProject(), $this, null, $tag);
                }
            }
        }

        return $this->methods;
    }

    /**
     * @return Method[]
     */
    public function getAllMethods(): array
    {
        $methods = $this->methods;
        foreach ($this->getUsedTraits() as $usedTrait) {
            /** @var Trait_ $trait */
            $trait = $this->getProject()->getIndex()->getElementByFqsen($usedTrait);
            foreach ($trait->getMethods() as $method) {
                $methods[$method->getName()] = $method;
            }
        }

        return $methods;
    }

    private function findMethodTag(Php\Method $method): ?DocBlock\Tags\Method
    {
        foreach ($this->getDocBlockTags() as $tag) {
            if ($tag instanceof DocBlock\Tags\Method &&
                $tag->getMethodName() === $method->getName()) {
                return $tag;
            }
        }

        return null;
    }

    private function getDocBlockTags(): iterable
    {
        if ($this->php->getDocBlock()) {
            foreach ($this->php->getDocBlock()->getTags() as $tag) {
                yield $tag;
            }
        }
    }

    /**
     * @return Property[]
     */
    public function getProperties(): array
    {
        if (isset($this->properties) === false) {
            $this->properties = [];
            foreach ($this->php->getProperties() as $property) {
                $this->properties[$property->getName()] = new Property(
                    $this->getProject(),
                    $this,
                    $property,
                    $this->findPropertyTag($property)
                );
            }
            foreach ($this->getDocBlockTags() as $tag) {
                if ($tag instanceof DocBlock\Tags\Property &&
                    array_key_exists($tag->getVariableName(), $this->properties) === false) {
                    $this->properties[$tag->getVariableName()] = new Property($this->getProject(), $this, null, $tag);
                }
            }
        }
        return $this->properties;
    }

    private function findPropertyTag(Php\Property $property): ?DocBlock\Tags\Property
    {
        foreach ($this->getDocBlockTags() as $tag) {
            if ($tag instanceof DocBlock\Tags\Property &&
                $tag->getVariableName() === $property->getName()) {
                return $tag;
            }
        }

        return null;
    }

    /**
     * @return Constant[]
     */
    public function getConstants(): array
    {
        if (isset($this->constants) === false) {
            $this->constants = [];
            foreach ($this->php->getConstants() as $fqsen => $constant) {
                $this->constants[$fqsen] = new Constant($this->getProject(), $this, $constant);
            }
        }

        return $this->constants;
    }

    /**
     * @return Fqsen[]
     */
    public function getInterfaces(): array
    {
        return $this->php->getInterfaces();
    }

    /**
     * @return Fqsen[]
     */
    public function getUsedTraits(): array
    {
        return $this->php->getUsedTraits();
    }
}