/**
  * Registers services on the given app.
  *
  * @param Application $app An Application instance.
  *
  * @throws Exception\MissingDependencyException if the application does not have a descriptor.builder service.
  * @throws Exception\MissingDependencyException if the application does not have a serializer service.
  */
 public function register(Application $app)
 {
     if (!isset($app['descriptor.builder'])) {
         throw new Exception\MissingDependencyException('The builder object that is used to construct the ProjectDescriptor is missing');
     }
     if (!isset($app['serializer'])) {
         throw new Exception\MissingDependencyException('The serializer object that is used to read the template configuration with is missing');
     }
     // parameters
     $app['linker.substitutions'] = array('phpDocumentor\\Descriptor\\ProjectDescriptor' => array('files'), 'phpDocumentor\\Descriptor\\FileDescriptor' => array('tags', 'classes', 'interfaces', 'traits', 'functions', 'constants'), 'phpDocumentor\\Descriptor\\ClassDescriptor' => array('tags', 'parent', 'interfaces', 'constants', 'properties', 'methods', 'usedTraits'), 'phpDocumentor\\Descriptor\\InterfaceDescriptor' => array('tags', 'parent', 'constants', 'methods'), 'phpDocumentor\\Descriptor\\TraitDescriptor' => array('tags', 'properties', 'methods', 'usedTraits'), 'phpDocumentor\\Descriptor\\FunctionDescriptor' => array('tags', 'arguments'), 'phpDocumentor\\Descriptor\\MethodDescriptor' => array('tags', 'arguments'), 'phpDocumentor\\Descriptor\\ArgumentDescriptor' => array('types'), 'phpDocumentor\\Descriptor\\PropertyDescriptor' => array('tags', 'types'), 'phpDocumentor\\Descriptor\\ConstantDescriptor' => array('tags', 'types'), 'phpDocumentor\\Descriptor\\Tag\\ParamDescriptor' => array('types'), 'phpDocumentor\\Descriptor\\Tag\\ReturnDescriptor' => array('types'), 'phpDocumentor\\Descriptor\\Tag\\SeeDescriptor' => array('reference'), 'phpDocumentor\\Descriptor\\Type\\CollectionDescriptor' => array('baseType', 'types', 'keyTypes'));
     // services
     $app['compiler'] = $app->share(function ($container) {
         $compiler = new Compiler();
         $compiler->insert(new ElementsIndexBuilder(), ElementsIndexBuilder::COMPILER_PRIORITY);
         $compiler->insert(new MarkerFromTagsExtractor(), MarkerFromTagsExtractor::COMPILER_PRIORITY);
         $compiler->insert(new ExampleTagsEnricher($container['parser.example.finder']), ExampleTagsEnricher::COMPILER_PRIORITY);
         $compiler->insert(new PackageTreeBuilder(), PackageTreeBuilder::COMPILER_PRIORITY);
         $compiler->insert(new NamespaceTreeBuilder(), NamespaceTreeBuilder::COMPILER_PRIORITY);
         $compiler->insert(new ResolveInlineLinkAndSeeTags($container['transformer.routing.queue']), ResolveInlineLinkAndSeeTags::COMPILER_PRIORITY);
         $compiler->insert($container['linker'], Linker::COMPILER_PRIORITY);
         $compiler->insert($container['transformer'], Transformer::COMPILER_PRIORITY);
         $compiler->insert(new Debug($container['monolog'], $container['descriptor.analyzer']), Debug::COMPILER_PRIORITY);
         return $compiler;
     });
     $app['linker'] = $app->share(function ($app) {
         return new Linker($app['linker.substitutions']);
     });
     $app['transformer.behaviour.collection'] = $app->share(function () {
         return new Behaviour\Collection();
     });
     $app['transformer.routing.standard'] = $app->share(function ($container) {
         /** @var ProjectDescriptorBuilder $projectDescriptorBuilder */
         $projectDescriptorBuilder = $container['descriptor.builder'];
         return new Router\StandardRouter($projectDescriptorBuilder);
     });
     $app['transformer.routing.external'] = $app->share(function ($container) {
         return new Router\ExternalRouter($container['config']);
     });
     $app['transformer.routing.queue'] = $app->share(function ($container) {
         $queue = new Router\Queue();
         // TODO: load from app configuration instead of hardcoded
         $queue->insert($container['transformer.routing.external'], 10500);
         $queue->insert($container['transformer.routing.standard'], 10000);
         return $queue;
     });
     $app['transformer.writer.collection'] = $app->share(function ($container) {
         return new Writer\Collection($container['transformer.routing.queue']);
     });
     $this->provideTemplatingSystem($app);
     $app['transformer'] = $app->share(function ($container) {
         $transformer = new Transformer($container['transformer.template.collection'], $container['transformer.writer.collection']);
         $transformer->setBehaviours($container['transformer.behaviour.collection']);
         return $transformer;
     });
     $app->command(new TransformCommand($app['descriptor.builder'], $app['transformer'], $app['compiler']));
     $app->command(new ListCommand($app['transformer.template.factory']));
 }
Exemplo n.º 2
0
 /**
  * @covers \phpDocumentor\Transformer\Router\Queue::match
  */
 public function testNullIsReturnedWhenNoMatchingRuleCanBeFound()
 {
     $nodeName = 'test';
     $this->fixture->insert($this->givenARouterMatchingNodeWithResult($nodeName, false), 0);
     // Act
     $result = $this->fixture->match($nodeName);
     // Assert
     $this->assertNull($result);
 }
 /**
  * Registers services on the given app.
  *
  * @param Application $app An Application instance
  */
 public function register(Application $app)
 {
     if (!isset($app['descriptor.builder'])) {
         throw new Exception\MissingDependencyException('The builder object that is used to construct the ProjectDescriptor is missing');
     }
     if (!isset($app['serializer'])) {
         throw new Exception\MissingDependencyException('The serializer object that is used to read the template configuration with is missing');
     }
     $templateDir = __DIR__ . '/../../../data/templates';
     // vendored installation
     if (file_exists(__DIR__ . '/../../../../templates')) {
         $templateDir = __DIR__ . '/../../../../templates';
     }
     // parameters
     $app['transformer.template.location'] = $templateDir;
     $app['linker.substitutions'] = array('phpDocumentor\\Descriptor\\ProjectDescriptor' => array('files'), 'phpDocumentor\\Descriptor\\FileDescriptor' => array('tags', 'classes', 'interfaces', 'traits'), 'phpDocumentor\\Descriptor\\ClassDescriptor' => array('tags', 'parent', 'interfaces', 'constants', 'properties', 'methods'), 'phpDocumentor\\Descriptor\\InterfaceDescriptor' => array('tags', 'parent', 'constants', 'methods'), 'phpDocumentor\\Descriptor\\TraitDescriptor' => array('tags', 'properties', 'methods'), 'phpDocumentor\\Descriptor\\MethodDescriptor' => array('tags', 'arguments'), 'phpDocumentor\\Descriptor\\ArgumentDescriptor' => array('types'), 'phpDocumentor\\Descriptor\\PropertyDescriptor' => array('tags', 'types'), 'phpDocumentor\\Descriptor\\ConstantDescriptor' => array('tags', 'types'), 'phpDocumentor\\Descriptor\\Tag\\ParamDescriptor' => array('types'), 'phpDocumentor\\Descriptor\\Tag\\ReturnDescriptor' => array('types'), 'phpDocumentor\\Descriptor\\Tag\\SeeDescriptor' => array('reference'));
     // services
     $app['compiler'] = $app->share(function ($container) {
         $compiler = new Compiler();
         $compiler->insert(new ElementsIndexBuilder(), ElementsIndexBuilder::COMPILER_PRIORITY);
         $compiler->insert(new PackageTreeBuilder(), PackageTreeBuilder::COMPILER_PRIORITY);
         $compiler->insert(new NamespaceTreeBuilder(), NamespaceTreeBuilder::COMPILER_PRIORITY);
         $compiler->insert($container['linker'], Linker::COMPILER_PRIORITY);
         $compiler->insert($container['transformer'], Transformer::COMPILER_PRIORITY);
         $compiler->insert(new Debug($container['monolog'], $container['descriptor.analyzer']), Debug::COMPILER_PRIORITY);
         return $compiler;
     });
     $app['linker'] = $app->share(function ($app) {
         return new Linker($app['linker.substitutions']);
     });
     $app['transformer.behaviour.collection'] = $app->share(function () {
         return new Behaviour\Collection();
     });
     $app['transformer.routing.queue'] = $app->share(function () {
         $queue = new Router\Queue();
         // TODO: load from app configuration instead of hardcoded
         $queue->insert(new Router\StandardRouter(), 10000);
         return $queue;
     });
     $app['transformer.writer.collection'] = $app->share(function ($container) {
         return new Writer\Collection($container['transformer.routing.queue']);
     });
     $app['transformer.template.collection'] = $app->share(function ($container) {
         return new Template\Collection($container['transformer.template.location'], $container['serializer']);
     });
     $app['transformer'] = $app->share(function ($container) {
         $transformer = new Transformer($container['transformer.template.collection'], $container['transformer.writer.collection']);
         $transformer->setBehaviours($container['transformer.behaviour.collection']);
         return $transformer;
     });
     $app->command(new TransformCommand($app['descriptor.builder'], $app['transformer'], $app['compiler']));
     $app->command(new ListCommand());
 }
Exemplo n.º 4
0
 /**
  * Uses the currently selected node and transformation to assemble the destination path for the file.
  *
  * The Twig writer accepts the use of a Query to be able to generate output for multiple objects using the same
  * template.
  *
  * The given node is the result of such a query, or if no query given the selected element, and the transformation
  * contains the destination file.
  *
  * Since it is important to be able to generate a unique name per element can the user provide a template variable
  * in the name of the file.
  * Such a template variable always resides between double braces and tries to take the node value of a given
  * query string.
  *
  * Example:
  *
  *   An artefact stating `classes/{{name}}.html` will try to find the
  *   node 'name' as a child of the given $node and use that value instead.
  *
  * @param DescriptorAbstract $node
  * @param Transformation     $transformation
  *
  * @throws \InvalidArgumentException if no artifact is provided and no routing rule matches.
  *
  * @return string|false returns the destination location or false if generation should be aborted.
  */
 protected function getDestinationPath($node, Transformation $transformation)
 {
     $writer = $this;
     if (!$node) {
         throw new \UnexpectedValueException('The transformation node in the twig writer is not expected to be false or null');
     }
     if (!$transformation->getArtifact()) {
         $rule = $this->routers->match($node);
         if (!$rule) {
             throw new \InvalidArgumentException('No matching routing rule could be found for the given node, please provide an artifact location, ' . 'encountered: ' . ($node === null ? 'NULL' : get_class($node)));
         }
         $rule = new ForFileProxy($rule);
         $url = $rule->generate($node);
         if ($url === false || $url[0] !== DIRECTORY_SEPARATOR) {
             return false;
         }
         $path = $transformation->getTransformer()->getTarget() . str_replace('/', DIRECTORY_SEPARATOR, $url);
     } else {
         $path = $transformation->getTransformer()->getTarget() . DIRECTORY_SEPARATOR . $transformation->getArtifact();
     }
     $destination = preg_replace_callback('/{{([^}]+)}}/u', function ($query) use($node, $writer) {
         // strip any surrounding \ or /
         return trim((string) $writer->walkObjectTree($node, $query[1]), '\\/');
     }, $path);
     // replace any \ with the directory separator to be compatible with the
     // current filesystem and allow the next file_exists to do its work
     $destination = str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $destination);
     // create directory if it does not exist yet
     if (!file_exists(dirname($destination))) {
         mkdir(dirname($destination), 0777, true);
     }
     return $destination;
 }
Exemplo n.º 5
0
 /**
  * Returns a relative URL from the webroot if the given FQSEN exists in the project.
  *
  * Example usage inside template would be (where @link is an attribute called link):
  *
  * ```
  * <xsl:value-of select="php:function('phpDocumentor\Plugin\Core\Xslt\Extension::path', string(@link))" />
  * ```
  *
  * @param string $fqsen
  *
  * @return bool|string
  */
 public static function path($fqsen)
 {
     $projectDescriptor = self::$descriptorBuilder->getProjectDescriptor();
     $elementList = $projectDescriptor->getIndexes()->get('elements');
     $node = $fqsen;
     if (isset($elementList[$fqsen])) {
         $node = $elementList[$fqsen];
     } elseif (isset($elementList['~\\' . $fqsen])) {
         $node = $elementList['~\\' . $fqsen];
     }
     $rule = self::$routers->match($node);
     if (!$rule) {
         return '';
     }
     $generatedUrl = $rule->generate($node);
     return $generatedUrl ? ltrim($generatedUrl, '/') : false;
 }
Exemplo n.º 6
0
 /**
  * @param ProjectDescriptor $project
  * @param $element
  * @return false|string
  */
 private function generateUrlForXmlElement(ProjectDescriptor $project, $element)
 {
     $elements = $project->getIndexes()->get('elements');
     $elementFqcn = ($element->parentNode->nodeName === 'namespace' ? '~\\' : '') . $element->nodeValue;
     $node = isset($elements[$elementFqcn]) ? $elements[$elementFqcn] : $element->nodeValue;
     // do not use the normalized version if the element is not found!
     $rule = $this->routers->match($node);
     if (!$rule) {
         throw new \InvalidArgumentException('No matching routing rule could be found for the given node, please provide an artifact location, ' . 'encountered: ' . ($node === null ? 'NULL' : get_class($node)));
     }
     $rule = new ForFileProxy($rule);
     $url = $rule->generate($node);
     return $url;
 }
Exemplo n.º 7
0
 /**
  * Converts the given path to be relative to the root of the documentation
  * target directory.
  *
  * It is not possible to use absolute paths in documentation templates since
  * they may be used locally, or in a subfolder. As such we need to calculate
  * the number of levels to go up from the current document's directory and
  * then append the given path.
  *
  * For example:
  *
  *     Suppose you are in <root>/classes/my/class.html and you want open
  *     <root>/my/index.html then you provide 'my/index.html' to this method
  *     and it will convert it into ../../my/index.html (<root>/classes/my is
  *     two nesting levels until the root).
  *
  * This method does not try to normalize or optimize the paths in order to
  * save on development time and performance, and because it adds no real
  * value.
  *
  * @param string $relative_path
  *
  * @return string
  */
 public function convertToRootPath($relative_path)
 {
     // get the path to the root directory
     $path_parts = explode(DIRECTORY_SEPARATOR, $this->getDestination());
     if (count($path_parts) > 1) {
         $path_to_root = implode('/', array_fill(0, count($path_parts) - 1, '..')) . '/';
     } else {
         $path_to_root = '';
     }
     if (is_string($relative_path) && $relative_path[0] != '@') {
         // append the relative path to the root
         return $path_to_root . ltrim($relative_path, '/');
     }
     $rule = $this->routers->match($relative_path);
     if (!$rule) {
         return null;
     }
     $generatedPath = $rule->generate($relative_path);
     return $generatedPath ? $path_to_root . ltrim($generatedPath, '/') : null;
 }
Exemplo n.º 8
0
 /**
  * Uses the currently selected node and transformation to assemble the destination path for the file.
  *
  * The Twig writer accepts the use of a Query to be able to generate output for multiple objects using the same
  * template.
  *
  * The given node is the result of such a query, or if no query given the selected element, and the transformation
  * contains the destination file.
  *
  * Since it is important to be able to generate a unique name per element can the user provide a template variable
  * in the name of the file.
  * Such a template variable always resides between double braces and tries to take the node value of a given
  * query string.
  *
  * Example:
  *
  *   An artifact stating `classes/{{name}}.html` will try to find the
  *   node 'name' as a child of the given $node and use that value instead.
  *
  * @param DescriptorAbstract $node
  * @param Transformation     $transformation
  *
  * @throws \InvalidArgumentException if no artifact is provided and no routing rule matches.
  * @throws \UnexpectedValueException if the provided node does not contain anything.
  *
  * @return string|false returns the destination location or false if generation should be aborted.
  */
 protected function getDestinationPath($node, Transformation $transformation)
 {
     $writer = $this;
     if (!$node) {
         throw new \UnexpectedValueException('The transformation node in the twig writer is not expected to be false or null');
     }
     if (!$transformation->getArtifact()) {
         $rule = $this->routers->match($node);
         if (!$rule) {
             throw new \InvalidArgumentException('No matching routing rule could be found for the given node, please provide an artifact location, ' . 'encountered: ' . ($node === null ? 'NULL' : get_class($node)));
         }
         $rule = new ForFileProxy($rule);
         $url = $rule->generate($node);
         if ($url === false || $url[0] !== DIRECTORY_SEPARATOR) {
             return false;
         }
         $path = $transformation->getTransformer()->getTarget() . str_replace('/', DIRECTORY_SEPARATOR, $url);
     } else {
         $path = $transformation->getTransformer()->getTarget() . DIRECTORY_SEPARATOR . $transformation->getArtifact();
     }
     $finder = new Pathfinder();
     $destination = preg_replace_callback('/{{([^}]+)}}/', function ($query) use($node, $writer, $finder) {
         // strip any surrounding \ or /
         $filepart = trim((string) current($finder->find($node, $query[1])), '\\/');
         // make it windows proof
         if (extension_loaded('iconv')) {
             $filepart = iconv('UTF-8', 'ASCII//TRANSLIT', $filepart);
         }
         $filepart = strpos($filepart, '/') !== false ? implode('/', array_map('urlencode', explode('/', $filepart))) : implode('\\', array_map('urlencode', explode('\\', $filepart)));
         return $filepart;
     }, $path);
     var_dump($destination);
     // replace any \ with the directory separator to be compatible with the
     // current filesystem and allow the next file_exists to do its work
     $destination = str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $destination);
     // create directory if it does not exist yet
     if (!file_exists(dirname($destination))) {
         mkdir(dirname($destination), 0777, true);
     }
     return $destination;
 }
Exemplo n.º 9
0
 protected function renderLink($path, $presentation)
 {
     $url = false;
     $rule = $this->routers->match($path);
     if ($rule) {
         $generatedUrl = $rule->generate($path);
         $url = $generatedUrl ? ltrim($generatedUrl, '/') : false;
     }
     if (is_string($url) && $url[0] != '/' && strpos($url, 'http://') !== 0 && strpos($url, 'https://') !== 0) {
         $url = $this->convertToRootPath($url);
     }
     switch ($presentation) {
         case 'url':
             // return the first url
             return $url;
         case 'class:short':
             $parts = explode('\\', $path);
             $path = end($parts);
             break;
     }
     return $url ? sprintf('<a href="%s">%s</a>', $url, $path) : $path;
 }