1<?php 2/** 3 * This file is part of phpDocumentor. 4 * 5 * For the full copyright and license information, please view the LICENSE 6 * file that was distributed with this source code. 7 * 8 * @copyright 2010-2015 Mike van Riel<mike@phpdoc.org> 9 * @license http://www.opensource.org/licenses/mit-license.php MIT 10 * @link http://phpdoc.org 11 */ 12 13namespace phpDocumentor\Reflection\DocBlock; 14 15use phpDocumentor\Reflection\DocBlock\Tags\Example; 16 17/** 18 * Class used to find an example file's location based on a given ExampleDescriptor. 19 */ 20class ExampleFinder 21{ 22 /** @var string */ 23 private $sourceDirectory = ''; 24 25 /** @var string[] */ 26 private $exampleDirectories = []; 27 28 /** 29 * Attempts to find the example contents for the given descriptor. 30 * 31 * @param Example $example 32 * 33 * @return string 34 */ 35 public function find(Example $example) 36 { 37 $filename = $example->getFilePath(); 38 39 $file = $this->getExampleFileContents($filename); 40 if (!$file) { 41 return "** File not found : {$filename} **"; 42 } 43 44 return implode('', array_slice($file, $example->getStartingLine() - 1, $example->getLineCount())); 45 } 46 47 /** 48 * Registers the project's root directory where an 'examples' folder can be expected. 49 * 50 * @param string $directory 51 * 52 * @return void 53 */ 54 public function setSourceDirectory($directory = '') 55 { 56 $this->sourceDirectory = $directory; 57 } 58 59 /** 60 * Returns the project's root directory where an 'examples' folder can be expected. 61 * 62 * @return string 63 */ 64 public function getSourceDirectory() 65 { 66 return $this->sourceDirectory; 67 } 68 69 /** 70 * Registers a series of directories that may contain examples. 71 * 72 * @param string[] $directories 73 */ 74 public function setExampleDirectories(array $directories) 75 { 76 $this->exampleDirectories = $directories; 77 } 78 79 /** 80 * Returns a series of directories that may contain examples. 81 * 82 * @return string[] 83 */ 84 public function getExampleDirectories() 85 { 86 return $this->exampleDirectories; 87 } 88 89 /** 90 * Attempts to find the requested example file and returns its contents or null if no file was found. 91 * 92 * This method will try several methods in search of the given example file, the first one it encounters is 93 * returned: 94 * 95 * 1. Iterates through all examples folders for the given filename 96 * 2. Checks the source folder for the given filename 97 * 3. Checks the 'examples' folder in the current working directory for examples 98 * 4. Checks the path relative to the current working directory for the given filename 99 * 100 * @param string $filename 101 * 102 * @return string|null 103 */ 104 private function getExampleFileContents($filename) 105 { 106 $normalizedPath = null; 107 108 foreach ($this->exampleDirectories as $directory) { 109 $exampleFileFromConfig = $this->constructExamplePath($directory, $filename); 110 if (is_readable($exampleFileFromConfig)) { 111 $normalizedPath = $exampleFileFromConfig; 112 break; 113 } 114 } 115 116 if (!$normalizedPath) { 117 if (is_readable($this->getExamplePathFromSource($filename))) { 118 $normalizedPath = $this->getExamplePathFromSource($filename); 119 } elseif (is_readable($this->getExamplePathFromExampleDirectory($filename))) { 120 $normalizedPath = $this->getExamplePathFromExampleDirectory($filename); 121 } elseif (is_readable($filename)) { 122 $normalizedPath = $filename; 123 } 124 } 125 126 return $normalizedPath && is_readable($normalizedPath) ? file($normalizedPath) : null; 127 } 128 129 /** 130 * Get example filepath based on the example directory inside your project. 131 * 132 * @param string $file 133 * 134 * @return string 135 */ 136 private function getExamplePathFromExampleDirectory($file) 137 { 138 return getcwd() . DIRECTORY_SEPARATOR . 'examples' . DIRECTORY_SEPARATOR . $file; 139 } 140 141 /** 142 * Returns a path to the example file in the given directory.. 143 * 144 * @param string $directory 145 * @param string $file 146 * 147 * @return string 148 */ 149 private function constructExamplePath($directory, $file) 150 { 151 return rtrim($directory, '\\/') . DIRECTORY_SEPARATOR . $file; 152 } 153 154 /** 155 * Get example filepath based on sourcecode. 156 * 157 * @param string $file 158 * 159 * @return string 160 */ 161 private function getExamplePathFromSource($file) 162 { 163 return sprintf( 164 '%s%s%s', 165 trim($this->getSourceDirectory(), '\\/'), 166 DIRECTORY_SEPARATOR, 167 trim($file, '"') 168 ); 169 } 170} 171