Completed
Push — develop ( 71fd61...bbac44 )
by Jaap
06:03 queued 02:27
created

Compiler/Pass/NamespaceTreeBuilder.php (2 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
/**
3
 * phpDocumentor
4
 *
5
 * PHP Version 5.3
6
 *
7
 * @copyright 2010-2014 Mike van Riel / Naenius (http://www.naenius.com)
8
 * @license   http://www.opensource.org/licenses/mit-license.php MIT
9
 * @link      http://phpdoc.org
10
 */
11
12
namespace phpDocumentor\Compiler\Pass;
13
14
use phpDocumentor\Compiler\CompilerPassInterface;
15
use phpDocumentor\Descriptor\Collection;
16
use phpDocumentor\Descriptor\DescriptorAbstract;
17
use phpDocumentor\Descriptor\NamespaceDescriptor;
18
use phpDocumentor\Descriptor\ProjectDescriptor;
19
use phpDocumentor\Reflection\Fqsen;
20
21
/**
22
 * Rebuilds the namespace tree from the elements found in files.
23
 *
24
 * On every compiler pass is the namespace tree rebuild to aid in the process
25
 * of incremental updates. The Files Collection in the Project Descriptor is the
26
 * only location where aliases to elements may be serialized.
27
 *
28
 * If the namespace tree were to be persisted then both locations needed to be
29
 * invalidated if a file were to change.
30
 */
31
class NamespaceTreeBuilder implements CompilerPassInterface
32
{
33
    const COMPILER_PRIORITY = 9000;
34
35
    /**
36
     * {@inheritDoc}
37
     */
38 1
    public function getDescription()
39
    {
40 1
        return 'Build "namespaces" index and add namespaces to "elements"';
41
    }
42
43
    /**
44
     * {@inheritDoc}
45
     */
46 6
    public function execute(ProjectDescriptor $project)
47
    {
48 6
        $project->getIndexes()->get('elements', new Collection())->set('~\\', $project->getNamespace());
49 6
        $project->getIndexes()->get('namespaces', new Collection())->set('\\', $project->getNamespace());
50
51 6
        foreach ($project->getFiles() as $file) {
52 6
            $this->addElementsOfTypeToNamespace($project, $file->getConstants()->getAll(), 'constants');
53 6
            $this->addElementsOfTypeToNamespace($project, $file->getFunctions()->getAll(), 'functions');
54 6
            $this->addElementsOfTypeToNamespace($project, $file->getClasses()->getAll(), 'classes');
55 6
            $this->addElementsOfTypeToNamespace($project, $file->getInterfaces()->getAll(), 'interfaces');
56 6
            $this->addElementsOfTypeToNamespace($project, $file->getTraits()->getAll(), 'traits');
57
        }
58
59
        /** @var NamespaceDescriptor $namespace */
60 6
        foreach ($project->getIndexes()->get('namespaces')->getAll() as $namespace) {
61 6
            if ($namespace->getNamespace() !== '') {
62 6
                $this->addToParentNamespace($project, $namespace);
63
0 ignored issues
show
Blank line found at end of control structure
Loading history...
64
            }
65
        }
66 6
    }
67
68
    /**
69
     * Adds the given elements of a specific type to their respective Namespace Descriptors.
70
     *
71
     * This method will assign the given elements to the namespace as registered in the namespace field of that
72
     * element. If a namespace does not exist yet it will automatically be created.
73
     *
74
     * @param ProjectDescriptor $project
75
     * @param DescriptorAbstract[] $elements Series of elements to add to their respective namespace.
76
     * @param string $type Declares which field of the namespace will be populated with the given
77
     * series of elements. This name will be transformed to a getter which must exist. Out of performance
78
     * considerations will no effort be done to verify whether the provided type is valid.
79
     *
80
     * @return void
81
     */
82 6
    protected function addElementsOfTypeToNamespace(ProjectDescriptor $project, array $elements, $type)
83
    {
84
        /** @var DescriptorAbstract $element */
85 6
        foreach ($elements as $element) {
86 6
            $namespaceName = (string)$element->getNamespace();
87
            //TODO: find out why this can happen. Some bug in the assembler?
88 6
            if ($namespaceName === '') {
89
                $namespaceName = '\\';
90
            }
91
92 6
            $namespace = $project->getIndexes()->get('namespaces', new Collection())->get($namespaceName);
93
94 6
            if ($namespace === null) {
95 6
                $namespace = new NamespaceDescriptor();
96 6
                $fqsen = new Fqsen($namespaceName);
97 6
                $namespace->setName($fqsen->getName());
98 6
                $namespace->setFullyQualifiedStructuralElementName($fqsen);
99 6
                $namespaceName = substr((string)$fqsen, 0, -strlen($fqsen->getName())-1);
100 6
                $namespace->setNamespace($namespaceName);
101 6
                $project->getIndexes()->get('namespaces')->set((string)$namespace->getFullyQualifiedStructuralElementName(), $namespace);
102 6
                $this->addToParentNamespace($project, $namespace);
103
            }
104
105
            // replace textual representation with an object representation
106 6
            $element->setNamespace($namespace);
107
108
            // add element to namespace
109 6
            $getter = 'get' . ucfirst($type);
110
111
            /** @var Collection $collection */
112 6
            $collection = $namespace->$getter();
113 6
            $collection->add($element);
114
0 ignored issues
show
Blank line found at end of control structure
Loading history...
115
        }
116 6
    }
117
118
    /**
119
     * @param ProjectDescriptor $project
120
     * @param $namespace
121
     */
122 6
    private function addToParentNamespace(ProjectDescriptor $project, NamespaceDescriptor $namespace)
123
    {
124
        /** @var NamespaceDescriptor $parent */
125 6
        $parent = $project->getIndexes()->get('namespaces')->get($namespace->getNamespace());
126 6
        $project->getIndexes()->get('elements')->set(
127 6
            '~' . (string)$namespace->getFullyQualifiedStructuralElementName(),
128 6
            $namespace
129
        );
130
131
        try {
132 6
            if ($parent === null) {
133 6
                $parent = new NamespaceDescriptor();
134 6
                $fqsen = new Fqsen($namespace->getNamespace());
135 6
                $parent->setFullyQualifiedStructuralElementName($fqsen);
136 6
                $parent->setName($fqsen->getName());
137 6
                $namespaceName = substr((string)$fqsen, 0, -strlen($parent->getName())-1);
138 6
                $parent->setNamespace($namespaceName === '' ? '\\' : $namespaceName);
139 6
                $project->getIndexes()->get('namespaces')->set((string)$parent->getFullyQualifiedStructuralElementName(), $parent);
140 6
                $this->addToParentNamespace($project, $parent);
141
            }
142
143 6
            $namespace->setParent($parent);
144 6
            $parent->getChildren()->set($namespace->getName(), $namespace);
145 6
        } catch (\InvalidArgumentException $e) {
146
            //bit hacky but it works for now.
147
            //$project->getNamespace()->getChildren()->add($namespace);
148
        }
149 6
    }
150
}
151