[CLEANUP] Improve the @param/@return/@var PHPDoc
[Packages/TYPO3.CMS.git] / typo3 / sysext / fluid / Classes / Service / DocbookGenerator.php
1 <?php
2 namespace TYPO3\CMS\Fluid\Service;
3
4 /* *
5 * This script is backported from the TYPO3 Flow package "TYPO3.Fluid". *
6 * *
7 * It is free software; you can redistribute it and/or modify it under *
8 * the terms of the GNU Lesser General Public License, either version 3 *
9 * of the License, or (at your option) any later version. *
10 * *
11 * The TYPO3 project - inspiring people to share! *
12 * */
13
14 use TYPO3\CMS\Fluid\Core\ViewHelper\ViewHelperInterface;
15
16 /**
17 * XML Schema (XSD) Generator. Will generate an XML schema which can be used for autocompletion
18 * in schema-aware editors like Eclipse XML editor.
19 */
20 class DocbookGenerator extends \TYPO3\CMS\Fluid\Service\AbstractGenerator {
21 /**
22 * Generate the XML Schema definition for a given namespace.
23 *
24 * @param string $namespace Namespace identifier to generate the XSD for, without leading Backslash.
25 * @return string XML Schema definition
26 */
27 public function generateDocbook($namespace) {
28 if (substr($namespace, -1) !== \TYPO3\CMS\Fluid\Fluid::NAMESPACE_SEPARATOR) {
29 $namespace .= \TYPO3\CMS\Fluid\Fluid::NAMESPACE_SEPARATOR;
30 }
31 $classNames = $this->getClassNamesInNamespace($namespace);
32 $xmlRootNode = new \SimpleXMLElement('<?xml version="1.0" encoding="UTF-8"?>
33 <section version="5.0" xmlns="http://docbook.org/ns/docbook"
34 xml:id="fluid.usermanual.standardviewhelpers"
35 xmlns:xl="http://www.w3.org/1999/xlink"
36 xmlns:xi="http://www.w3.org/2001/XInclude"
37 xmlns:xhtml="http://www.w3.org/1999/xhtml"
38 xmlns:svg="http://www.w3.org/2000/svg"
39 xmlns:ns="http://docbook.org/ns/docbook"
40 xmlns:mathml="http://www.w3.org/1998/Math/MathML">
41 <title>Standard View Helper Library</title>
42
43 <para>Should be autogenerated from the tags.</para>
44 </section>');
45 foreach ($classNames as $className) {
46 $this->generateXmlForClassName($className, $namespace, $xmlRootNode);
47 }
48 return $xmlRootNode->asXML();
49 }
50
51 /**
52 * Generate the XML Schema for a given class name.
53 *
54 * @param string $className Class name to generate the schema for.
55 * @param string $namespace Namespace prefix. Used to split off the first parts of the class name.
56 * @param \SimpleXMLElement $xmlRootNode XML root node where the xsd:element is appended.
57 * @return void
58 */
59 protected function generateXmlForClassName($className, $namespace, \SimpleXMLElement $xmlRootNode) {
60 $reflectionClass = new \TYPO3\CMS\Extbase\Reflection\ClassReflection($className);
61 if (!$reflectionClass->isSubclassOf($this->abstractViewHelperReflectionClass)) {
62 return;
63 }
64 $tagName = $this->getTagNameForClass($className, $namespace);
65 $docbookSection = $xmlRootNode->addChild('section');
66 $docbookSection->addChild('title', $tagName);
67 $this->docCommentParser->parseDocComment($reflectionClass->getDocComment());
68 $this->addDocumentation($this->docCommentParser->getDescription(), $docbookSection);
69 $argumentsSection = $docbookSection->addChild('section');
70 $argumentsSection->addChild('title', 'Arguments');
71 $this->addArguments($className, $argumentsSection);
72 return $docbookSection;
73 }
74
75 /**
76 * Add attribute descriptions to a given tag.
77 * Initializes the view helper and its arguments, and then reads out the list of arguments.
78 *
79 * @param string $className Class name where to add the attribute descriptions
80 * @param \SimpleXMLElement $docbookSection DocBook section to add the attributes to.
81 * @return void
82 */
83 protected function addArguments($className, \SimpleXMLElement $docbookSection) {
84 $viewHelper = $this->instanciateViewHelper($className);
85 $argumentDefinitions = $viewHelper->prepareArguments();
86 if (count($argumentDefinitions) === 0) {
87 $docbookSection->addChild('para', 'No arguments defined.');
88 return;
89 }
90 $argumentsTable = $docbookSection->addChild('table');
91 $argumentsTable->addChild('title', 'Arguments');
92 $tgroup = $argumentsTable->addChild('tgroup');
93 $tgroup['cols'] = 4;
94 $this->addArgumentTableRow($tgroup->addChild('thead'), 'Name', 'Type', 'Required', 'Description', 'Default');
95 $tbody = $tgroup->addChild('tbody');
96 foreach ($argumentDefinitions as $argumentDefinition) {
97 $this->addArgumentTableRow($tbody, $argumentDefinition->getName(), $argumentDefinition->getType(), $argumentDefinition->isRequired() ? 'yes' : 'no', $argumentDefinition->getDescription(), $argumentDefinition->getDefaultValue());
98 }
99 }
100
101 /**
102 * Instantiate a view helper.
103 *
104 * @param string $className
105 * @return ViewHelperInterface
106 */
107 protected function instanciateViewHelper($className) {
108 return $this->objectManager->get($className);
109 }
110
111 /**
112 * @param \SimpleXMLElement $parent
113 * @param string $name
114 * @param string $type
115 * @param bool $required
116 * @param string $description
117 * @param string $default
118 * @return void
119 */
120 private function addArgumentTableRow(\SimpleXMLElement $parent, $name, $type, $required, $description, $default) {
121 $row = $parent->addChild('row');
122 $row->addChild('entry', $name);
123 $row->addChild('entry', $type);
124 $row->addChild('entry', $required);
125 $row->addChild('entry', $description);
126 $row->addChild('entry', (string)$default);
127 }
128
129 /**
130 * Add documentation XSD to a given XML node
131 *
132 * As Eclipse renders newlines only on new <xsd:documentation> tags, we wrap every line in a new
133 * <xsd:documentation> tag.
134 * Furthermore, eclipse strips out tags - the only way to prevent this is to have every line wrapped in a
135 * CDATA block AND to replace the < and > with their XML entities. (This is IMHO not XML conformant).
136 *
137 * @param string $documentation Documentation string to add.
138 * @param \SimpleXMLElement $docbookSection Node to add the documentation to
139 * @return void
140 */
141 protected function addDocumentation($documentation, \SimpleXMLElement $docbookSection) {
142 $splitRegex = '/^\\s*(=[^=]+=)$/m';
143 $regex = '/^\\s*(=([^=]+)=)$/m';
144 $matches = preg_split($splitRegex, $documentation, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
145 $currentSection = $docbookSection;
146 foreach ($matches as $singleMatch) {
147 if (preg_match($regex, $singleMatch, $tmp)) {
148 $currentSection = $docbookSection->addChild('section');
149 $currentSection->addChild('title', trim($tmp[2]));
150 } else {
151 $this->addText(trim($singleMatch), $currentSection);
152 }
153 }
154 }
155
156 /**
157 * @param string $text
158 * @param \SimpleXMLElement $parentElement
159 */
160 protected function addText($text, \SimpleXMLElement $parentElement) {
161 $splitRegex = '/
162 (<code(?:.*?)>
163 (?:.*?)
164 <\\/code>)/xs';
165 $regex = '/
166 <code(.*?)>
167 (.*?)
168 <\\/code>/xs';
169 $matches = preg_split($splitRegex, $text, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
170 foreach ($matches as $singleMatch) {
171 if (preg_match($regex, $singleMatch, $tmp)) {
172 preg_match('/title="([^"]+)"/', $tmp[1], $titleMatch);
173 $example = $parentElement->addChild('example');
174 if (count($titleMatch)) {
175 $example->addChild('title', trim($titleMatch[1]));
176 } else {
177 $example->addChild('title', 'Example');
178 }
179 $this->addChildWithCData($example, 'programlisting', trim($tmp[2]));
180 } else {
181 $textParts = explode("\n", $singleMatch);
182 foreach ($textParts as $text) {
183 if (trim($text) === '') {
184 continue;
185 }
186 $this->addChildWithCData($parentElement, 'para', trim($text));
187 }
188 }
189 }
190 }
191
192 }