COMPILER_PRIORITY
COMPILER_PRIORITY = 9000
Rebuilds the namespace tree from the elements found in files.
On every compiler pass is the namespace tree rebuild to aid in the process of incremental updates. The Files Collection in the Project Descriptor is the only location where aliases to elements may be serialized.
If the namespace tree were to be persisted then both locations needed to be invalidated if a file were to change.
execute(\phpDocumentor\Descriptor\ProjectDescriptor $project) : mixed
Executes a compiler pass.
This method will execute the business logic associated with a given compiler pass and allow it to manipulate or consumer the Object Graph using the ProjectDescriptor object.
\phpDocumentor\Descriptor\ProjectDescriptor | $project | Representation of the Object Graph that can be manipulated. |
addElementsOfTypeToNamespace(\phpDocumentor\Descriptor\ProjectDescriptor $project, array<mixed,\phpDocumentor\Descriptor\DescriptorAbstract> $elements, string $type) : void
Adds the given elements of a specific type to their respective Namespace Descriptors.
This method will assign the given elements to the namespace as registered in the namespace field of that element. If a namespace does not exist yet it will automatically be created.
\phpDocumentor\Descriptor\ProjectDescriptor | $project | |
array<mixed,\phpDocumentor\Descriptor\DescriptorAbstract> | $elements | Series of elements to add to their respective namespace. |
string | $type | Declares which field of the namespace will be populated with the given series of elements. This name will be transformed to a getter which must exist. Out of performance considerations will no effort be done to verify whether the provided type is valid. |
createNamespaceDescriptorTree(\phpDocumentor\Descriptor\ProjectDescriptor $project, string $namespaceName) : void
Creates a tree of NamespaceDescriptors based on the provided FQNN (namespace name).
This method will examine the namespace name and create a namespace descriptor for each part of the FQNN if it doesn't exist in the namespaces field of the current namespace (starting with the root Namespace in the Project Descriptor),
As an intended side effect this method also populates the elements index of the ProjectDescriptor with all created NamespaceDescriptors. Each index key is prefixed with a tilde (~) so that it will not conflict with other FQSEN's, such as classes or interfaces.
\phpDocumentor\Descriptor\ProjectDescriptor | $project | |
string | $namespaceName | A FQNN of the namespace (and parents) to create. |
<?php
/**
* phpDocumentor
*
* PHP Version 5.3
*
* @copyright 2010-2014 Mike van Riel / Naenius (http://www.naenius.com)
* @license http://www.opensource.org/licenses/mit-license.php MIT
* @link http://phpdoc.org
*/
namespace phpDocumentor\Compiler\Pass;
use phpDocumentor\Compiler\CompilerPassInterface;
use phpDocumentor\Descriptor\Collection;
use phpDocumentor\Descriptor\DescriptorAbstract;
use phpDocumentor\Descriptor\NamespaceDescriptor;
use phpDocumentor\Descriptor\ProjectDescriptor;
/**
* Rebuilds the namespace tree from the elements found in files.
*
* On every compiler pass is the namespace tree rebuild to aid in the process
* of incremental updates. The Files Collection in the Project Descriptor is the
* only location where aliases to elements may be serialized.
*
* If the namespace tree were to be persisted then both locations needed to be
* invalidated if a file were to change.
*/
class NamespaceTreeBuilder implements CompilerPassInterface
{
const COMPILER_PRIORITY = 9000;
/**
* {@inheritDoc}
*/
public function getDescription()
{
return 'Build "namespaces" index and add namespaces to "elements"';
}
/**
* {@inheritDoc}
*/
public function execute(ProjectDescriptor $project)
{
$project->getIndexes()->get('elements', new Collection())->set('~\\', $project->getNamespace());
$project->getIndexes()->get('namespaces', new Collection())->add($project->getNamespace());
foreach ($project->getFiles() as $file) {
$this->addElementsOfTypeToNamespace($project, $file->getConstants()->getAll(), 'constants');
$this->addElementsOfTypeToNamespace($project, $file->getFunctions()->getAll(), 'functions');
$this->addElementsOfTypeToNamespace($project, $file->getClasses()->getAll(), 'classes');
$this->addElementsOfTypeToNamespace($project, $file->getInterfaces()->getAll(), 'interfaces');
$this->addElementsOfTypeToNamespace($project, $file->getTraits()->getAll(), 'traits');
}
}
/**
* Adds the given elements of a specific type to their respective Namespace Descriptors.
*
* This method will assign the given elements to the namespace as registered in the namespace field of that
* element. If a namespace does not exist yet it will automatically be created.
*
* @param ProjectDescriptor $project
* @param DescriptorAbstract[] $elements Series of elements to add to their respective namespace.
* @param string $type Declares which field of the namespace will be populated with the given
* series of elements. This name will be transformed to a getter which must exist. Out of performance
* considerations will no effort be done to verify whether the provided type is valid.
*
* @return void
*/
protected function addElementsOfTypeToNamespace(ProjectDescriptor $project, array $elements, $type)
{
/** @var DescriptorAbstract $element */
foreach ($elements as $element) {
$namespaceName = (string) $element->getNamespace();
// ensure consistency by trimming the slash prefix and then re-appending it.
$namespaceIndexName = '~\\' . ltrim($namespaceName, '\\');
if (!isset($project->getIndexes()->elements[$namespaceIndexName])) {
$this->createNamespaceDescriptorTree($project, $namespaceName);
}
/** @var NamespaceDescriptor $namespace */
$namespace = $project->getIndexes()->elements[$namespaceIndexName];
// replace textual representation with an object representation
$element->setNamespace($namespace);
// add element to namespace
$getter = 'get'.ucfirst($type);
/** @var Collection $collection */
$collection = $namespace->$getter();
$collection->add($element);
}
}
/**
* Creates a tree of NamespaceDescriptors based on the provided FQNN (namespace name).
*
* This method will examine the namespace name and create a namespace descriptor for each part of
* the FQNN if it doesn't exist in the namespaces field of the current namespace (starting with the root
* Namespace in the Project Descriptor),
*
* As an intended side effect this method also populates the *elements* index of the ProjectDescriptor with all
* created NamespaceDescriptors. Each index key is prefixed with a tilde (~) so that it will not conflict with
* other FQSEN's, such as classes or interfaces.
*
* @param ProjectDescriptor $project
* @param string $namespaceName A FQNN of the namespace (and parents) to create.
*
* @see ProjectDescriptor::getNamespace() for the root namespace.
* @see NamespaceDescriptor::getNamespaces() for the child namespaces of a given namespace.
*
* @return void
*/
protected function createNamespaceDescriptorTree(ProjectDescriptor $project, $namespaceName)
{
$parts = explode('\\', ltrim($namespaceName, '\\'));
$fqnn = '';
// this method does not use recursion to traverse the tree but uses a pointer that will be overridden with the
// next item that is to be traversed (child namespace) at the end of the loop.
$pointer = $project->getNamespace();
foreach ($parts as $part) {
$fqnn .= '\\' . $part;
if ($pointer->getChildren()->get($part)) {
$pointer = $pointer->getChildren()->get($part);
continue;
}
// namespace does not exist, create it
$interimNamespaceDescriptor = new NamespaceDescriptor();
$interimNamespaceDescriptor->setParent($pointer);
$interimNamespaceDescriptor->setName($part);
$interimNamespaceDescriptor->setFullyQualifiedStructuralElementName($fqnn);
// add to the pointer's list of children
$pointer->getChildren()->set($part, $interimNamespaceDescriptor);
// add to index
$project->getIndexes()->elements['~' . $fqnn] = $interimNamespaceDescriptor;
$project->getIndexes()->get('namespaces', new Collection())->add($interimNamespaceDescriptor);
// move pointer forward
$pointer = $interimNamespaceDescriptor;
}
}
}