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$
12 * @link     http://pear.php.net/package/PHP_UML
13 * @since    $Date$
14 */
15
16/**
17 * General class for an renderer in the PHP implementation
18 *
19 * @category   PHP
20 * @package    PHP_UML
21 * @subpackage Output
22 * @subpackage Php
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_Php_DocElement extends PHP_UML_Output_ApiRenderer
27{
28    const FILE_EXT          = 'php';
29    const TEMPLATES_DIRNAME = 'templates';
30
31    /**
32     * Constructor
33     *
34     * @param PHP_UML_Output_ExporterAPI $exporter Reference to an exporter
35     */
36    public function __construct(PHP_UML_Output_ExporterAPI $exporter)
37    {
38        parent::__construct($exporter);
39        $this->mainTpl = $this->getTemplate('main.php');
40    }
41
42    protected function getDescription(PHP_UML_Metamodel_Stereotype $s, $annotatedElement='')
43    {
44        $tag = PHP_UML_Metamodel_Helper::getStereotypeTag($s, 'description');
45        if (!is_null($tag))
46            return $tag->value;
47        else
48            return '';
49    }
50
51    /**
52     * Renders the operation's parameters, as a comma-sep list, between brackets
53     *
54     * @param PHP_UML_Metamodel_Operation $operation The operation
55     * @param bool                        $withType  If true, adds an hyperlink
56     *
57     * @return string
58     */
59    protected function getParameterList(PHP_UML_Metamodel_Operation $operation, $withType = false)
60    {
61        $str = '(';
62        $n   = count($operation->ownedParameter);
63        for ($i=0; $i<$n; $i++) {
64            $parameter = $operation->ownedParameter[$i];
65            if (substr($parameter->direction, 0, 2)=='in') {
66                if ($withType && isset($parameter->type) && !($parameter->type instanceof PHP_UML_Metamodel_Datatype)) {
67                    if (is_object($parameter->type))
68                        $str .= $this->getLinkTo($parameter->type).' ';
69                    else if (strcasecmp($parameter->type, 'array')==0)
70                        $str .= $this->displayUnresolved($parameter->type).' ';
71                }
72                if ($parameter->direction=='inout') {
73                    $str .= '&';
74                }
75                if ($parameter->name[0] != '$')
76                    $str .= '$';
77                $str .= $parameter->name;
78                $str .= $this->getDefaultValue($parameter);
79                if ($i<($n-1))
80                    $str .= ', ';
81            }
82        }
83        $str .= ')';
84        return $str;
85    }
86
87    protected function getDefaultValue(PHP_UML_Metamodel_TypedElement $obj)
88    {
89        if ($obj->default!='')
90            return '='.$obj->default;
91        else
92            return '';
93    }
94
95    /**
96     * Renders a link towards a given element
97     * (since datatypes don't own to a "package",  we suppose they are located in
98     * the top package)
99     *
100     * @param PHP_UML_Metamodel_Classifier $t        The element
101     * @param string                       $cssStyle CSS style to use
102     *
103     * @return string
104     */
105    protected function getLinkTo(PHP_UML_Metamodel_Classifier $t, $hideDatatype=true)
106    {
107        if ($hideDatatype && ($t instanceof PHP_UML_Metamodel_Datatype))
108            return '';
109
110        $ns = $t instanceof PHP_UML_Metamodel_Datatype ? '' : self::T_NAMESPACE;
111        if (isset($t->package)) {
112            $ns .= $this->getAbsPath($t->package, self::T_NAMESPACE);
113        }
114        return $ns.$t->name;
115    }
116
117    /**
118     * Renders an unresolved type as an HTML span
119     *
120     * @param string $type Type, provided as a string
121     *
122     * @return string
123     */
124    protected function displayUnresolved($type)
125    {
126        return $type;
127    }
128
129
130    protected function getTagsAsList(PHP_UML_Metamodel_Stereotype $s)
131    {
132        return $this->getDocblocks($s, 0);
133    }
134
135    /**
136     * Renders the properties of a given stereotype.
137     * Docblocks in $ignoredTag are not shown.
138     *
139     * @param PHP_UML_Metamodel_Stereotype $s        A stereotype
140     * @param int                          $nbSpacer Number of spacers to add
141     *
142     * @return string
143     */
144    protected function getDocblocks(PHP_UML_Metamodel_Stereotype $s, $nbSpacer = 0)
145    {
146        $str    = '';
147        $spacer = str_repeat(chr(9), $nbSpacer);
148        foreach ($s->ownedAttribute as $tag) {
149            if (!(in_array($tag->name, $this->ignoredTag))) {
150                $str .= $spacer;
151                if ($tag->name!='description') {
152                    $str .= ' * @'.$tag->name.' ';
153                } else {
154                    $str .= ' * ';
155                }
156                if (strlen($tag->value)>0)
157                    $str .= str_replace($this->getNl(), $this->getNl().$spacer.' * ', $tag->value);
158                if ($tag->name=='description') {
159                    $str .= $this->getNl().$spacer.' *';
160                }
161                $str .= $this->getNl();
162            }
163        }
164        if ($str != '') {
165            $str = $spacer.'/**'.$this->getNl().$str.$spacer.' */'.$this->getNl();
166        }
167        return $str;
168    }
169
170
171    /**
172     * Renders the block "Properties" of a package or a class as HTML
173     *
174     * @param PHP_UML_Metamodel_NamedElement $p A classifier/a package
175     *
176     * @return string
177     */
178    protected function getPropertyBlock(PHP_UML_Metamodel_NamedElement $p)
179    {
180        if (empty($p->ownedAttribute))
181            return '';
182
183        $str    = '';
184        $spacer = chr(9);
185        foreach ($p->ownedAttribute as $o) {
186
187            if (!is_null($o->description) && $this->exporter->getDocblocks()) {
188                // we add var/return docblocks if they are missing
189                $this->addVarDocblock($o);
190                $str .= $this->getDocblocks($o->description, 1);
191            }
192
193            $str .= $spacer;
194            if ($o->isReadOnly)
195                $str .= 'const ';
196            else {
197                $str .= $o->visibility.' ';
198                if (!$o->isInstantiable)
199                    $str .= 'static ';
200            }
201
202            // type display;
203            /*if (is_object($o->type))
204                $str .= $this->getLinkTo($o->type).' ';
205            else
206                $str .= $this->displayUnresolved($o->type);*/
207            if ((!empty($o->name)) && ($o->name[0]!='$' && !$o->isReadOnly))
208                $str .= '$';
209
210            $str .= $o->name.''.$this->getDefaultValue($o).';';
211
212            $str .= $this->getNl().$this->getNl();
213        }
214        $str .= '';
215        return $str;
216    }
217
218    private function addVarDocblock(PHP_UML_Metamodel_Property $o)
219    {
220        $found = false;
221        foreach ($o->description->ownedAttribute as $tag) {
222            if ($tag->name=='var') {
223                $found = true;
224                break;
225            }
226        }
227        if (!$found) {
228            $st       = new PHP_UML_Metamodel_Stereotype();
229            $st->name = 'var';
230            if (is_object($o->type))
231                $st->value = $this->getLinkTo($o->type, false);
232            else
233                $st->value = $this->displayUnresolved($o->type);
234            $o->description->ownedAttribute[] = $st;
235        }
236    }
237
238    private function addReturnDocblock(PHP_UML_Metamodel_Operation $o)
239    {
240        $found = false;
241        foreach ($o->description->ownedAttribute as $tag) {
242            if ($tag->name=='return') {
243                $found = true;
244                break;
245            }
246        }
247        if (!$found) {
248            $st       = new PHP_UML_Metamodel_Stereotype();
249            $st->name = 'return';
250            foreach ($o->ownedParameter as $parameter) {
251                if ($parameter->direction != 'in') {
252                    if (is_object($parameter->type))
253                        $st->value .= $this->getLinkTo($parameter->type, false).' ';
254                    else
255                        $st->value .= $this->displayUnresolved($parameter->type);
256                }
257            }
258            $o->description->ownedAttribute[] = $st;
259        }
260    }
261
262
263    /**
264     * Renders the block "Function" of a package or a classifier as HTML
265     *
266     * @param PHP_UML_Metamodel_NamedElement $p A classifier or a package
267     *
268     * @return string
269     */
270    protected function getFunctionBlock(PHP_UML_Metamodel_NamedElement $p)
271    {
272        if (empty($p->ownedOperation))
273            return'';
274
275        $str    = '';
276        $spacer = chr(9);
277
278        foreach ($p->ownedOperation as $o) {
279
280            if (!is_null($o->description) && $this->exporter->getDocblocks()) {
281                $this->addReturnDocblock($o);
282                $str .= $this->getDocblocks($o->description, 1);
283            }
284
285            $str .= $spacer.($o->visibility).' ';
286            if (!$o->isInstantiable)
287                $str .= 'static ';
288            if ($o->isAbstract)
289                $str .= 'abstract ';
290
291            $str .= 'function '.$o->name;
292
293            /*type hint
294            $return = $this->getReturnParam($o);
295            if (is_object($return->type))
296                $str .= $this->getLinkTo($return->type).' ';
297            else
298                $str .= $this->displayUnresolved($return->type);*/
299            $str .= $this->getParameterList($o, true);
300
301            if ($o->isAbstract || $p instanceof PHP_UML_Metamodel_Interface)
302                $str .= ';'.$this->getNl().$this->getNl();
303            else
304                $str .= $this->getNl().$spacer.'{'.$this->getNl().
305                    $spacer.'}'.$this->getNl().$this->getNl();
306        }
307        $str .= '';
308        return $str;
309    }
310
311    /**
312     * Returns the HTML code for the "File" information tag
313     *
314     * @param PHP_UML_Metamodel_NamedElement $p An element
315     *
316     * @return string
317     */
318    protected function getFileInfo(PHP_UML_Metamodel_NamedElement $p)
319    {
320        if (!empty($p->file->package))
321            return ''.$this->getAbsPath($p->file->package).$p->file->name.'';
322        else
323            return '';
324    }
325
326    protected function getNl()
327    {
328        return PHP_EOL;
329    }
330
331    /**
332     * Replace the template's placeholders with their value
333     *
334     * @param string $main   Main HTML content (generated by PHP_UML)
335     * @param string $header Navigation HTML content (navig bar)
336     * @param string $ns     Title content
337     * @param string $name   Element name
338     *
339     * @return string
340     */
341    protected function replaceInTpl($main, $header, $ns, $name)
342    {
343        $str = str_replace('#HEADER', $header, $this->mainTpl);
344        $str = str_replace('#NAMESPACE', $ns, $str);
345        $str = str_replace('#DETAIL', $main, $str);
346        $str = str_replace('#NAME', $this->getTypeName().' '.$name, $str);
347        return $str;
348    }
349
350    protected function getTemplateDirectory()
351    {
352        return dirname(__FILE__).DIRECTORY_SEPARATOR.self::TEMPLATES_DIRNAME;
353    }
354
355    protected function save($elementName, $str)
356    {
357        $fic = $this->getContextPackage()->dir.$elementName.'.'.self::FILE_EXT;
358        file_put_contents($fic, $str);
359    }
360}
361?>
362