1<?php
2/**
3 * PHP_UML
4 *
5 * PHP version 5
6 *
7 * @category PHP
8 * @package  PHP_UML
9 * @author   Baptiste Autin <ohlesbeauxjours@yahoo.fr>
10 * @license  http://www.gnu.org/licenses/lgpl.html LGPL License 3
11 * @version  SVN: $Revision: 180 $
12 * @link     http://pear.php.net/package/PHP_UML
13 * @since    $Date: 2012-05-12 19:33:59 +0200 (sam., 12 mai 2012) $
14 */
15
16/**
17 * General class for an renderer in the HtmlNew implementation
18 *
19 * @category   PHP
20 * @package    PHP_UML
21 * @subpackage Output
22 * @subpackage HtmlNew
23 * @author     Baptiste Autin <ohlesbeauxjours@yahoo.fr>
24 * @license    http://www.gnu.org/licenses/lgpl.html LGPL License 3
25 */
26abstract class PHP_UML_Output_HtmlNew_DocElement extends PHP_UML_Output_ApiRenderer
27{
28    const FILE_EXT = 'htm';
29
30    const RESOURCES_DIRNAME = '$resources';
31    const HELP_FILENAME     = 'help';
32    const INDEX_FILENAME    = 'index';
33    const INDEXALL_FILENAME = 'index-all';
34    const MENU_FILENAME     = 'menu';
35    const JS_MAIN_NAME      = 'MainList';
36    const TEMPLATES_DIRNAME = 'templates';
37
38    /**
39     * Constructor
40     *
41     * @param PHP_UML_Output_ExporterAPI $exporter Reference to an exporter
42     */
43    public function __construct(PHP_UML_Output_ExporterAPI $exporter)
44    {
45        parent::__construct($exporter);
46        $this->mainTpl = $this->getTemplate('main.htm');
47    }
48
49    protected function getDescription(PHP_UML_Metamodel_Stereotype $s, $annotatedElement='')
50    {
51        $tag = PHP_UML_Metamodel_Helper::getStereotypeTag($s, 'description');
52        if (!is_null($tag))
53            return nl2br(htmlspecialchars($tag->value));
54        else
55            return '';
56    }
57
58    /**
59     * Renders the operation's parameters, as a comma-sep list, between brackets
60     *
61     * @param PHP_UML_Metamodel_Operation $operation The operation
62     * @param bool                        $withType  If true, adds an hyperlink
63     *
64     * @return string
65     */
66    protected function getParameterList(PHP_UML_Metamodel_Operation $operation, $withType = false)
67    {
68        $n      = count($operation->ownedParameter);
69        $pieces = array();
70        for ($i=0; $i<$n; $i++) {
71            $parameter = $operation->ownedParameter[$i];
72            if (substr($parameter->direction, 0, 2)=='in') {
73                $str = '';
74                if ($withType && isset($parameter->type)) {
75                    if (is_object($parameter->type))
76                        $str .= $this->getLinkTo($parameter->type).' ';
77                    else
78                        $str .= $this->displayUnresolved($parameter->type);
79                }
80                if ($parameter->direction=='inout') {
81                    $str .= '&#38;';
82                }
83                $str .= $parameter->name;
84                $str .= $this->getDefaultValue($parameter);
85                $pieces[] = $str;
86            }
87        }
88        return '('.implode(', ', $pieces).')';
89    }
90
91    protected function getDefaultValue(PHP_UML_Metamodel_TypedElement $obj)
92    {
93        if ($obj->default!='')
94            return '<span class="defVal"> = '.htmlentities($obj->default, ENT_QUOTES).'</span>';
95        else
96            return '';
97    }
98
99    /**
100     * Renders a HTML hyperlink towards a given element
101     * (since datatypes don't own to a "package",  we suppose they are located in
102     * the top package)
103     *
104     * @param PHP_UML_Metamodel_Classifier $t        The element
105     * @param string                       $cssStyle CSS style to use
106     *
107     * @return string
108     */
109    protected function getLinkTo(PHP_UML_Metamodel_Classifier $t, $cssStyle='link')
110    {
111        $loc = '';
112        $ns  = '';
113        if (isset($t->package)) {
114            $loc = $this->getAbsPath($t->package);
115            $ns  = $this->getAbsPath($t->package, self::T_NAMESPACE);
116        }
117        return '<a href="'.$this->getContextPackage()->rpt.$loc.self::getObjPrefix($t).$t->name.'.'.
118            self::FILE_EXT.'" class="'.$cssStyle.'">'.$ns.$t->name.'</a>';
119    }
120
121    /**
122     * Renders an unresolved type as an HTML span
123     *
124     * @param string $type Type, provided as a string
125     *
126     * @return string
127     */
128    protected function displayUnresolved($type)
129    {
130        return '<span class="link">'.$type.'</span> ';
131    }
132
133
134    /**
135     * Renders the properties of a given stereotype as an HTML list (LI tags).
136     * Docblocks in $ignoredTag are not shown, as well as "return" tag with only a type
137     *
138     * @param PHP_UML_Metamodel_Stereotype $s A stereotype
139     *
140     * @return string
141     */
142    protected function getTagsAsList(PHP_UML_Metamodel_Stereotype $s)
143    {
144        $str = '';
145        foreach ($s->ownedAttribute as $tag) {
146            if (!(in_array($tag->name, $this->ignoredTag) || ($tag->name=='return' && strpos($tag->value, ' ')===false))) {
147                if ($tag->name!='description') {
148                    $str .= '<li class="smaller">';
149                    $str .= '@'.$tag->name.' ';
150                } else {
151                    $str .= '<li>';
152                }
153                if (strlen($tag->value)>0)
154                    $str .= nl2br(htmlspecialchars($tag->value));
155                $str .= '</li>';
156            }
157        }
158        return $str;
159    }
160
161
162    /**
163     * Renders the block "Properties" of a package or a class as HTML
164     *
165     * @param PHP_UML_Metamodel_NamedElement $p A classifier/a package
166     *
167     * @return string
168     */
169    protected function getPropertyBlock(PHP_UML_Metamodel_NamedElement $p)
170    {
171        if (empty($p->ownedAttribute))
172            return '';
173
174        $str  = '<h2>Properties</h2>';
175        $str .= '<ul class="summary">';
176        foreach ($p->ownedAttribute as $o) {
177            $str .= '<li class="Collapsed" id="'.$this->generatePropertyId($o).'">';
178            $str .= '<a href="javascript:void(0);" class="'.
179                $this->getPropertyStyle($o->visibility).'" target="main">'.
180                $o->name.'</a>';
181
182            $str .= '<ul class="description"><li>';
183            $str .= ucfirst($o->visibility).' ';
184            if (!$o->isInstantiable)
185                $str .= 'static ';
186            if ($o->isReadOnly)
187                $str .= 'const ';
188            if (is_object($o->type))
189                $str .= $this->getLinkTo($o->type).' ';
190            else
191                $str .= $this->displayUnresolved($o->type);
192            $str .= '<span class="smallTitle">'.$o->name.'</span>'.$this->getDefaultValue($o).'</li>';
193            if (!is_null($o->description)) {
194                $str .= $this->getTagsAsList($o->description);
195            }
196            $str .= $this->getFileInfo($o);
197            $str .= '</ul>';
198
199            $str .= '</li>';
200        }
201        $str .= '</ul>';
202        return $str;
203    }
204
205    /**
206     * Renders the block "Function" of a package or a classifier as HTML
207     *
208     * @param PHP_UML_Metamodel_NamedElement $p A classifier or a package
209     *
210     * @return string
211     */
212    protected function getFunctionBlock(PHP_UML_Metamodel_NamedElement $p)
213    {
214        if (empty($p->ownedOperation))
215            return'';
216
217        $str  = '<h2>Functions</h2>';
218        $str .= '<ul class="summary">';
219        foreach ($p->ownedOperation as $o) {
220            $fullName = $this->getParameterList($o, true);
221
222            $str .= '<li class="Collapsed" id="'.$this->generateFunctionId($o).'">';
223            $str .= '<a href="javascript:void(0);" class="'.$this->getFunctionStyle($o->visibility);
224            if ($o->isAbstract)
225                $str .= ' abstract';
226            $str .= '" target="main">'.$o->name.'</a>'.$fullName;
227
228            $str .= '<ul class="description"><li>';
229            $str .= ucfirst($o->visibility).' ';
230            if (!$o->isInstantiable)
231                $str .= 'static ';
232            if ($o->isAbstract)
233                $str .= 'abstract ';
234            $return = $this->getReturnParam($o);
235            if (!empty($return)) {
236                if (is_object($return->type))
237                    $str .= $this->getLinkTo($return->type).' ';
238                else
239                    $str .= $this->displayUnresolved($return->type);
240            }
241            $str .= '<span class="smallTitle">'.$o->name.'</span>'.$fullName.'</li>';
242
243            if (!is_null($o->description)) {
244                $str .= $this->getTagsAsList($o->description);
245            }
246            foreach ($this->getAllImplemented($p) as $ai) {
247                foreach ($ai->ownedOperation as $aiO) {
248                    if ($aiO->name == $o->name && !empty($aiO->description)) {
249                        $txt = $this->getDescription($aiO->description, $aiO->id);
250                        if ($txt!='')
251                            $str .= '<li>'.$txt.'<br/><span class="note">(copied from interface '.$this->getLinkTo($ai).')</span></li>';
252                    }
253                }
254            }
255            foreach ($this->getAllInherited($p) as $ai) {
256                foreach ($ai->ownedOperation as $aiO) {
257                    if ($aiO->name == $o->name && !empty($aiO->description)) {
258                        $txt = $this->getDescription($aiO->description, $aiO->id);
259                        if ($txt!='')
260                            $str .= '<li>'.$txt.'<br/><span class="note">(copied from class '.$this->getLinkTo($ai).')</span></li>';
261                    }
262                }
263            }
264            $str .= $this->getFileInfo($o);
265            $str .= '</ul>';
266
267            $str .= '</li>';
268        }
269        $str .= '</ul>';
270        return $str;
271    }
272
273    /**
274     * Returns the HTML for the link "Package" in the navigation bar
275     *
276     * @param string $rel A prefix to add to the hyperlink (eg: ../)
277     *
278     * @return string
279     */
280    protected function getNavigParentPackage($rel='')
281    {
282        return '<li><a href="'.$rel.self::PACKAGE_FILENAME.'.'.self::FILE_EXT.'" class="top">Package</a></li>';
283    }
284
285    /**
286     * Returns the HTML code for the common items of the navigation bar
287     *
288     * @return string
289     */
290    protected function getCommonLinks()
291    {
292        return '<li><a href="javascript:toggler.toggleAll(\''.self::JS_MAIN_NAME.'\', \'btnToggle\')" class="expandAllBtn" id="btnToggle">Expand all</a></li>'.
293            '<li><a href="'.$this->getContextPackage()->rpt.self::HELP_FILENAME.'.'.self::FILE_EXT.'" class="helpBtn">Help</a></li>'.
294            '<li><a href="'.$this->getContextPackage()->rpt.self::INDEXALL_FILENAME.'.'.self::FILE_EXT.'" class="indexAllBtn">Index</a></li>';
295    }
296
297    /**
298     * Returns the HTML code for the "File" information tag
299     *
300     * @param PHP_UML_Metamodel_NamedElement $p An element
301     *
302     * @return string
303     */
304    protected function getFileInfo(PHP_UML_Metamodel_NamedElement $p)
305    {
306        if (!empty($p->file->package))
307            return '<li>File: '.$this->getAbsPath($p->file->package).$p->file->name.'</li>';
308        else
309            return '';
310    }
311
312    protected function getPropertyStyle($visibility)
313    {
314        return 'property-'.substr($visibility, 0, 3);
315    }
316
317    protected function getFunctionStyle($visibility)
318    {
319        return 'method-'.substr($visibility, 0, 3);
320    }
321
322    /**
323     * Replace the template's placeholders with their value
324     *
325     * @param string $main Main HTML content (generated by PHP_UML)
326     * @param string $nav  Navigation HTML content (navig bar)
327     * @param string $tit  Title content
328     * @param string $name Element name
329     *
330     * @return string
331     */
332    protected function replaceInTpl($main, $nav, $tit, $name)
333    {
334        $str = str_replace('#NAVIG', $nav, $this->mainTpl);
335        $str = str_replace('#TITLE', $tit, $str);
336        $str = str_replace('#DETAIL', $main, $str);
337        $str = str_replace('#RELPATHTOP', $this->getContextPackage()->rpt, $str);
338        $str = str_replace('#NAME', $this->getTypeName().' '.$name, $str);
339        $str = str_replace('#CURDATE', date("M j, Y, G:i:s O"), $str);
340        return $str;
341    }
342
343    protected function getTemplateDirectory()
344    {
345        return dirname(__FILE__).DIRECTORY_SEPARATOR.self::TEMPLATES_DIRNAME;
346    }
347
348    protected function save($elementName, $str)
349    {
350        $fic = $this->getContextPackage()->dir.$elementName.'.'.self::FILE_EXT;
351        file_put_contents($fic, $str);
352    }
353}
354?>
355