Completed
Push — develop ( a89061...54507c )
by Jaap
08:53
created

phpDocumentor/Compiler/Pass/PackageTreeBuilder.php (5 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-2018 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\PackageDescriptor;
18
use phpDocumentor\Descriptor\ProjectDescriptor;
19
use phpDocumentor\Descriptor\TagDescriptor;
20
21
/**
22
 * Rebuilds the package tree from the elements found in files.
23
 *
24
 * On every compiler pass is the package tree rebuild to aid in the process
25
 * of incremental updates.
26
 *
27
 * If the package tree were to be persisted then both locations needed to be
28
 * invalidated if a file were to change.
29
 */
30
class PackageTreeBuilder implements CompilerPassInterface
31
{
32
    const COMPILER_PRIORITY = 9001;
33
34
    /**
35
     * {@inheritDoc}
36
     */
37
    public function getDescription()
38
    {
39
        return 'Build "packages" index';
40
    }
41
42
    /**
43
     * Compiles a 'packages' index on the project and create all Package Descriptors necessary.
44
     */
45
    public function execute(ProjectDescriptor $project)
46
    {
47
        $rootPackageDescriptor = new PackageDescriptor();
48
        $rootPackageDescriptor->setName('\\');
49
        $project->getIndexes()->set('packages', new Collection());
50
        $project->getIndexes()->packages['\\'] = $rootPackageDescriptor;
0 ignored issues
show
The property packages does not exist on object<phpDocumentor\Descriptor\Collection>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
51
52
        foreach ($project->getFiles() as $file) {
53
            $this->addElementsOfTypeToPackage($project, [$file], 'files');
54
            $this->addElementsOfTypeToPackage($project, $file->getConstants()->getAll(), 'constants');
55
            $this->addElementsOfTypeToPackage($project, $file->getFunctions()->getAll(), 'functions');
56
            $this->addElementsOfTypeToPackage($project, $file->getClasses()->getAll(), 'classes');
57
            $this->addElementsOfTypeToPackage($project, $file->getInterfaces()->getAll(), 'interfaces');
58
            $this->addElementsOfTypeToPackage($project, $file->getTraits()->getAll(), 'traits');
59
        }
60
    }
61
62
    /**
63
     * Adds the given elements of a specific type to their respective Package Descriptors.
64
     *
65
     * This method will assign the given elements to the package as registered in the package field of that
66
     * element. If a package does not exist yet it will automatically be created.
67
     *
68
     * @param DescriptorAbstract[] $elements Series of elements to add to their respective package.
69
     * @param string $type Declares which field of the package will be populated with the given
70
     * series of elements. This name will be transformed to a getter which must exist. Out of performance
71
     * considerations will no effort be done to verify whether the provided type is valid.
72
     */
73
    protected function addElementsOfTypeToPackage(ProjectDescriptor $project, array $elements, $type)
74
    {
75
        /** @var DescriptorAbstract $element */
76
        foreach ($elements as $element) {
77
            $packageName = '';
78
            $packageTags = $element->getTags()->get('package');
79
            if ($packageTags instanceof Collection) {
80
                $packageTag = $packageTags->getIterator()->current();
81
                if ($packageTag instanceof TagDescriptor) {
82
                    $packageName = $packageTag->getDescription();
83
                }
84
            }
85
86
            $subpackageCollection = $element->getTags()->get('subpackage');
87
            if ($subpackageCollection instanceof Collection && $subpackageCollection->count() > 0) {
88
                $subpackageTag = $subpackageCollection->getIterator()->current();
89
                if ($subpackageTag instanceof TagDescriptor) {
90
                    $packageName .= '\\' . $subpackageTag->getDescription();
91
                }
92
            }
93
94
            // ensure consistency by trimming the slash prefix and then re-appending it.
95
            $packageIndexName = '\\' . ltrim($packageName, '\\');
96
            if (!isset($project->getIndexes()->packages[$packageIndexName])) {
0 ignored issues
show
The property packages does not exist on object<phpDocumentor\Descriptor\Collection>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
97
                $this->createPackageDescriptorTree($project, $packageName);
98
            }
99
100
            /** @var PackageDescriptor $package */
101
            $package = $project->getIndexes()->packages[$packageIndexName];
0 ignored issues
show
The property packages does not exist on object<phpDocumentor\Descriptor\Collection>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
102
103
            // replace textual representation with an object representation
104
            $element->setPackage($package);
105
106
            // add element to package
107
            $getter = 'get' . ucfirst($type);
108
109
            /** @var Collection $collection */
110
            $collection = $package->{$getter}();
111
            $collection->add($element);
112
        }
113
    }
114
115
    /**
116
     * Creates a tree of PackageDescriptors based on the provided FQNN (package name).
117
     *
118
     * This method will examine the package name and create a package descriptor for each part of
119
     * the FQNN if it doesn't exist in the packages field of the current package (starting with the root
120
     * Package in the Project Descriptor),
121
     *
122
     * As an intended side effect this method also populates the *elements* index of the ProjectDescriptor with all
123
     * created PackageDescriptors. Each index key is prefixed with a tilde (~) so that it will not conflict with
124
     * other FQSEN's, such as classes or interfaces.
125
     *
126
     * @param string $packageName A FQNN of the package (and parents) to create.
127
     * @see ProjectDescriptor::getPackage() for the root package.
128
     * @see PackageDescriptor::getChildren() for the child packages of a given package.
129
     */
130
    protected function createPackageDescriptorTree(ProjectDescriptor $project, $packageName)
131
    {
132
        $parts = explode('\\', ltrim($packageName, '\\'));
133
        $fqnn = '';
134
135
        // this method does not use recursion to traverse the tree but uses a pointer that will be overridden with the
136
        // next item that is to be traversed (child package) at the end of the loop.
137
138
        /** @var PackageDescriptor $pointer */
139
        $pointer = $project->getIndexes()->packages['\\'];
0 ignored issues
show
The property packages does not exist on object<phpDocumentor\Descriptor\Collection>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
140
        foreach ($parts as $part) {
141
            $fqnn .= '\\' . $part;
142
            if ($pointer->getChildren()->get($part)) {
143
                $pointer = $pointer->getChildren()->get($part);
144
                continue;
145
            }
146
147
            // package does not exist, create it
148
            $interimPackageDescriptor = new PackageDescriptor();
149
            $interimPackageDescriptor->setParent($pointer);
150
            $interimPackageDescriptor->setName($part);
151
            $interimPackageDescriptor->setFullyQualifiedStructuralElementName($fqnn);
152
153
            // add to the pointer's list of children
154
            $pointer->getChildren()->set($part ?: 'UNKNOWN', $interimPackageDescriptor);
155
156
            // add to index
157
            $project->getIndexes()->packages[$fqnn] = $interimPackageDescriptor;
0 ignored issues
show
The property packages does not exist on object<phpDocumentor\Descriptor\Collection>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
158
159
            // move pointer forward
160
            $pointer = $interimPackageDescriptor;
161
        }
162
    }
163
}
164