You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							349 lines
						
					
					
						
							8.8 KiB
						
					
					
				
			
		
		
	
	
							349 lines
						
					
					
						
							8.8 KiB
						
					
					
				| <?php | |
| /** | |
|  * @link http://www.yiiframework.com/ | |
|  * @copyright Copyright (c) 2008 Yii Software LLC | |
|  * @license http://www.yiiframework.com/license/ | |
|  */ | |
|  | |
| namespace yii\apidoc\templates\html; | |
|  | |
| use yii\apidoc\models\BaseDoc; | |
| use yii\apidoc\models\ConstDoc; | |
| use yii\apidoc\models\EventDoc; | |
| use yii\apidoc\models\MethodDoc; | |
| use yii\apidoc\models\PropertyDoc; | |
| use yii\apidoc\models\TypeDoc; | |
| use yii\apidoc\models\ClassDoc; | |
| use yii\apidoc\models\Context; | |
| use yii\apidoc\models\InterfaceDoc; | |
| use yii\apidoc\models\TraitDoc; | |
| use yii\apidoc\templates\BaseRenderer; | |
| use yii\base\ViewContextInterface; | |
| use yii\console\Controller; | |
| use yii\helpers\Console; | |
| use yii\helpers\Html; | |
| use Yii; | |
| use yii\web\AssetManager; | |
| use yii\web\View; | |
|  | |
| /** | |
|  * The base class for HTML API documentation renderers. | |
|  * | |
|  * @author Carsten Brandt <mail@cebe.cc> | |
|  * @since 2.0 | |
|  */ | |
| abstract class Renderer extends BaseRenderer implements ViewContextInterface | |
| { | |
| 	/** | |
| 	 * @var string directory to use for output of html files. Can be a path alias. | |
| 	 */ | |
| 	public $targetDir; | |
| 	/** | |
| 	 * @var string string to use as the title of the generated page. | |
| 	 */ | |
| 	public $pageTitle = 'Yii Framework 2.0 API Documentation'; | |
| 	/** | |
| 	 * @var string path or alias of the layout file to use. | |
| 	 */ | |
| 	public $layout; | |
| 	/** | |
| 	 * @var string path or alias of the view file to use for rendering types (classes, interfaces, traits). | |
| 	 */ | |
| 	public $typeView = '@yii/apidoc/templates/html/views/type.php'; | |
| 	/** | |
| 	 * @var string path or alias of the view file to use for rendering the index page. | |
| 	 */ | |
| 	public $indexView = '@yii/apidoc/templates/html/views/index.php'; | |
| 	/** | |
| 	 * @var Context the [[Context]] currently being rendered. | |
| 	 */ | |
| 	protected $context; | |
| 	/** | |
| 	 * @var View | |
| 	 */ | |
| 	private $_view; | |
|  | |
| 	/** | |
| 	 * @return View the view instance | |
| 	 */ | |
| 	public function getView() | |
| 	{ | |
| 		if ($this->_view === null) { | |
| 			$this->_view = new View(); | |
| 			$assetPath = Yii::getAlias($this->targetDir) . '/assets'; | |
| 			if (!is_dir($assetPath)) { | |
| 				mkdir($assetPath); | |
| 			} | |
| 			$this->_view->assetManager = new AssetManager([ | |
| 				'basePath' => $assetPath, | |
| 				'baseUrl' => '/assets', | |
| 			]); | |
| 		} | |
| 		return $this->_view; | |
| 	} | |
|  | |
| 	/** | |
| 	 * Renders a given [[Context]]. | |
| 	 * | |
| 	 * @param Context $context the api documentation context to render. | |
| 	 * @param Controller $controller the apidoc controller instance. Can be used to control output. | |
| 	 */ | |
| 	public function render($context, $controller) | |
| 	{ | |
| 		$this->context = $context; | |
| 		$dir = Yii::getAlias($this->targetDir); | |
| 		if (!is_dir($dir)) { | |
| 			mkdir($dir); | |
| 		} | |
|  | |
| 		$types = array_merge($context->classes, $context->interfaces, $context->traits); | |
| 		$typeCount = count($types) + 1; | |
| 		Console::startProgress(0, $typeCount, 'Rendering files: ', false); | |
| 		$done = 0; | |
| 		foreach($types as $type) { | |
| 			$fileContent = $this->renderWithLayout($this->typeView, [ | |
| 				'type' => $type, | |
| 				'docContext' => $context, | |
| 			]); | |
| 			file_put_contents($dir . '/' . $this->generateFileName($type->name), $fileContent); | |
| 			Console::updateProgress(++$done, $typeCount); | |
| 		} | |
| 		$indexFileContent = $this->renderWithLayout($this->indexView, [ | |
| 			'docContext' => $context, | |
| 			'types' => $types, | |
| 		]); | |
| 		file_put_contents($dir . '/index.html', $indexFileContent); | |
| 		Console::updateProgress(++$done, $typeCount); | |
| 		Console::endProgress(true); | |
| 		$controller->stdout('done.' . PHP_EOL, Console::FG_GREEN); | |
| 	} | |
|  | |
| 	protected function renderWithLayout($viewFile, $params) | |
| 	{ | |
| 		$output = $this->getView()->render($viewFile, $params, $this); | |
| 		if ($this->layout !== false) { | |
| 			$params['content'] = $output; | |
| 			return $this->getView()->renderFile($this->layout, $params, $this); | |
| 		} else { | |
| 			return $output; | |
| 		} | |
| 	} | |
|  | |
| 	/** | |
| 	 * creates a link to a type (class, interface or trait) | |
| 	 * @param ClassDoc|InterfaceDoc|TraitDoc $types | |
| 	 * @param BaseDoc $context | |
| 	 * @return string | |
| 	 */ | |
| 	public function typeLink($types, $context = null) | |
| 	{ | |
| 		if (!is_array($types)) { | |
| 			$types = [$types]; | |
| 		} | |
| 		$links = []; | |
| 		foreach($types as $type) { | |
| 			$postfix = ''; | |
| 			if (!is_object($type)) { | |
| 				if (substr($type, -2, 2) == '[]') { | |
| 					$postfix = '[]'; | |
| 					$type = substr($type, 0, -2); | |
| 				} | |
|  | |
| 				if (($t = $this->context->getType(ltrim($type, '\\'))) !== null) { | |
| 					$type = $t; | |
| 				} elseif ($type[0] !== '\\' && ($t = $this->context->getType($this->resolveNamespace($context) . '\\' . ltrim($type, '\\'))) !== null) { | |
| 					$type = $t; | |
| 				} else { | |
| 					ltrim($type, '\\'); | |
| 				} | |
| 			} | |
| 			if (!is_object($type)) { | |
| 				$links[] = $type; | |
| 			} else { | |
| 				$links[] = Html::a( | |
| 					$type->name, | |
| 					null, | |
| 					['href' => $this->generateFileName($type->name)] | |
| 				) . $postfix; | |
| 			} | |
| 		} | |
| 		return implode('|', $links); | |
| 	} | |
|  | |
| 	/** | |
| 	 * creates a link to a subject | |
| 	 * @param PropertyDoc|MethodDoc|ConstDoc|EventDoc $subject | |
| 	 * @param string $title | |
| 	 * @return string | |
| 	 */ | |
| 	public function subjectLink($subject, $title = null) | |
| 	{ | |
| 		if ($title === null) { | |
| 			$title = $subject->name; | |
| 		} | |
| 		if (($type = $this->context->getType($subject->definedBy)) === null) { | |
| 			return $subject->name; | |
| 		} else { | |
| 			$link = $this->generateFileName($type->name); | |
| 			if ($subject instanceof MethodDoc) { | |
| 				$link .= '#' . $subject->name . '()'; | |
| 			} else { | |
| 				$link .= '#' . $subject->name; | |
| 			} | |
| 			$link .= '-detail'; | |
| 			return Html::a($title, null, ['href' => $link]); | |
| 		} | |
| 	} | |
|  | |
| 	/** | |
| 	 * @param BaseDoc $context | |
| 	 */ | |
| 	private function resolveNamespace($context) | |
| 	{ | |
| 		// TODO use phpdoc Context for this | |
| 		if ($context === null) { | |
| 			return ''; | |
| 		} | |
| 		if ($context instanceof TypeDoc) { | |
| 			return $context->namespace; | |
| 		} | |
| 		if ($context->hasProperty('definedBy')) { | |
| 			$type = $this->context->getType($context); | |
| 			if ($type !== null) { | |
| 				return $type->namespace; | |
| 			} | |
| 		} | |
| 		return ''; | |
| 	} | |
|  | |
| 	/** | |
| 	 * @param ClassDoc $class | |
| 	 * @return string | |
| 	 */ | |
| 	public function renderInheritance($class) | |
| 	{ | |
| 		$parents[] = $this->typeLink($class); | |
| 		while ($class->parentClass !== null) { | |
| 			if(isset($this->context->classes[$class->parentClass])) { | |
| 				$class = $this->context->classes[$class->parentClass]; | |
| 				$parents[] = $this->typeLink($class); | |
| 			} else { | |
| 				$parents[] = $class->parentClass; // TODO link to php.net | |
| 				break; | |
| 			} | |
| 		} | |
| 		return implode(" »\n",$parents); | |
| 	} | |
|  | |
| 	/** | |
| 	 * @param array $names | |
| 	 * @return string | |
| 	 */ | |
| 	public function renderInterfaces($names) | |
| 	{ | |
| 		$interfaces = []; | |
| 		sort($names, SORT_STRING); | |
| 		foreach($names as $interface) { | |
| 			if(isset($this->context->interfaces[$interface])) { | |
| 				$interfaces[] = $this->typeLink($this->context->interfaces[$interface]); | |
| 			} else { | |
| 				$interfaces[] = $interface; // TODO link to php.net | |
| 			} | |
| 		} | |
| 		return implode(', ',$interfaces); | |
| 	} | |
|  | |
| 	/** | |
| 	 * @param array $names | |
| 	 * @return string | |
| 	 */ | |
| 	public function renderTraits($names) | |
| 	{ | |
| 		$traits = []; | |
| 		sort($names, SORT_STRING); | |
| 		foreach($names as $trait) { | |
| 			if(isset($this->context->traits[$trait])) { | |
| 				$traits[] = $this->typeLink($this->context->traits[$trait]); | |
| 			} else { | |
| 				$traits[] = $trait; // TODO link to php.net | |
| 			} | |
| 		} | |
| 		return implode(', ',$traits); | |
| 	} | |
|  | |
| 	/** | |
| 	 * @param array $names | |
| 	 * @return string | |
| 	 */ | |
| 	public function renderClasses($names) | |
| 	{ | |
| 		$classes = []; | |
| 		sort($names, SORT_STRING); | |
| 		foreach($names as $class) { | |
| 			if(isset($this->context->classes[$class])) { | |
| 				$classes[] = $this->typeLink($this->context->classes[$class]); | |
| 			} else { | |
| 				$classes[] = $class; // TODO link to php.net | |
| 			} | |
| 		} | |
| 		return implode(', ',$classes); | |
| 	} | |
|  | |
| 	/** | |
| 	 * @param PropertyDoc $property | |
| 	 * @return string | |
| 	 */ | |
| 	public function renderPropertySignature($property) | |
| 	{ | |
| 		return $this->typeLink($property->types) . ' ' . $property->name . ' = ' . ($property->defaultValue === null ? 'null' : $property->defaultValue); | |
| 		// TODO | |
| 		if(!empty($property->signature)) | |
| 			return $property->signature; | |
| 		$sig=''; | |
| 		if(!empty($property->getter)) | |
| 			$sig=$property->getter->signature; | |
| 		if(!empty($property->setter)) | |
| 		{ | |
| 			if($sig!=='') | |
| 				$sig.='<br/>'; | |
| 			$sig.=$property->setter->signature; | |
| 		} | |
| 		return $sig; | |
| 	} | |
|  | |
| 	/** | |
| 	 * @param MethodDoc $method | |
| 	 * @return string | |
| 	 */ | |
| 	public function renderMethodSignature($method) | |
| 	{ | |
| 		$params = []; | |
| 		foreach($method->params as $param) { | |
| 			$params[] = (empty($param->typeHint) ? '' : $param->typeHint . ' ') | |
| 				. ($param->isPassedByReference ? '<b>&</b>' : '') | |
| 				. $param->name | |
| 				. ($param->isOptional ? ' = ' . $param->defaultValue : ''); | |
| 		} | |
|  | |
| 		return ($method->isReturnByReference ? '<b>&</b>' : '') | |
| 			. ($method->returnType === null ? 'void' : $this->typeLink($method->returnTypes)) | |
| 			. ' ' . $method->name . '( ' | |
| 			. implode(', ', $params) | |
| 			. ' )'; | |
| 	} | |
|  | |
| 	protected function generateFileName($typeName) | |
| 	{ | |
| 		return strtolower(str_replace('\\', '_', $typeName)) . '.html'; | |
| 	} | |
|  | |
| 	/** | |
| 	 * Finds the view file corresponding to the specified relative view name. | |
| 	 * @param string $view a relative view name. The name does NOT start with a slash. | |
| 	 * @return string the view file path. Note that the file may not exist. | |
| 	 */ | |
| 	public function findViewFile($view) | |
| 	{ | |
| 		return Yii::getAlias('@yii/apidoc/templates/html/views/' . $view); | |
| 	} | |
| } |