1
|
|
|
<?php |
|
|
|
|
2
|
|
|
/******************************************************************************* |
3
|
|
|
* This file contains the Process Printer for SemanticResultFormats |
4
|
|
|
* (https://www.mediawiki.org/wiki/Extension:Semantic_Result_Formats) |
5
|
|
|
* |
6
|
|
|
* Copyright (c) 2008 - 2009 Frank Dengler and Hans-Jörg Happel |
7
|
|
|
* |
8
|
|
|
* Process Printer is free software: you can redistribute it and/or modify |
9
|
|
|
* it under the terms of the GNU General Public License as published by |
10
|
|
|
* the Free Software Foundation, either version 3 of the License, or |
11
|
|
|
* (at your option) any later version. |
12
|
|
|
* |
13
|
|
|
* Process Printer is distributed in the hope that it will be useful, |
14
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
15
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16
|
|
|
* GNU General Public License for more details. |
17
|
|
|
* |
18
|
|
|
* You should have received a copy of the GNU General Public License |
19
|
|
|
* along with Process Printer. If not, see <http://www.gnu.org/licenses/>. |
20
|
|
|
*******************************************************************************/ |
21
|
|
|
|
22
|
|
|
if ( !defined( 'MEDIAWIKI' ) ) { |
23
|
|
|
die( 'Not an entry point.' ); |
24
|
|
|
} |
25
|
|
|
|
26
|
|
|
/** |
27
|
|
|
* This is a contribution to Semtantic Result Formats (SRF) which are an |
28
|
|
|
* extension of Semantic MediaWiki (SMW) which in turn is an extension |
29
|
|
|
* of MediaWiki |
30
|
|
|
* |
31
|
|
|
* SRF defines certain "printers" to render the results of SMW semantic |
32
|
|
|
* "ASK"-queries. Some of these printers make use of the GraphViz/dot |
33
|
|
|
* library (which is wrapped by a separate MediaWiki extension). |
34
|
|
|
* |
35
|
|
|
* The purpose of this extension, is to render results of ASK-Queries |
36
|
|
|
* (e.g. Classes with Attributes) as GraphViz-layouted process graphs |
37
|
|
|
* |
38
|
|
|
* |
39
|
|
|
* @author Frank Dengler |
40
|
|
|
* @author Hans-Jörg Happel |
41
|
|
|
* @ingroup SemanticResultFormats |
42
|
|
|
* |
43
|
|
|
* @note AUTOLOADED |
44
|
|
|
*/ |
45
|
|
|
|
46
|
|
|
// global variable defining picture path |
47
|
|
|
|
48
|
|
|
$srfgPicturePath = "formats/graphviz/images/"; |
49
|
|
|
|
50
|
|
|
class SRFProcess extends SMWResultPrinter { |
51
|
|
|
|
52
|
|
|
// configuration variables |
53
|
|
|
protected $m_graphValidation = false; |
54
|
|
|
protected $m_isDebugSet = false; |
55
|
|
|
protected $m_processCategory = 'Process'; // Category for processes - required for rendering compound nodes |
56
|
|
|
|
57
|
|
|
// internal variables |
58
|
|
|
protected $m_process; // process to be rendered |
59
|
|
|
|
60
|
|
|
/** |
61
|
|
|
* (non-PHPdoc) |
62
|
|
|
* @see SMWResultPrinter::handleParameters() |
63
|
|
|
*/ |
64
|
|
|
protected function handleParameters( array $params, $outputmode ) { |
65
|
|
|
parent::handleParameters( $params, $outputmode ); |
66
|
|
|
|
67
|
|
|
// init process graph instance |
68
|
|
|
$this->m_process = new ProcessGraph(); |
69
|
|
|
|
70
|
|
|
$this->m_process->setGraphName( trim( $params['graphname'] ) ); |
71
|
|
|
$this->m_process->setGraphSize( trim( $params['graphsize'] ) ); |
72
|
|
|
$this->m_process->setClusterColor( trim( $params['clustercolor'] ) ); |
73
|
|
|
$this->m_process->setRankdir( strtoupper( trim( $params['rankdir'] ) ) ); |
74
|
|
|
$this->m_process->setHighlightNode( trim( $params['highlight'] ) ); |
75
|
|
|
$this->m_process->setHighlightColor( trim( $params['highlightcolor'] ) ); |
76
|
|
|
$this->m_process->setHighlightColor( trim( $params['redlinkcolor'] ) ); |
77
|
|
|
|
78
|
|
|
$this->m_process->setShowRoles( $params['showroles'] ); |
79
|
|
|
$this->m_process->setShowStatus( $params['showstatus'] ); |
80
|
|
|
$this->m_process->setShowRessources( $params['showresources'] ); |
81
|
|
|
$this->m_process->setShowDiscussion( $params['showdiscussion'] ); |
82
|
|
|
$this->m_process->setShowRedLinks( $params['showredlinks'] ); |
83
|
|
|
$this->m_process->setShowCompound( $params['showcompound'] ); |
84
|
|
|
|
85
|
|
|
$this->m_processCategory = $params['processcat']; |
86
|
|
|
$this->m_isDebugSet = $params['debug']; |
87
|
|
|
$this->m_graphValidation = $params['graphvalidation']; |
88
|
|
|
} |
89
|
|
|
|
90
|
|
|
/** |
91
|
|
|
* @see SMWResultPrinter::getParamDefinitions |
92
|
|
|
* |
93
|
|
|
* @since 1.8 |
94
|
|
|
* |
95
|
|
|
* @param $definitions array of IParamDefinition |
96
|
|
|
* |
97
|
|
|
* @return array of IParamDefinition|array |
98
|
|
|
*/ |
99
|
|
|
public function getParamDefinitions( array $definitions ) { |
100
|
|
|
$params = parent::getParamDefinitions( $definitions ); |
101
|
|
|
|
102
|
|
|
$params['graphname'] = [ |
103
|
|
|
'default' => '', |
104
|
|
|
'message' => 'srf-paramdesc-graphname', |
105
|
|
|
]; |
106
|
|
|
|
107
|
|
|
$params['rankdir'] = [ |
108
|
|
|
'default' => 'TB', |
109
|
|
|
'message' => 'srf-paramdesc-rankdir', |
110
|
|
|
]; |
111
|
|
|
|
112
|
|
|
$params['graphsize'] = [ |
113
|
|
|
'default' => '', |
114
|
|
|
'message' => 'srf-paramdesc-graphsize', |
115
|
|
|
]; |
116
|
|
|
|
117
|
|
|
$params['clustercolor'] = [ |
118
|
|
|
'default' => 'lightgrey', |
119
|
|
|
'message' => 'srf-paramdesc-clustercolor', |
120
|
|
|
]; |
121
|
|
|
|
122
|
|
|
$params['highlight'] = [ |
123
|
|
|
'default' => '', |
124
|
|
|
'message' => 'srf-paramdesc-highlight', |
125
|
|
|
]; |
126
|
|
|
|
127
|
|
|
$params['highlightcolor'] = [ |
128
|
|
|
'default' => 'blue', |
129
|
|
|
'message' => 'srf-paramdesc-highlightcolor', |
130
|
|
|
]; |
131
|
|
|
|
132
|
|
|
$params['redlinkcolor'] = [ |
133
|
|
|
'default' => 'red', |
134
|
|
|
'message' => 'srf-paramdesc-redlinkcolor', |
135
|
|
|
]; |
136
|
|
|
|
137
|
|
|
$params['processcat'] = [ |
138
|
|
|
'default' => 'Process', |
139
|
|
|
'message' => 'srf-paramdesc-processcategory', |
140
|
|
|
]; |
141
|
|
|
|
142
|
|
|
$params['showroles'] = [ |
143
|
|
|
'type' => 'boolean', |
144
|
|
|
'default' => false, |
145
|
|
|
'message' => 'srf-paramdesc-showroles', |
146
|
|
|
]; |
147
|
|
|
|
148
|
|
|
$params['showstatus'] = [ |
149
|
|
|
'type' => 'boolean', |
150
|
|
|
'default' => false, |
151
|
|
|
'message' => 'srf-paramdesc-showstatus', |
152
|
|
|
]; |
153
|
|
|
|
154
|
|
|
$params['showresources'] = [ |
155
|
|
|
'type' => 'boolean', |
156
|
|
|
'default' => false, |
157
|
|
|
'message' => 'srf-paramdesc-showresources', |
158
|
|
|
]; |
159
|
|
|
|
160
|
|
|
$params['showdiscussion'] = [ |
161
|
|
|
'type' => 'boolean', |
162
|
|
|
'default' => false, |
163
|
|
|
'message' => 'srf-paramdesc-showdiscussion', |
164
|
|
|
]; |
165
|
|
|
|
166
|
|
|
$params['showredlinks'] = [ |
167
|
|
|
'type' => 'boolean', |
168
|
|
|
'default' => false, |
169
|
|
|
'message' => 'srf-paramdesc-showredlinks', |
170
|
|
|
]; |
171
|
|
|
|
172
|
|
|
$params['showcompound'] = [ |
173
|
|
|
'type' => 'boolean', |
174
|
|
|
'default' => true, |
175
|
|
|
'message' => 'srf-paramdesc-showcompound', |
176
|
|
|
]; |
177
|
|
|
|
178
|
|
|
$params['debug'] = [ |
179
|
|
|
'type' => 'boolean', |
180
|
|
|
'default' => false, |
181
|
|
|
'message' => 'srf-paramdesc-debug', |
182
|
|
|
]; |
183
|
|
|
|
184
|
|
|
$params['graphvalidation'] = [ |
185
|
|
|
'type' => 'boolean', |
186
|
|
|
'default' => false, |
187
|
|
|
'message' => 'srf-paramdesc-graphvalidation', |
188
|
|
|
]; |
189
|
|
|
|
190
|
|
|
return $params; |
191
|
|
|
} |
192
|
|
|
|
193
|
|
|
/** |
194
|
|
|
* This method renders the result set provided by SMW according to the printer |
195
|
|
|
* |
196
|
|
|
* @param res SMWQueryResult, result set of the ask query provided by SMW |
197
|
|
|
* @param outputmode ? |
198
|
|
|
* |
199
|
|
|
* @return String, rendered HTML output of this printer for the ask-query |
|
|
|
|
200
|
|
|
* |
201
|
|
|
*/ |
202
|
|
|
protected function getResultText( SMWQueryResult $res, $outputmode ) { |
203
|
|
|
if ( !is_callable( 'renderGraphviz' ) ) { |
204
|
|
|
wfWarn( 'The SRF Graph printer needs the GraphViz extension to be installed.' ); |
205
|
|
|
return ''; |
206
|
|
|
} |
207
|
|
|
|
208
|
|
|
global $wgContLang; // content language object |
209
|
|
|
|
210
|
|
|
// |
211
|
|
|
// GraphViz settings |
212
|
|
|
// |
213
|
|
|
$this->isHTML = true; |
214
|
|
|
|
215
|
|
|
// |
216
|
|
|
// Iterate all rows in result set |
217
|
|
|
// |
218
|
|
|
|
219
|
|
|
$row = $res->getNext(); // get initial row (i.e. array of SMWResultArray) |
220
|
|
|
|
221
|
|
|
while ( $row !== false ) { |
222
|
|
|
/* SMWDataItem */ |
223
|
|
|
$subject = $row[0]->getResultSubject(); // get Subject of the Result |
224
|
|
|
// creates a new node if $val has type wikipage |
225
|
|
|
if ( $subject->getDIType() == SMWDataItem::TYPE_WIKIPAGE ) { |
226
|
|
|
$wikiPageValue = new SMWWikiPageValue( '_wpg' ); |
227
|
|
|
$wikiPageValue->setDataItem( $subject ); |
228
|
|
|
$node = $this->m_process->makeNode( |
229
|
|
|
$wikiPageValue->getShortWikiText(), |
230
|
|
|
$wikiPageValue->getShortWikiText() |
231
|
|
|
); |
232
|
|
|
} |
233
|
|
|
|
234
|
|
|
// |
235
|
|
|
// Iterate all colums of the row (which describe properties of the proces node) |
236
|
|
|
// |
237
|
|
|
|
238
|
|
|
// FIXME: this does not work with SMW >= 1.6, see |
239
|
|
|
// https://bugzilla.wikimedia.org/show_bug.cgi?id=35003 |
240
|
|
|
|
241
|
|
|
// FIXME: got _a bit_ of redundancy here looks like... :/ |
242
|
|
|
|
243
|
|
|
/** |
244
|
|
|
* @var SMWResultArray $field |
245
|
|
|
*/ |
246
|
|
|
foreach ( $row as $field ) { |
247
|
|
|
|
248
|
|
|
// check column title |
249
|
|
|
$req = $field->getPrintRequest(); |
250
|
|
|
switch ( ( strtolower( $req->getLabel() ) ) ) { |
251
|
|
|
|
252
|
|
|
case strtolower( $wgContLang->getNsText( NS_CATEGORY ) ): |
253
|
|
|
foreach ( $field->getContent() as $value ) { |
254
|
|
|
$wikiPageValue = new SMWWikiPageValue( '_wpg' ); |
255
|
|
|
$wikiPageValue->setDataItem( $value ); |
256
|
|
|
$val = $wikiPageValue->getShortWikiText(); |
257
|
|
|
|
258
|
|
|
if ( $val == ( $wgContLang->getNsText( NS_CATEGORY ) . ':' . $this->m_processCategory ) ) { |
259
|
|
|
$node->setAtomic( false ); |
|
|
|
|
260
|
|
|
} |
261
|
|
|
} |
262
|
|
|
|
263
|
|
|
break; |
264
|
|
|
|
265
|
|
|
case "haslabel": |
266
|
|
|
$value = current( $field->getContent() ); // save only the first |
267
|
|
|
|
268
|
|
|
if ( ( $value !== false ) ) { |
269
|
|
|
$wikiPageValue = new SMWWikiPageValue( '_wpg' ); |
270
|
|
|
$wikiPageValue->setDataItem( $value ); |
271
|
|
|
$val = $wikiPageValue->getLongWikiText(); |
272
|
|
|
|
273
|
|
|
if ( $this->m_process->getUseOtherLabels() ) { |
|
|
|
|
274
|
|
|
$val = str_replace( "&", "and", $val ); |
275
|
|
|
$node->setLabel( $val ); |
276
|
|
|
} |
277
|
|
|
} |
278
|
|
|
break; |
279
|
|
|
|
280
|
|
|
case "hasrole": |
281
|
|
|
foreach ( $field->getContent() as $value ) { |
282
|
|
|
$wikiPageValue = new SMWWikiPageValue( $field->getPrintRequest()->getTypeID() ); |
283
|
|
|
$wikiPageValue->setDataItem( $value ); |
284
|
|
|
$val = $wikiPageValue->getShortWikiText(); |
285
|
|
|
|
286
|
|
|
$role = $this->m_process->makeRole( $val, $val ); |
287
|
|
|
$node->addRole( $role ); |
288
|
|
|
} |
289
|
|
|
break; |
290
|
|
|
|
291
|
|
|
case "usesresource": |
292
|
|
|
foreach ( $field->getContent() as $value ) { |
293
|
|
|
$wikiPageValue = new SMWWikiPageValue( $field->getPrintRequest()->getTypeID() ); |
294
|
|
|
$wikiPageValue->setDataItem( $value ); |
295
|
|
|
$val = $wikiPageValue->getShortWikiText(); |
296
|
|
|
|
297
|
|
|
$xres = $this->m_process->makeRessource( $val, $val ); |
298
|
|
|
$node->addUsedRessource( $xres ); |
299
|
|
|
} |
300
|
|
|
break; |
301
|
|
|
|
302
|
|
|
case "producesresource": |
303
|
|
|
foreach ( $field->getContent() as $value ) { |
304
|
|
|
$wikiPageValue = new SMWWikiPageValue( $field->getPrintRequest()->getTypeID() ); |
305
|
|
|
$wikiPageValue->setDataItem( $value ); |
306
|
|
|
$val = $wikiPageValue->getShortWikiText(); |
307
|
|
|
|
308
|
|
|
$xres = $this->m_process->makeRessource( $val, $val ); |
309
|
|
|
$node->addProducedRessource( $xres ); |
310
|
|
|
} |
311
|
|
|
break; |
312
|
|
|
|
313
|
|
|
case "hassuccessor": |
314
|
|
|
|
315
|
|
|
if ( count( $field->getContent() ) > 1 ) { |
316
|
|
|
|
317
|
|
|
// SplitParallel |
318
|
|
|
$edge = new SplitParallelEdge(); |
319
|
|
|
$edge->setFrom( $node ); |
320
|
|
|
foreach ( $field->getContent() as $value ) { |
321
|
|
|
$wikiPageValue = new SMWWikiPageValue( $field->getPrintRequest()->getTypeID() ); |
322
|
|
|
$wikiPageValue->setDataItem( $value ); |
323
|
|
|
$val = $wikiPageValue->getShortWikiText(); |
324
|
|
|
|
325
|
|
|
$edge->addTo( $this->m_process->makeNode( $val, $val ) ); |
326
|
|
|
} |
327
|
|
|
|
328
|
|
|
} else { |
329
|
|
|
|
330
|
|
|
// Sequence |
331
|
|
|
foreach ( $field->getContent() as $value ) { |
332
|
|
|
$wikiPageValue = new SMWWikiPageValue( $field->getPrintRequest()->getTypeID() ); |
333
|
|
|
$wikiPageValue->setDataItem( $value ); |
334
|
|
|
$val = $wikiPageValue->getShortWikiText(); |
335
|
|
|
|
336
|
|
|
$edge = new SequentialEdge(); |
337
|
|
|
$edge->setFrom( $node ); |
338
|
|
|
$edge->setTo( $this->m_process->makeNode( $val, $val ) ); |
339
|
|
|
} |
340
|
|
|
} |
341
|
|
|
|
342
|
|
|
break; |
343
|
|
|
|
344
|
|
|
case "hasorsuccessor": |
345
|
|
|
|
346
|
|
|
if ( count( $field->getContent() ) > 0 ) { |
347
|
|
|
|
348
|
|
|
// SplitExclusiveOr |
349
|
|
|
$edge = new SplitExclusiveOrEdge(); |
350
|
|
|
$edge->setFrom( $node ); |
351
|
|
|
foreach ( $field->getContent() as $value ) { |
352
|
|
|
$wikiPageValue = new SMWWikiPageValue( $field->getPrintRequest()->getTypeID() ); |
353
|
|
|
$wikiPageValue->setDataItem( $value ); |
354
|
|
|
$val = $wikiPageValue->getShortWikiText(); |
355
|
|
|
|
356
|
|
|
$edge->addTo( $this->m_process->makeNode( $val, $val ) ); |
357
|
|
|
} |
358
|
|
|
} |
359
|
|
|
|
360
|
|
|
break; |
361
|
|
|
|
362
|
|
|
case "hascontruesuccessor": |
363
|
|
|
|
364
|
|
|
if ( count( $field->getContent() ) > 0 ) { |
365
|
|
|
|
366
|
|
|
// SplitConditional |
367
|
|
|
if ( !isset( $cond_edge ) ) { |
368
|
|
|
$cond_edge = new SplitConditionalOrEdge(); |
369
|
|
|
$cond_edge->setFrom( $node ); |
370
|
|
|
} |
371
|
|
|
|
372
|
|
|
// should be only one |
373
|
|
|
foreach ( $field->getContent() as $value ) { |
374
|
|
|
$wikiPageValue = new SMWWikiPageValue( $field->getPrintRequest()->getTypeID() ); |
375
|
|
|
$wikiPageValue->setDataItem( $value ); |
376
|
|
|
$val = $wikiPageValue->getShortWikiText(); |
377
|
|
|
|
378
|
|
|
$cond_edge->setToTrue( $this->m_process->makeNode( $val, $val ) ); |
379
|
|
|
} |
380
|
|
|
|
381
|
|
|
} |
382
|
|
|
|
383
|
|
|
break; |
384
|
|
|
|
385
|
|
|
case "hasconfalsesuccessor": |
386
|
|
|
|
387
|
|
|
if ( count( $field->getContent() ) > 0 ) { |
388
|
|
|
|
389
|
|
|
// SplitConditional |
390
|
|
|
if ( !isset( $cond_edge ) ) { |
391
|
|
|
$cond_edge = new SplitConditionalOrEdge(); |
392
|
|
|
$cond_edge->setFrom( $node ); |
393
|
|
|
} |
394
|
|
|
|
395
|
|
|
// should be only one |
396
|
|
|
foreach ( $field->getContent() as $value ) { |
397
|
|
|
$wikiPageValue = new SMWWikiPageValue( $field->getPrintRequest()->getTypeID() ); |
398
|
|
|
$wikiPageValue->setDataItem( $value ); |
399
|
|
|
$val = $wikiPageValue->getShortWikiText(); |
400
|
|
|
|
401
|
|
|
$cond_edge->setToFalse( $this->m_process->makeNode( $val, $val ) ); |
402
|
|
|
} |
403
|
|
|
} |
404
|
|
|
|
405
|
|
|
break; |
406
|
|
|
|
407
|
|
|
case "hascondition": |
408
|
|
|
|
409
|
|
|
if ( count( $field->getContent() ) > 0 ) { |
410
|
|
|
|
411
|
|
|
// SplitConditional |
412
|
|
|
if ( !isset( $cond_edge ) ) { |
413
|
|
|
$cond_edge = new SplitConditionalOrEdge(); |
414
|
|
|
$cond_edge->setFrom( $node ); |
415
|
|
|
} |
416
|
|
|
|
417
|
|
|
// should be only one |
418
|
|
|
foreach ( $field->getContent() as $value ) { |
419
|
|
|
$wikiPageValue = new SMWWikiPageValue( $field->getPrintRequest()->getTypeID() ); |
420
|
|
|
$wikiPageValue->setDataItem( $value ); |
421
|
|
|
$val = $wikiPageValue->getShortWikiText(); |
422
|
|
|
|
423
|
|
|
$cond_edge->setConditionText( $val ); |
424
|
|
|
|
425
|
|
|
} |
426
|
|
|
} |
427
|
|
|
|
428
|
|
|
break; |
429
|
|
|
|
430
|
|
|
case "hasstatus": |
431
|
|
|
|
432
|
|
|
// should be only one |
433
|
|
|
foreach ( $field->getContent() as $value ) { |
434
|
|
|
$wikiPageValue = new SMWWikiPageValue( $field->getPrintRequest()->getTypeID() ); |
435
|
|
|
$wikiPageValue->setDataItem( $value ); |
436
|
|
|
$val = $wikiPageValue->getShortWikiText(); |
437
|
|
|
|
438
|
|
|
$node->setStatus( $val ); |
439
|
|
|
} |
440
|
|
|
|
441
|
|
|
break; |
442
|
|
|
|
443
|
|
|
default: |
444
|
|
|
|
445
|
|
|
// TODO - redundant column in result |
446
|
|
|
|
447
|
|
|
} |
448
|
|
|
} |
449
|
|
|
|
450
|
|
|
// reset row variables |
451
|
|
|
unset( $node ); |
452
|
|
|
unset( $cond_edge ); |
453
|
|
|
|
454
|
|
|
$row = $res->getNext(); // switch to next row |
455
|
|
|
} |
456
|
|
|
|
457
|
|
|
// |
458
|
|
|
// generate graphInput |
459
|
|
|
// |
460
|
|
|
$graphInput = $this->m_process->getGraphVizCode(); |
461
|
|
|
|
462
|
|
|
// |
463
|
|
|
// render graphViz code |
464
|
|
|
// |
465
|
|
|
$result = renderGraphviz( $graphInput ); |
466
|
|
|
|
467
|
|
|
$debug = ''; |
468
|
|
|
if ( $this->m_isDebugSet ) { |
469
|
|
|
$debug = '<pre>' . $graphInput . '</pre>'; |
470
|
|
|
} |
471
|
|
|
|
472
|
|
|
return $result . $debug; |
473
|
|
|
} |
474
|
|
|
} |
475
|
|
|
|
476
|
|
|
/** |
477
|
|
|
* Class representing a process graph |
478
|
|
|
*/ |
479
|
|
|
class ProcessGraph { |
480
|
|
|
|
481
|
|
|
// configuration variables |
482
|
|
|
protected $m_graphName = ''; |
483
|
|
|
protected $m_rankdir = 'TB'; |
484
|
|
|
protected $m_graphSize = ''; |
485
|
|
|
protected $m_clusterColor = 'lightgrey'; |
486
|
|
|
protected $m_showStatus = false; // should status be rendered? |
487
|
|
|
protected $m_showRoles = false; // should roles be rendered? |
488
|
|
|
protected $m_showRessources = false; // should ressources be rendered? |
489
|
|
|
protected $m_showDiscussion = false; // should discussion be rendered? |
490
|
|
|
protected $m_highlightNode = ''; // node to be highlighted |
491
|
|
|
protected $m_highlightColor = 'blue'; // highlight font color |
492
|
|
|
protected $m_showRedLinks = false; // check and highlight red links? |
493
|
|
|
protected $m_redLinkColor = 'red'; // red link font color |
494
|
|
|
protected $m_showCompound = true; // highlight compound nodes (=subprocesses) |
495
|
|
|
|
496
|
|
|
public $m_useHtmlNodes = true; // Set to false if you do not want to use HTML table nodes |
497
|
|
|
|
498
|
|
|
// instance variables |
499
|
|
|
protected $m_nodes = []; // list of all nodes |
500
|
|
|
protected $m_startnodes = []; // list of start nodes |
501
|
|
|
protected $m_endnodes = []; // list of end nodes |
502
|
|
|
protected $m_ressources = []; // list of ressources |
503
|
|
|
protected $m_roles = []; // list of roles |
504
|
|
|
protected $m_errors = []; // list of errors |
505
|
|
|
|
506
|
|
|
/** |
507
|
|
|
* This method should be used for getting new or existing nodes |
508
|
|
|
* If a node does not exist yet, it will be created |
509
|
|
|
* |
510
|
|
|
* @param $id string, node id |
511
|
|
|
* @param $label string, node label |
512
|
|
|
* |
513
|
|
|
* @return Object of type ProcessNode |
514
|
|
|
*/ |
515
|
|
|
public function makeNode( $id, $label ) { |
516
|
|
|
// check if node exists |
517
|
|
|
if ( isset( $this->m_nodes[$id] ) ) { |
518
|
|
|
// take existing node |
519
|
|
|
$node = $this->m_nodes[$id]; |
520
|
|
|
|
521
|
|
|
} else { |
522
|
|
|
// create new node |
523
|
|
|
|
524
|
|
|
$node = new ProcessNode(); |
525
|
|
|
$node->setId( $id ); |
526
|
|
|
$node->setLabel( $label ); |
527
|
|
|
$node->setProcess( $this ); |
528
|
|
|
|
529
|
|
|
// is actual node name the same like the one to highlight? |
530
|
|
|
if ( strcasecmp( $id, $this->m_highlightNode ) == 0 ) { |
531
|
|
|
$node->setFontColor( $this->m_highlightColor ); |
532
|
|
|
} |
533
|
|
|
|
534
|
|
|
// is the node a red link (i.e. corresponding wiki page does not yet exist)? |
535
|
|
|
if ( $this->m_showRedLinks ) { |
536
|
|
|
$title = Title::newFromDBkey( $id ); |
537
|
|
|
if ( isset( $title ) && ( !$title->exists() ) ) { |
538
|
|
|
$node->setFontColor( $this->m_redLinkColor ); |
539
|
|
|
} |
540
|
|
|
} |
541
|
|
|
|
542
|
|
|
// add new node to process |
543
|
|
|
$this->m_nodes[$id] = $node; |
544
|
|
|
} |
545
|
|
|
|
546
|
|
|
return $node; |
547
|
|
|
|
548
|
|
|
} |
549
|
|
|
|
550
|
|
|
public function makeRole( $id, $label ) { |
551
|
|
|
// check if role exists |
552
|
|
|
if ( isset( $this->m_roles[$id] ) ) { |
553
|
|
|
// take existing roles |
554
|
|
|
$role = $this->m_roles[$id]; |
555
|
|
|
|
556
|
|
|
} else { |
557
|
|
|
$role = new ProcessRole(); |
558
|
|
|
$role->setId( $id ); |
559
|
|
|
$role->setLabel( $label ); |
560
|
|
|
|
561
|
|
|
// add new role to process |
562
|
|
|
$this->m_roles[$id] = $role; |
563
|
|
|
} |
564
|
|
|
|
565
|
|
|
return $role; |
566
|
|
|
|
567
|
|
|
} |
568
|
|
|
|
569
|
|
|
public function makeRessource( $id, $label ) { |
570
|
|
|
// check if res exists |
571
|
|
|
if ( isset( $this->m_ressources[$id] ) ) { |
572
|
|
|
// take existing res |
573
|
|
|
$res = $this->m_ressources[$id]; |
574
|
|
|
|
575
|
|
|
} else { |
576
|
|
|
$res = new ProcessRessource(); |
577
|
|
|
$res->setId( $id ); |
578
|
|
|
$res->setLabel( $label ); |
579
|
|
|
|
580
|
|
|
// add new res to process |
581
|
|
|
$this->m_ressources[$id] = $res; |
582
|
|
|
|
583
|
|
|
} |
584
|
|
|
|
585
|
|
|
return $res; |
586
|
|
|
|
587
|
|
|
} |
588
|
|
|
|
589
|
|
|
public function getEndNodes() { |
590
|
|
|
if ( count( $this->m_endnodes ) == 0 ) { |
591
|
|
|
foreach ( $this->m_nodes as $node ) { |
592
|
|
|
if ( count( $node->getSucc() ) == 0 ) { |
593
|
|
|
$this->m_endnodes[] = $node; |
594
|
|
|
} |
595
|
|
|
} |
596
|
|
|
} |
597
|
|
|
|
598
|
|
|
return $this->m_endnodes; |
599
|
|
|
} |
600
|
|
|
|
601
|
|
|
public function getStartNodes() { |
602
|
|
|
|
603
|
|
|
if ( count( $this->m_startnodes ) == 0 ) { |
604
|
|
|
foreach ( $this->m_nodes as $node ) { |
605
|
|
|
if ( count( $node->getPred() ) == 0 ) { |
606
|
|
|
$this->m_startnodes[] = $node; |
607
|
|
|
} |
608
|
|
|
} |
609
|
|
|
} |
610
|
|
|
|
611
|
|
|
return $this->m_startnodes; |
612
|
|
|
} |
613
|
|
|
|
614
|
|
|
public function setShowStatus( $show ) { |
615
|
|
|
$this->m_showStatus = $show; |
616
|
|
|
} |
617
|
|
|
|
618
|
|
|
public function getShowStatus() { |
619
|
|
|
return $this->m_showStatus; |
620
|
|
|
} |
621
|
|
|
|
622
|
|
|
public function setShowRoles( $show ) { |
623
|
|
|
$this->m_showRoles = $show; |
624
|
|
|
} |
625
|
|
|
|
626
|
|
|
public function getShowRoles() { |
627
|
|
|
return $this->m_showRoles; |
628
|
|
|
} |
629
|
|
|
|
630
|
|
|
public function setShowCompound( $show ) { |
631
|
|
|
$this->m_showCompound = $show; |
632
|
|
|
} |
633
|
|
|
|
634
|
|
|
public function getShowCompound() { |
635
|
|
|
return $this->m_showCompound; |
636
|
|
|
} |
637
|
|
|
|
638
|
|
|
public function setShowDiscussion( $show ) { |
639
|
|
|
$this->m_showDiscussion = $show; |
640
|
|
|
} |
641
|
|
|
|
642
|
|
|
public function getShowDiscussion() { |
643
|
|
|
return $this->m_showDiscussion; |
644
|
|
|
} |
645
|
|
|
|
646
|
|
|
public function setShowRessources( $show ) { |
647
|
|
|
$this->m_showRessources = $show; |
648
|
|
|
} |
649
|
|
|
|
650
|
|
|
public function getShowRessources() { |
651
|
|
|
return $this->m_showRessources; |
652
|
|
|
} |
653
|
|
|
|
654
|
|
|
public function setGraphName( $name ) { |
655
|
|
|
$this->m_graphName = $name; |
656
|
|
|
} |
657
|
|
|
|
658
|
|
|
public function getGraphName() { |
659
|
|
|
if ( $this->m_graphName == '' ) { |
660
|
|
|
$this->m_graphName = 'ProcessQueryResult' . rand( 1, 99999 ); |
661
|
|
|
} |
662
|
|
|
return $this->m_graphName; |
663
|
|
|
} |
664
|
|
|
|
665
|
|
|
public function setGraphSize( $size ) { |
666
|
|
|
$this->m_graphSize = $size; |
667
|
|
|
} |
668
|
|
|
|
669
|
|
|
public function setRankdir( $rankdir ) { |
670
|
|
|
$this->m_rankdir = $rankdir; |
671
|
|
|
} |
672
|
|
|
|
673
|
|
|
public function setClusterColor( $color ) { |
674
|
|
|
$this->m_clusterColor = $color; |
675
|
|
|
} |
676
|
|
|
|
677
|
|
|
public function setHighlightColor( $color ) { |
678
|
|
|
$this->m_highlightColor = $color; |
679
|
|
|
} |
680
|
|
|
|
681
|
|
|
public function setRedLinkColor( $color ) { |
682
|
|
|
$this->m_redLinkColor = $color; |
683
|
|
|
} |
684
|
|
|
|
685
|
|
|
public function setShowRedLinks( $show ) { |
686
|
|
|
$this->m_showRedLinks = $show; |
687
|
|
|
} |
688
|
|
|
|
689
|
|
|
public function setHighlightNode( $name ) { |
690
|
|
|
$this->m_highlightNode = $name; |
691
|
|
|
} |
692
|
|
|
|
693
|
|
|
public function addError( $error ) { |
694
|
|
|
$this->m_errors[] = $error; |
695
|
|
|
} |
696
|
|
|
|
697
|
|
|
public function getErrors() { |
698
|
|
|
return $this->m_errors; |
699
|
|
|
} |
700
|
|
|
|
701
|
|
|
public function getGraphVizCode() { |
702
|
|
|
// |
703
|
|
|
// header |
704
|
|
|
// |
705
|
|
|
$res = 'digraph ' . $this->getGraphName() . ' { |
706
|
|
|
|
707
|
|
|
ranksep="0.5";'; |
708
|
|
|
if ( $this->m_graphSize != '' ) { |
709
|
|
|
$res .= ' |
710
|
|
|
size="' . $this->m_graphSize . '";'; |
711
|
|
|
} |
712
|
|
|
$res .= ' |
713
|
|
|
rankdir=' . $this->m_rankdir . '; |
714
|
|
|
'; |
715
|
|
|
|
716
|
|
|
// |
717
|
|
|
// add startnodes |
718
|
|
|
// |
719
|
|
|
// TODO I18N |
720
|
|
|
$res .= ' |
721
|
|
|
{rank=source; "Start";} |
722
|
|
|
"Start"[shape=box,label="Start",style=filled,color=green];'; |
723
|
|
|
|
724
|
|
|
foreach ( $this->getStartNodes() as $node ) { |
725
|
|
|
$res .= ' |
726
|
|
|
"Start" -> "' . $node->getId() . '":port1:n;'; |
727
|
|
|
} |
728
|
|
|
|
729
|
|
|
$res .= ' |
730
|
|
|
'; |
731
|
|
|
|
732
|
|
|
// |
733
|
|
|
// add endnodes |
734
|
|
|
// |
735
|
|
|
// TODO I18N |
736
|
|
|
$res .= ' |
737
|
|
|
{rank=sink; "End"; } |
738
|
|
|
"End"[shape=box,label="End",style=filled,color=green];'; |
739
|
|
|
|
740
|
|
|
foreach ( $this->getEndNodes() as $node ) { |
741
|
|
|
$res .= ' |
742
|
|
|
"' . $node->getId() . '":port1:s -> "End";'; |
743
|
|
|
} |
744
|
|
|
|
745
|
|
|
$res .= ' |
746
|
|
|
|
747
|
|
|
'; |
748
|
|
|
|
749
|
|
|
// |
750
|
|
|
// add subnodes |
751
|
|
|
// |
752
|
|
|
foreach ( $this->m_nodes as $node ) { |
753
|
|
|
$res .= $node->getGraphVizCode(); |
754
|
|
|
} |
755
|
|
|
|
756
|
|
|
// |
757
|
|
|
// add final stuff |
758
|
|
|
// |
759
|
|
|
$res .= |
760
|
|
|
' |
761
|
|
|
}'; |
762
|
|
|
|
763
|
|
|
return $res; |
764
|
|
|
|
765
|
|
|
} |
766
|
|
|
|
767
|
|
|
} |
768
|
|
|
|
769
|
|
|
abstract class ProcessElement { |
770
|
|
|
|
771
|
|
|
// TODO I18N |
772
|
|
|
private $m_id = 'no_id'; |
773
|
|
|
private $m_label = 'unlabeled'; |
774
|
|
|
private $m_uid; |
775
|
|
|
|
776
|
|
|
public function getUUID() { |
777
|
|
|
if ( !isset( $this->m_uid ) ) { |
778
|
|
|
$this->m_uid = sprintf( |
779
|
|
|
'%04x%04x-%04x-%04x-%04x-%04x%04x%04x', |
780
|
|
|
mt_rand( 0, 0xffff ), |
781
|
|
|
mt_rand( 0, 0xffff ), |
782
|
|
|
mt_rand( 0, 0xffff ), |
783
|
|
|
mt_rand( 0, 0x0fff ) | 0x4000, |
784
|
|
|
mt_rand( 0, 0x3fff ) | 0x8000, |
785
|
|
|
mt_rand( 0, 0xffff ), |
786
|
|
|
mt_rand( 0, 0xffff ), |
787
|
|
|
mt_rand( 0, 0xffff ) |
788
|
|
|
); |
789
|
|
|
} |
790
|
|
|
|
791
|
|
|
return $this->m_uid; |
792
|
|
|
} |
793
|
|
|
|
794
|
|
|
public function getId() { |
795
|
|
|
return $this->m_id; |
796
|
|
|
} |
797
|
|
|
|
798
|
|
|
public function setId( $id ) { |
799
|
|
|
$this->m_id = $id; |
800
|
|
|
} |
801
|
|
|
|
802
|
|
|
public function getLabel() { |
803
|
|
|
return $this->m_label; |
804
|
|
|
} |
805
|
|
|
|
806
|
|
|
public function setLabel( $label ) { |
807
|
|
|
$this->m_label = $label; |
808
|
|
|
} |
809
|
|
|
|
810
|
|
|
} |
811
|
|
|
|
812
|
|
|
class ProcessRessource extends ProcessElement { |
813
|
|
|
|
814
|
|
|
private $m_usedby = []; |
815
|
|
|
private $m_producedby = []; |
816
|
|
|
|
817
|
|
|
public function getProducers() { |
818
|
|
|
return $this->m_producedby; |
819
|
|
|
} |
820
|
|
|
|
821
|
|
|
public function getUsers() { |
822
|
|
|
return $this->m_usedby; |
823
|
|
|
} |
824
|
|
|
|
825
|
|
|
public function addProducer( $node ) { |
826
|
|
|
$this->m_producedby[] = $node; |
827
|
|
|
} |
828
|
|
|
|
829
|
|
|
public function addUser( $node ) { |
830
|
|
|
$this->m_usedby[] = $node; |
831
|
|
|
} |
832
|
|
|
|
833
|
|
|
} |
834
|
|
|
|
835
|
|
|
class ProcessRole extends ProcessElement { |
836
|
|
|
|
837
|
|
|
private $m_nodes = []; |
838
|
|
|
|
839
|
|
|
public function getNodes() { |
840
|
|
|
return $this->m_nodes; |
841
|
|
|
} |
842
|
|
|
|
843
|
|
|
public function addNode( $node ) { |
844
|
|
|
$this->m_nodes[] = $node; |
845
|
|
|
} |
846
|
|
|
|
847
|
|
|
} |
848
|
|
|
|
849
|
|
|
class ProcessNode extends ProcessElement { |
850
|
|
|
|
851
|
|
|
private $m_status; // status value |
852
|
|
|
private $m_is_atomic = true; // set false if this is a compound node |
853
|
|
|
|
854
|
|
|
private $m_process; // reference to parent process |
855
|
|
|
|
856
|
|
|
private $m_fontColor = ''; // font color to render |
857
|
|
|
|
858
|
|
|
private $m_usedressources = []; // ressources used by this node |
859
|
|
|
private $m_producedressources = []; // ressources produces by this node |
860
|
|
|
private $m_roles = []; // roles related to this node |
861
|
|
|
|
862
|
|
|
private $m_edgeout; // outgoing edge (can be only one) |
863
|
|
|
private $m_edgesin = []; // incoming edges (can be many) |
864
|
|
|
|
865
|
|
|
public function setStatus( $status ) { |
866
|
|
|
$this->m_status = $status; |
867
|
|
|
} |
868
|
|
|
|
869
|
|
|
public function getStatus() { |
870
|
|
|
return $this->m_status; |
871
|
|
|
} |
872
|
|
|
|
873
|
|
|
public function setFontColor( $color ) { |
874
|
|
|
$this->m_fontColor = $color; |
875
|
|
|
} |
876
|
|
|
|
877
|
|
|
public function setProcess( $proc ) { |
878
|
|
|
$this->m_process = $proc; |
879
|
|
|
} |
880
|
|
|
|
881
|
|
|
public function getProcess() { |
882
|
|
|
return $this->m_process; |
883
|
|
|
} |
884
|
|
|
|
885
|
|
|
public function getPred() { |
886
|
|
|
$res = []; |
887
|
|
|
|
888
|
|
|
foreach ( $this->m_edgesin as $edge ) { |
889
|
|
|
$res = array_merge( $res, $edge->getPred() ); |
890
|
|
|
} |
891
|
|
|
|
892
|
|
|
return $res; |
893
|
|
|
} |
894
|
|
|
|
895
|
|
|
public function getSucc() { |
896
|
|
|
$res = []; |
897
|
|
|
|
898
|
|
|
if ( isset( $this->m_edgeout ) ) { |
899
|
|
|
$res = $this->m_edgeout->getSucc(); |
900
|
|
|
} |
901
|
|
|
|
902
|
|
|
return $res; |
903
|
|
|
} |
904
|
|
|
|
905
|
|
|
public function setEdgeOut( $edge ) { |
906
|
|
|
$this->m_edgeout = $edge; |
907
|
|
|
} |
908
|
|
|
|
909
|
|
|
public function getEdgeOut() { |
910
|
|
|
return $this->m_edgeout; |
911
|
|
|
} |
912
|
|
|
|
913
|
|
|
public function addEdgeIn( $edge ) { |
914
|
|
|
$this->m_edgesin[] = $edge; |
915
|
|
|
} |
916
|
|
|
|
917
|
|
|
public function getEdgesIn() { |
918
|
|
|
return $this->m_edgesin; |
919
|
|
|
} |
920
|
|
|
|
921
|
|
|
public function addRole( $role ) { |
922
|
|
|
$this->m_roles[] = $role; |
923
|
|
|
$role->addNode( $this ); |
924
|
|
|
} |
925
|
|
|
|
926
|
|
|
public function getRoles() { |
927
|
|
|
return $this->m_roles; |
928
|
|
|
} |
929
|
|
|
|
930
|
|
|
public function addUsedRessource( $res ) { |
931
|
|
|
$this->m_usedressources[] = $res; |
932
|
|
|
$res->addUser( $this ); |
933
|
|
|
} |
934
|
|
|
|
935
|
|
|
public function getUsedRessources() { |
936
|
|
|
return $this->m_usedressources; |
937
|
|
|
} |
938
|
|
|
|
939
|
|
|
public function addProducedRessource( $res ) { |
940
|
|
|
$this->m_producedressources[] = $res; |
941
|
|
|
$res->addProducer( $this ); |
942
|
|
|
} |
943
|
|
|
|
944
|
|
|
public function getProducedRessources() { |
945
|
|
|
return $this->m_producedressources; |
946
|
|
|
} |
947
|
|
|
|
948
|
|
|
public function isAtomic() { |
949
|
|
|
return $this->m_is_atomic; |
950
|
|
|
} |
951
|
|
|
|
952
|
|
|
public function setAtomic( $atomic ) { |
953
|
|
|
$this->m_is_atomic = $atomic; |
954
|
|
|
} |
955
|
|
|
|
956
|
|
|
public function getGraphVizCode() { |
957
|
|
|
global $IP, $srfgPicturePath, $srfgIP; |
958
|
|
|
// |
959
|
|
|
// show node status |
960
|
|
|
// |
961
|
|
|
$status = ''; |
962
|
|
|
if ( $this->getProcess()->getShowStatus() ) { |
963
|
|
|
|
964
|
|
|
if ( file_exists( $IP . "/images/p000.png" ) ) { |
965
|
|
|
$PicturePath = $IP . "/images/"; |
966
|
|
|
} elseif ( file_exists( $srfgIP . "/formats/graphviz/images/p000.png" ) ) { |
967
|
|
|
$PicturePath = $srfgIP . "/formats/graphviz/images/"; |
968
|
|
|
} else { |
969
|
|
|
$PicturePath = $IP . $srfgPicturePath; |
970
|
|
|
} |
971
|
|
|
// $color = 'grey' . $this->getStatus(); |
972
|
|
|
// $color = 'grey' . rand(1, 100); |
973
|
|
|
// $status = ',style=filled,color=' . $color; |
974
|
|
|
if ( $this->getStatus() != '' ) { |
975
|
|
|
if ( $this->getStatus() < 25 ) { |
976
|
|
|
$status = ' HREF="[[' . $this->getId() . ']]" TOOLTIP="status ' . $this->getStatus( |
977
|
|
|
) . '%"><IMG SRC="' . $PicturePath . 'p000.png" /'; |
978
|
|
|
} elseif ( $this->getStatus() < 50 ) { |
979
|
|
|
$status = ' HREF="[[' . $this->getId() . ']]" TOOLTIP="status ' . $this->getStatus( |
980
|
|
|
) . '%"><IMG SRC="' . $PicturePath . 'p025.png" /'; |
981
|
|
|
} elseif ( $this->getStatus() < 75 ) { |
982
|
|
|
$status = ' HREF="[[' . $this->getId() . ']]" TOOLTIP="status ' . $this->getStatus( |
983
|
|
|
) . '%"><IMG SRC="' . $PicturePath . 'p050.png" /'; |
984
|
|
|
} elseif ( $this->getStatus() < 100 ) { |
985
|
|
|
$status = ' HREF="[[' . $this->getId() . ']]" TOOLTIP="status ' . $this->getStatus( |
986
|
|
|
) . '%"><IMG SRC="' . $PicturePath . 'p075.png" /'; |
987
|
|
|
} elseif ( $this->getStatus() == 100 ) { |
988
|
|
|
$status = ' HREF="[[' . $this->getId() . ']]" TOOLTIP="status ' . $this->getStatus( |
989
|
|
|
) . '%"><IMG SRC="' . $PicturePath . 'p100.png" /'; |
990
|
|
|
} |
991
|
|
|
} |
992
|
|
|
|
993
|
|
|
} |
994
|
|
|
|
995
|
|
|
// |
996
|
|
|
// show discussion page |
997
|
|
|
// |
998
|
|
|
$discussion = ''; |
999
|
|
|
if ( $this->getProcess()->getShowDiscussion() ) { |
1000
|
|
|
|
1001
|
|
|
if ( file_exists( $IP . "/images/discuss_icon.png" ) ) { |
1002
|
|
|
$PicturePath = $IP . "/images/"; |
1003
|
|
|
} elseif ( file_exists( $srfgIP . "/formats/graphviz/images/discuss_icon.png" ) ) { |
1004
|
|
|
$PicturePath = $srfgIP . "/formats/graphviz/images/"; |
1005
|
|
|
} else { |
1006
|
|
|
$PicturePath = $IP . $srfgPicturePath; |
1007
|
|
|
} |
1008
|
|
|
$discussionTitle = Title::newFromText( 'Talk:' . $this->getId() . '' ); |
1009
|
|
|
if ( $discussionTitle->isKnown() ) { |
1010
|
|
|
$discussion = ' HREF="[[Talk:' . $this->getId() . ']]" TOOLTIP="Talk:' . $this->getId( |
1011
|
|
|
) . '"><IMG SRC="' . $PicturePath . 'discuss_icon.png" /'; |
1012
|
|
|
} else { |
1013
|
|
|
$discussion = ' HREF="[[Talk:' . $this->getId() . ']]" TOOLTIP="Talk:' . $this->getId( |
1014
|
|
|
) . '"><IMG SRC="' . $PicturePath . 'discuss_icon_grey.png" /'; |
1015
|
|
|
} |
1016
|
|
|
|
1017
|
|
|
} |
1018
|
|
|
|
1019
|
|
|
// use highlight color if set (either CURRENTPAGE or REDLINK highlighting - see ProcessGraph::makeNode() |
1020
|
|
|
$high = ''; |
1021
|
|
|
if ( $this->m_fontColor !== '' ) { |
1022
|
|
|
$high = ',fontcolor=' . $this->m_fontColor; |
1023
|
|
|
} |
1024
|
|
|
|
1025
|
|
|
// insert icon for non-atomic nodes (i.e. subprocesses) |
1026
|
|
|
$compound = '<TR><TD ALIGN="LEFT" BORDER="0" WIDTH="20px">'; |
1027
|
|
|
if ( $this->getProcess()->getShowCompound() ) { |
1028
|
|
|
if ( file_exists( $IP . "/images/subprocess.png" ) ) { |
1029
|
|
|
$PicturePath = $IP . "/images/"; |
1030
|
|
|
} elseif ( file_exists( $srfgIP . "/formats/graphviz/images/subprocess.png" ) ) { |
1031
|
|
|
$PicturePath = $srfgIP . "/formats/graphviz/images/"; |
1032
|
|
|
} else { |
1033
|
|
|
$PicturePath = $IP . $srfgPicturePath; |
1034
|
|
|
} |
1035
|
|
|
if ( !$this->isAtomic() ) { |
1036
|
|
|
$compound = '<TR><TD ALIGN="LEFT" BORDER="0" WIDTH="20px" HREF="[[' . $this->getId( |
1037
|
|
|
) . ']]" TOOLTIP="sub process"><IMG SRC="' . $PicturePath . 'subprocess.png"/>'; |
1038
|
|
|
} |
1039
|
|
|
} |
1040
|
|
|
|
1041
|
|
|
// |
1042
|
|
|
// render node itself |
1043
|
|
|
// |
1044
|
|
|
if ( $this->m_process->m_useHtmlNodes ) { |
1045
|
|
|
$res = |
1046
|
|
|
'"' . $this->getId( |
1047
|
|
|
) . '" [shape=plaintext,label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">' . $compound . '</TD><TD BORDER="0" WIDTH="80%"></TD><TD ALIGN="RIGHT" BORDER="0" WIDTH="20px"' . $status . '></TD><TD ALIGN="RIGHT" BORDER="0" WIDTH="20px"' . $discussion . '></TD></TR><TR><TD COLSPAN="4" PORT="port1" HREF="[[' . $this->getId( |
1048
|
|
|
) . ']]" TOOLTIP="' . $this->getLabel() . '"><FONT' . $high . '>' . $this->getLabel() . '</FONT></TD> </TR></TABLE>>]; |
1049
|
|
|
'; |
1050
|
|
|
} else { |
1051
|
|
|
$res = |
1052
|
|
|
'"' . $this->getId() . '"[label="' . $this->getLabel( |
1053
|
|
|
) . '",shape=rect, height=1.5, URL="[[' . $this->getId() . ']]"]; |
1054
|
|
|
'; |
1055
|
|
|
} |
1056
|
|
|
|
1057
|
|
|
// |
1058
|
|
|
// render outgoing node |
1059
|
|
|
// |
1060
|
|
|
if ( isset( $this->m_edgeout ) ) { |
1061
|
|
|
$res .= $this->m_edgeout->getGraphVizCode(); |
1062
|
|
|
} |
1063
|
|
|
|
1064
|
|
|
// |
1065
|
|
|
// show cluster for roles and ressources |
1066
|
|
|
// |
1067
|
|
|
$rrcluster = false; |
1068
|
|
|
$rrcode = 'subgraph "cluster_role' . rand( 1, 9999 ) . '" { style=filled;color=lightgrey;'; |
1069
|
|
|
|
1070
|
|
|
// show roles |
1071
|
|
|
if ( $this->getProcess()->getShowRoles() ) { |
1072
|
|
|
|
1073
|
|
|
foreach ( $this->getRoles() as $role ) { |
1074
|
|
|
$rrcluster = true; |
1075
|
|
|
$rrcode .= ' |
1076
|
|
|
"' . $role->getId() . '"[label="' . $role->getLabel( |
1077
|
|
|
) . '",shape=doubleoctagon, color=red, URL="[[' . $role->getId() . ']]"]; |
1078
|
|
|
"' . $role->getId() . '" -> "' . $this->getId() . '":port1 [color=red,arrowhead = none,constraint=false]; |
1079
|
|
|
'; |
1080
|
|
|
|
1081
|
|
|
} |
1082
|
|
|
} |
1083
|
|
|
|
1084
|
|
|
if ( $this->getProcess()->getShowRessources() ) { |
1085
|
|
|
|
1086
|
|
|
foreach ( $this->getUsedRessources() as $xres ) { |
1087
|
|
|
$rrcluster = true; |
1088
|
|
|
$rrcode .= ' |
1089
|
|
|
"' . $xres->getId() . '"[label="' . $xres->getLabel( |
1090
|
|
|
) . '",shape=folder, color=blue, URL="[[' . $xres->getId() . ']]"]; |
1091
|
|
|
"' . $xres->getId() . '" -> "' . $this->getId() . '":port1 [color=blue,constraint=false]; |
1092
|
|
|
'; |
1093
|
|
|
} |
1094
|
|
|
|
1095
|
|
|
foreach ( $this->getProducedRessources() as $xres ) { |
1096
|
|
|
$rrcluster = true; |
1097
|
|
|
$rrcode .= ' |
1098
|
|
|
"' . $xres->getId() . '"[label="' . $xres->getLabel( |
1099
|
|
|
) . '",shape=folder, color=blue, URL="[[' . $xres->getId() . ']]"]; |
1100
|
|
|
"' . $this->getId() . '":port1 -> "' . $xres->getId() . '" [color=blue,constraint=false]; |
1101
|
|
|
'; |
1102
|
|
|
} |
1103
|
|
|
|
1104
|
|
|
} |
1105
|
|
|
|
1106
|
|
|
if ( $rrcluster ) { |
1107
|
|
|
$res .= $rrcode . '}'; |
1108
|
|
|
} |
1109
|
|
|
|
1110
|
|
|
$res .= ' |
1111
|
|
|
'; |
1112
|
|
|
|
1113
|
|
|
return $res; |
1114
|
|
|
} |
1115
|
|
|
|
1116
|
|
|
} |
1117
|
|
|
|
1118
|
|
|
/** |
1119
|
|
|
* Abstract base class for edges in a process graph |
1120
|
|
|
*/ |
1121
|
|
|
abstract class ProcessEdge { |
1122
|
|
|
|
1123
|
|
|
private $m_id; |
1124
|
|
|
private $m_uid; |
1125
|
|
|
|
1126
|
|
|
public function getId() { |
1127
|
|
|
if ( !isset( $this->m_id ) ) { |
1128
|
|
|
$this->m_id = 'edge' . rand( 1, 99999 ); |
1129
|
|
|
} |
1130
|
|
|
|
1131
|
|
|
return $this->m_id; |
1132
|
|
|
} |
1133
|
|
|
|
1134
|
|
|
public function getUUID() { |
1135
|
|
|
if ( !isset( $this->m_uid ) ) { |
1136
|
|
|
$this->m_uid = sprintf( |
1137
|
|
|
'%04x%04x-%04x-%04x-%04x-%04x%04x%04x', |
1138
|
|
|
mt_rand( 0, 0xffff ), |
1139
|
|
|
mt_rand( 0, 0xffff ), |
1140
|
|
|
mt_rand( 0, 0xffff ), |
1141
|
|
|
mt_rand( 0, 0x0fff ) | 0x4000, |
1142
|
|
|
mt_rand( 0, 0x3fff ) | 0x8000, |
1143
|
|
|
mt_rand( 0, 0xffff ), |
1144
|
|
|
mt_rand( 0, 0xffff ), |
1145
|
|
|
mt_rand( 0, 0xffff ) |
1146
|
|
|
); |
1147
|
|
|
} |
1148
|
|
|
|
1149
|
|
|
return $this->m_uid; |
1150
|
|
|
} |
1151
|
|
|
|
1152
|
|
|
abstract public function getSucc(); |
1153
|
|
|
|
1154
|
|
|
abstract public function getPred(); |
1155
|
|
|
|
1156
|
|
|
abstract public function getGraphVizCode(); |
1157
|
|
|
} |
1158
|
|
|
|
1159
|
|
|
abstract class SplitEdge extends ProcessEdge { |
1160
|
|
|
|
1161
|
|
|
protected $m_from; |
1162
|
|
|
protected $m_to = []; |
1163
|
|
|
|
1164
|
|
|
public function setFrom( $node ) { |
1165
|
|
|
$this->m_from = $node; |
1166
|
|
|
$node->setEdgeOut( $this ); |
1167
|
|
|
} |
1168
|
|
|
|
1169
|
|
|
public function addTo( $node ) { |
1170
|
|
|
$this->m_to[] = $node; |
1171
|
|
|
$node->addEdgeIn( $this ); |
1172
|
|
|
} |
1173
|
|
|
|
1174
|
|
|
public function getPred() { |
1175
|
|
|
return [ $this->m_from ]; |
1176
|
|
|
} |
1177
|
|
|
|
1178
|
|
|
public function getSucc() { |
1179
|
|
|
return $this->m_to; |
1180
|
|
|
} |
1181
|
|
|
|
1182
|
|
|
} |
1183
|
|
|
|
1184
|
|
|
class SplitConditionalOrEdge extends ProcessEdge { |
1185
|
|
|
|
1186
|
|
|
protected $m_from; |
1187
|
|
|
protected $m_to_true; |
1188
|
|
|
protected $m_to_false; |
1189
|
|
|
protected $m_con_text = 'empty_condition'; |
1190
|
|
|
|
1191
|
|
|
public function getSucc() { |
1192
|
|
|
return [ $this->m_to_false, $this->m_to_true ]; |
1193
|
|
|
} |
1194
|
|
|
|
1195
|
|
|
public function getPred() { |
1196
|
|
|
return [ $this->m_from ]; |
1197
|
|
|
} |
1198
|
|
|
|
1199
|
|
|
public function setFrom( $node ) { |
1200
|
|
|
$this->m_from = $node; |
1201
|
|
|
$node->setEdgeOut( $this ); |
1202
|
|
|
} |
1203
|
|
|
|
1204
|
|
|
public function setToFalse( $node ) { |
1205
|
|
|
$this->m_to_false = $node; |
1206
|
|
|
$node->addEdgeIn( $this ); |
1207
|
|
|
} |
1208
|
|
|
|
1209
|
|
|
public function setToTrue( $node ) { |
1210
|
|
|
$this->m_to_true = $node; |
1211
|
|
|
$node->addEdgeIn( $this ); |
1212
|
|
|
} |
1213
|
|
|
|
1214
|
|
|
public function setConditionText( $cond ) { |
1215
|
|
|
$this->m_con_text = $cond; |
1216
|
|
|
} |
1217
|
|
|
|
1218
|
|
|
public function getGraphVizCode() { |
1219
|
|
|
|
1220
|
|
|
$p = $this->m_from; |
1221
|
|
|
|
1222
|
|
|
if ( ( !isset( $this->m_from ) ) || ( !isset( $this->m_to_false ) ) || ( !isset( $this->m_to_true ) ) ) { |
1223
|
|
|
|
1224
|
|
|
echo "error with SplitConditionalOrEdge"; // TODO |
1225
|
|
|
exit; |
|
|
|
|
1226
|
|
|
} |
1227
|
|
|
|
1228
|
|
|
$res = |
1229
|
|
|
'subgraph "clus_' . $this->getId() . '" { |
1230
|
|
|
'; |
1231
|
|
|
|
1232
|
|
|
// cond-Shape |
1233
|
|
|
$con = 'con' . rand( 1, 99999 ); |
1234
|
|
|
$res .= |
1235
|
|
|
'"' . $con . '"[shape=diamond,label="' . $this->m_con_text . '",style=filled,color=skyblue]; |
1236
|
|
|
"' . $p->getId() . '":port1:s -> "' . $con . '"; |
1237
|
|
|
'; |
1238
|
|
|
|
1239
|
|
|
// True Succ |
1240
|
|
|
$res .= |
1241
|
|
|
'"' . $this->m_to_true->getId() . '" [URL = "[[' . $this->m_to_true->getId() . ']]"]; |
1242
|
|
|
'; |
1243
|
|
|
|
1244
|
|
|
$res .= |
1245
|
|
|
'"' . $con . '" -> "' . $this->m_to_true->getId() . '":port1:n [label="true"]; |
1246
|
|
|
'; |
1247
|
|
|
|
1248
|
|
|
// False Succ |
1249
|
|
|
$res .= |
1250
|
|
|
'"' . $this->m_to_false->getId() . '" [URL = "[[' . $this->m_to_false->getId() . ']]"]; |
1251
|
|
|
'; |
1252
|
|
|
|
1253
|
|
|
$res .= |
1254
|
|
|
'"' . $con . '" -> "' . $this->m_to_false->getId() . '":port1:n [label="false"];'; |
1255
|
|
|
|
1256
|
|
|
$res .= ' |
1257
|
|
|
} |
1258
|
|
|
'; |
1259
|
|
|
|
1260
|
|
|
return $res; |
1261
|
|
|
} |
1262
|
|
|
|
1263
|
|
|
} |
1264
|
|
|
|
1265
|
|
|
class SplitExclusiveOrEdge extends SplitEdge { |
1266
|
|
|
|
1267
|
|
|
public function getGraphVizCode() { |
1268
|
|
|
global $srfgShapeStyle; |
1269
|
|
|
$p = $this->getPred(); |
1270
|
|
|
$p = $p[0]; |
1271
|
|
|
if ( $srfgShapeStyle == '' ) { |
1272
|
|
|
$srfgShapeStyle = "box"; |
1273
|
|
|
} |
1274
|
|
|
$res = |
1275
|
|
|
'subgraph "clus_' . $this->getId() . '" { |
1276
|
|
|
'; |
1277
|
|
|
|
1278
|
|
|
// add OR-Shape |
1279
|
|
|
$orx = 'or' . rand( 1, 99999 ); |
1280
|
|
|
$res .= |
1281
|
|
|
'"' . $orx . '"[shape=' . $srfgShapeStyle . ',label="+",style=filled,color=gold]; |
1282
|
|
|
"' . $p->getId() . '":port1:s -> "' . $orx . '"; |
1283
|
|
|
'; |
1284
|
|
|
|
1285
|
|
|
foreach ( $this->getSucc() as $s ) { |
1286
|
|
|
$res .= |
1287
|
|
|
'"' . $s->getId() . '" [URL="[[' . $s->getId() . ']]"]; |
1288
|
|
|
'; |
1289
|
|
|
|
1290
|
|
|
$res .= |
1291
|
|
|
'"' . $orx . '" -> "' . $s->getId() . '":port1:n; |
1292
|
|
|
'; |
1293
|
|
|
} |
1294
|
|
|
|
1295
|
|
|
$res .= ' |
1296
|
|
|
} |
1297
|
|
|
'; |
1298
|
|
|
|
1299
|
|
|
return $res; |
1300
|
|
|
} |
1301
|
|
|
|
1302
|
|
|
} |
1303
|
|
|
|
1304
|
|
|
class SplitParallelEdge extends SplitEdge { |
1305
|
|
|
|
1306
|
|
|
public function getGraphVizCode() { |
1307
|
|
|
global $srfgShapeStyle; |
1308
|
|
|
if ( $srfgShapeStyle == '' ) { |
1309
|
|
|
$srfgShapeStyle = "box"; |
1310
|
|
|
} |
1311
|
|
|
$p = $this->getPred(); |
1312
|
|
|
$p = $p[0]; |
1313
|
|
|
|
1314
|
|
|
$res = |
1315
|
|
|
'subgraph "clus_' . $this->getId() . '" { |
1316
|
|
|
'; |
1317
|
|
|
|
1318
|
|
|
// add AND-Shape |
1319
|
|
|
$and = 'and' . rand( 1, 99999 ); |
1320
|
|
|
$res .= |
1321
|
|
|
'"' . $and . '"[shape=' . $srfgShapeStyle . ',label="||",style=filled,color=palegreen]; |
1322
|
|
|
"' . $p->getId() . '":port1:s -> "' . $and . '"; |
1323
|
|
|
'; |
1324
|
|
|
|
1325
|
|
|
foreach ( $this->getSucc() as $s ) { |
1326
|
|
|
$res .= |
1327
|
|
|
'"' . $s->getId() . '" [URL = "[[' . $s->getId() . ']]"]; |
1328
|
|
|
'; |
1329
|
|
|
|
1330
|
|
|
$res .= |
1331
|
|
|
'"' . $and . '" -> "' . $s->getId() . '":port1:n; |
1332
|
|
|
'; |
1333
|
|
|
} |
1334
|
|
|
|
1335
|
|
|
$res .= ' |
1336
|
|
|
} |
1337
|
|
|
'; |
1338
|
|
|
|
1339
|
|
|
return $res; |
1340
|
|
|
} |
1341
|
|
|
|
1342
|
|
|
} |
1343
|
|
|
|
1344
|
|
|
class SequentialEdge extends ProcessEdge { |
1345
|
|
|
|
1346
|
|
|
private $m_from; |
1347
|
|
|
private $m_to; |
1348
|
|
|
|
1349
|
|
|
public function setFrom( $node ) { |
1350
|
|
|
$this->m_from = $node; |
1351
|
|
|
$node->setEdgeOut( $this ); |
1352
|
|
|
} |
1353
|
|
|
|
1354
|
|
|
public function setTo( $node ) { |
1355
|
|
|
$this->m_to = $node; |
1356
|
|
|
$node->addEdgeIn( $this ); |
1357
|
|
|
} |
1358
|
|
|
|
1359
|
|
|
public function getPred() { |
1360
|
|
|
return [ $this->m_from ]; |
1361
|
|
|
} |
1362
|
|
|
|
1363
|
|
|
public function getSucc() { |
1364
|
|
|
return [ $this->m_to ]; |
1365
|
|
|
} |
1366
|
|
|
|
1367
|
|
|
public function getGraphVizCode() { |
1368
|
|
|
|
1369
|
|
|
$p = $this->m_from; |
1370
|
|
|
$s = $this->m_to; |
1371
|
|
|
|
1372
|
|
|
$res = |
1373
|
|
|
'subgraph "clus_' . $this->getId() . '" { |
1374
|
|
|
'; |
1375
|
|
|
|
1376
|
|
|
$res .= |
1377
|
|
|
'"' . $s->getId() . '" [URL = "[[' . $s->getId() . ']]"]; |
1378
|
|
|
'; |
1379
|
|
|
|
1380
|
|
|
$res .= |
1381
|
|
|
'"' . $p->getId() . '":port1:s -> "' . $s->getId() . '":port1:n;'; |
1382
|
|
|
|
1383
|
|
|
$res .= ' |
1384
|
|
|
} |
1385
|
|
|
'; |
1386
|
|
|
|
1387
|
|
|
return $res; |
1388
|
|
|
} |
1389
|
|
|
|
1390
|
|
|
} |
The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.
The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.
To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.