File "ProjectFactory.php"

Full Path: /var/www/html/back/vendor/phpdocumentor/reflection/src/phpDocumentor/Reflection/Php/ProjectFactory.php
File size: 7.45 KB
MIME-type: text/x-php
Charset: utf-8

<?php

declare(strict_types=1);

/**
 * This file is part of phpDocumentor.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @link http://phpdoc.org
 */

namespace phpDocumentor\Reflection\Php;

use Override;
use phpDocumentor\Reflection\DocBlockFactory;
use phpDocumentor\Reflection\Exception;
use phpDocumentor\Reflection\File as SourceFile;
use phpDocumentor\Reflection\Fqsen;
use phpDocumentor\Reflection\Php\Expression\ExpressionPrinter;
use phpDocumentor\Reflection\Php\Factory\Class_;
use phpDocumentor\Reflection\Php\Factory\ClassConstant;
use phpDocumentor\Reflection\Php\Factory\ConstructorPromotion;
use phpDocumentor\Reflection\Php\Factory\ContextStack;
use phpDocumentor\Reflection\Php\Factory\Define;
use phpDocumentor\Reflection\Php\Factory\Enum_;
use phpDocumentor\Reflection\Php\Factory\EnumCase;
use phpDocumentor\Reflection\Php\Factory\Function_;
use phpDocumentor\Reflection\Php\Factory\GlobalConstant;
use phpDocumentor\Reflection\Php\Factory\IfStatement;
use phpDocumentor\Reflection\Php\Factory\Interface_;
use phpDocumentor\Reflection\Php\Factory\Method;
use phpDocumentor\Reflection\Php\Factory\Noop;
use phpDocumentor\Reflection\Php\Factory\Property;
use phpDocumentor\Reflection\Php\Factory\Reducer\Attribute;
use phpDocumentor\Reflection\Php\Factory\Reducer\Parameter;
use phpDocumentor\Reflection\Php\Factory\Trait_;
use phpDocumentor\Reflection\Php\Factory\TraitUse;
use phpDocumentor\Reflection\Project as ProjectInterface;
use phpDocumentor\Reflection\ProjectFactory as ProjectFactoryInterface;

use function is_array;

use const PHP_INT_MAX;

/**
 * Factory class to transform files into a project description.
 */
final class ProjectFactory implements ProjectFactoryInterface
{
    private readonly ProjectFactoryStrategies $strategies;

    /**
     * Initializes the factory with a number of strategies.
     *
     * @param ProjectFactoryStrategy[]|ProjectFactoryStrategies $strategies
     */
    public function __construct(array|ProjectFactoryStrategies $strategies)
    {
        $this->strategies = is_array($strategies) ? new ProjectFactoryStrategies($strategies) : $strategies;
    }

    /**
     * Creates a new instance of this factory. With all default strategies.
     */
    public static function createInstance(): self
    {
        $docblockFactory = DocBlockFactory::createInstance();
        $expressionPrinter = new ExpressionPrinter();

        $attributeReducer = new Attribute();
        $parameterReducer = new Parameter($expressionPrinter);

        $methodStrategy =  new Method($docblockFactory, [$attributeReducer, $parameterReducer]);

        $strategies = new ProjectFactoryStrategies(
            [
                new \phpDocumentor\Reflection\Php\Factory\Namespace_(),
                new Class_($docblockFactory, [$attributeReducer]),
                new Enum_($docblockFactory, [$attributeReducer]),
                new EnumCase($docblockFactory, $expressionPrinter, [$attributeReducer]),
                new Define($docblockFactory, $expressionPrinter),
                new GlobalConstant($docblockFactory, $expressionPrinter),
                new ClassConstant($docblockFactory, $expressionPrinter, [$attributeReducer]),
                new Factory\File($docblockFactory, NodesFactory::createInstance()),
                new Function_($docblockFactory, [$attributeReducer, $parameterReducer]),
                new Interface_($docblockFactory, [$attributeReducer]),
                $methodStrategy,
                new Property($docblockFactory, $expressionPrinter, [$attributeReducer, $parameterReducer]),
                new Trait_($docblockFactory, [$attributeReducer]),

                new IfStatement(),
                new TraitUse(),
            ],
        );

        $strategies->addStrategy(
            new ConstructorPromotion($methodStrategy, $docblockFactory, $expressionPrinter, [$attributeReducer, $parameterReducer]),
            1100,
        );
        $strategies->addStrategy(new Noop(), -PHP_INT_MAX);

        return new self($strategies);
    }

    public function addStrategy(
        ProjectFactoryStrategy $strategy,
        int $priority = ProjectFactoryStrategies::DEFAULT_PRIORITY,
    ): void {
        $this->strategies->addStrategy($strategy, $priority);
    }

    /**
     * Creates a project from the set of files.
     *
     * @param SourceFile[] $files
     *
     * @throws Exception When no matching strategy was found.
     */
    #[Override]
    public function create(string $name, array $files): ProjectInterface
    {
        $contextStack = new ContextStack(new Project($name), null);

        foreach ($files as $filePath) {
            $strategy = $this->strategies->findMatching($contextStack, $filePath);
            $strategy->create($contextStack, $filePath, $this->strategies);
        }

        $project = $contextStack->getProject();
        $this->buildNamespaces($project);

        return $project;
    }

    /**
     * Builds the namespace tree with all elements in the project.
     */
    private function buildNamespaces(Project $project): void
    {
        foreach ($project->getFiles() as $file) {
            foreach ($file->getNamespaces() as $namespaceFqsen) {
                $namespace = $this->getNamespaceByName($project, (string) $namespaceFqsen);
                $this->buildNamespace($file, $namespace);
            }
        }
    }

    /**
     * Gets Namespace from the project if it exists, otherwise returns a new namepace
     */
    private function getNamespaceByName(Project $project, string $name): Namespace_
    {
        $existingNamespaces = $project->getNamespaces();

        if (isset($existingNamespaces[$name])) {
            return $existingNamespaces[$name];
        }

        $namespace = new Namespace_(new Fqsen($name));
        $project->addNamespace($namespace);

        return $namespace;
    }

    /**
     * Adds all elements belonging to the namespace to the namespace.
     */
    private function buildNamespace(File $file, Namespace_ $namespace): void
    {
        foreach ($file->getClasses() as $class) {
            if ($namespace->getFqsen() . '\\' . $class->getName() !== (string) $class->getFqsen()) {
                continue;
            }

            $namespace->addClass($class->getFqsen());
        }

        foreach ($file->getInterfaces() as $interface) {
            if ($namespace->getFqsen() . '\\' . $interface->getName() !== (string) $interface->getFqsen()) {
                continue;
            }

            $namespace->addInterface($interface->getFqsen());
        }

        foreach ($file->getFunctions() as $function) {
            if ($namespace->getFqsen() . '\\' . $function->getName() . '()' !== (string) $function->getFqsen()) {
                continue;
            }

            $namespace->addFunction($function->getFqsen());
        }

        foreach ($file->getConstants() as $constant) {
            if (
                $namespace->getFqsen() . '::' . $constant->getName() !== (string) $constant->getFqsen() &&
                $namespace->getFqsen() . '\\' . $constant->getName() !== (string) $constant->getFqsen()
            ) {
                continue;
            }

            $namespace->addConstant($constant->getFqsen());
        }

        foreach ($file->getTraits() as $trait) {
            if ($namespace->getFqsen() . '\\' . $trait->getName() !== (string) $trait->getFqsen()) {
                continue;
            }

            $namespace->addTrait($trait->getFqsen());
        }
    }
}