*/ class GraphPrinter extends SMWResultPrinter { const NODELABEL_DISPLAYTITLE = 'displaytitle'; public static $NODE_LABELS = [ self::NODELABEL_DISPLAYTITLE, ]; public static $NODE_SHAPES = [ 'box', 'box3d', 'circle', 'component', 'diamond', 'doublecircle', 'doubleoctagon', 'egg', 'ellipse', 'folder', 'hexagon', 'house', 'invhouse', 'invtrapezium', 'invtriangle', 'Mcircle', 'Mdiamond', 'Msquare', 'none', 'note', 'octagon', 'parallelogram', 'pentagon ', 'plaintext', 'point', 'polygon', 'rect', 'rectangle', 'septagon', 'square', 'tab', 'trapezium', 'triangle', 'tripleoctagon', ]; protected $m_graphName; protected $m_graphLabel; protected $m_graphColor; protected $m_graphLegend; protected $m_graphLink; protected $m_rankdir; protected $m_graphSize; protected $m_labelArray = []; protected $m_graphColors = [ 'black', 'red', 'green', 'blue', 'darkviolet', 'gold', 'deeppink', 'brown', 'bisque', 'darkgreen', 'yellow', 'darkblue', 'magenta', 'steelblue2' ]; protected $m_nameProperty; protected $m_nodeShape; protected $m_parentRelation; protected $m_wordWrapLimit; protected $m_nodeLabel; /** * (non-PHPdoc) * @see SMWResultPrinter::handleParameters() */ protected function handleParameters( array $params, $outputmode ) { parent::handleParameters( $params, $outputmode ); $this->m_graphName = trim( $params['graphname'] ); $this->m_graphSize = trim( $params['graphsize'] ); $this->m_graphLegend = $params['graphlegend']; $this->m_graphLabel = $params['graphlabel']; $this->m_rankdir = strtoupper( trim( $params['arrowdirection'] ) ); $this->m_graphLink = $params['graphlink']; $this->m_graphColor = $params['graphcolor']; $this->m_nameProperty = $params['nameproperty'] === false ? false : trim( $params['nameproperty'] ); $this->m_parentRelation = strtolower( trim( $params['relation'] ) ) == 'parent'; $this->m_nodeShape = $params['nodeshape']; $this->m_wordWrapLimit = $params['wordwraplimit']; $this->m_nodeLabel = $params['nodelabel']; } protected function getResultText( SMWQueryResult $res, $outputmode ) { if ( !class_exists( 'GraphViz' ) && !class_exists( '\\MediaWiki\\Extension\\GraphViz\\GraphViz' ) ) { wfWarn( 'The SRF Graph printer needs the GraphViz extension to be installed.' ); return ''; } $this->isHTML = true; $graphInput = "digraph $this->m_graphName {"; if ( $this->m_graphSize != '' ) { $graphInput .= "size=\"$this->m_graphSize\";"; } if ( $this->m_nodeShape ) { $graphInput .= "node [shape=$this->m_nodeShape];"; } $graphInput .= "rankdir=$this->m_rankdir;"; while ( $row = $res->getNext() ) { $graphInput .= $this->getGVForItem( $row, $outputmode ); } $graphInput .= "}"; // Calls graphvizParserHook function from MediaWiki GraphViz extension $result = $GLOBALS['wgParser']->recursiveTagParse( "$graphInput" ); if ( $this->m_graphLegend && $this->m_graphColor ) { $arrayCount = 0; $arraySize = count( $this->m_graphColors ); $result .= "

"; foreach ( $this->m_labelArray as $m_label ) { if ( $arrayCount >= $arraySize ) { $arrayCount = 0; } $color = $this->m_graphColors[$arrayCount]; $result .= "$color: $m_label
"; $arrayCount += 1; } $result .= "

"; } return $result; } /** * Returns the GV for a single subject. * * @since 1.5.4 * * @param array $row * @param $outputmode * * @return string */ protected function getGVForItem( array /* of SMWResultArray */ $row, $outputmode ) { $segments = []; // Loop throught all fields of the record. foreach ( $row as $i => $resultArray ) { // Loop throught all the parts of the field value. while ( ( $object = $resultArray->getNextDataValue() ) !== false ) { $propName = $resultArray->getPrintRequest()->getLabel(); $isName = $this->m_nameProperty ? ( $i != 0 && $this->m_nameProperty === $propName ) : $i == 0; if ( $isName ) { $name = $this->getWordWrappedText( $object->getShortText( $outputmode ), $this->m_wordWrapLimit ); } if ( !( $this->m_nameProperty && $i == 0 ) ) { $segments[] = $this->getGVForDataValue( $object, $outputmode, $isName, $name, $propName ); } } } return implode( "\n", $segments ); } /** * Returns the GV for a single SMWDataValue. * * @since 1.5.4 * * @param SMWDataValue $object * @param $outputmode * @param boolean $isName Is this the name that should be used for the node? * @param string $name * @param string $labelName * * @return string */ protected function getGVForDataValue( SMWDataValue $object, $outputmode, $isName, $name, $labelName ) { $graphInput = ''; $nodeLabel = ''; $text = $object->getShortText( $outputmode ); if ( $this->m_graphLink ) { $nodeLinkURL = "[[" . $text . "]]"; } $text = $this->getWordWrappedText( $text, $this->m_wordWrapLimit ); if ( $this->m_nodeLabel === self::NODELABEL_DISPLAYTITLE && $object instanceof SMWWikiPageValue ) { $objectDisplayTitle = $object->getDisplayTitle(); if ( !empty( $objectDisplayTitle )) { $nodeLabel = $this->getWordWrappedText( $objectDisplayTitle, $this->m_wordWrapLimit ); } } if ( $this->m_graphLink ) { if( $nodeLabel === '' ) { $graphInput .= " \"$text\" [URL = \"$nodeLinkURL\"]; "; } else { $graphInput .= " \"$text\" [URL = \"$nodeLinkURL\", label = \"$nodeLabel\"]; "; } } if ( !$isName ) { $graphInput .= $this->m_parentRelation ? " \"$text\" -> \"$name\" " : " \"$name\" -> \"$text\" "; if ( $this->m_graphLabel || $this->m_graphColor ) { $graphInput .= ' ['; if ( array_search( $labelName, $this->m_labelArray, true ) === false ) { $this->m_labelArray[] = $labelName; } $color = $this->m_graphColors[array_search( $labelName, $this->m_labelArray, true )]; if ( $this->m_graphLabel ) { $graphInput .= "label=\"$labelName\""; if ( $this->m_graphColor ) { $graphInput .= ",fontcolor=$color,"; } } if ( $this->m_graphColor ) { $graphInput .= "color=$color"; } $graphInput .= ']'; } $graphInput .= ';'; } return $graphInput; } /** * Returns the word wrapped version of the provided text. * * @since 1.5.4 * * @param string $text * @param integer $charLimit * * @return string */ protected function getWordWrappedText( $text, $charLimit ) { $charLimit = max( [ $charLimit, 1 ] ); $segments = []; while ( strlen( $text ) > $charLimit ) { // Find the last space in the allowed range. $splitPosition = strrpos( substr( $text, 0, $charLimit ), ' ' ); if ( $splitPosition === false ) { // If there is no space (lond word), find the next space. $splitPosition = strpos( $text, ' ' ); if ( $splitPosition === false ) { // If there are no spaces, everything goes on one line. $splitPosition = strlen( $text ) - 1; } } $segments[] = substr( $text, 0, $splitPosition + 1 ); $text = substr( $text, $splitPosition + 1 ); } $segments[] = $text; return implode( '\n', $segments ); } /** * (non-PHPdoc) * @see SMWResultPrinter::getName() */ public function getName() { return wfMessage( 'srf-printername-graph' )->text(); } /** * @see SMWResultPrinter::getParamDefinitions * * @since 1.8 * * @param $definitions array of IParamDefinition * * @return array of IParamDefinition|array */ public function getParamDefinitions( array $definitions ) { $params = parent::getParamDefinitions( $definitions ); $params['graphname'] = [ 'default' => 'QueryResult', 'message' => 'srf-paramdesc-graphname', ]; $params['graphsize'] = [ 'type' => 'string', 'default' => '', 'message' => 'srf-paramdesc-graphsize', 'manipulatedefault' => false, ]; $params['graphlegend'] = [ 'type' => 'boolean', 'default' => false, 'message' => 'srf-paramdesc-graphlegend', ]; $params['graphlabel'] = [ 'type' => 'boolean', 'default' => false, 'message' => 'srf-paramdesc-graphlabel', ]; $params['graphlink'] = [ 'type' => 'boolean', 'default' => false, 'message' => 'srf-paramdesc-graphlink', ]; $params['graphcolor'] = [ 'type' => 'boolean', 'default' => false, 'message' => 'srf-paramdesc-graphcolor', ]; $params['arrowdirection'] = [ 'aliases' => 'rankdir', 'default' => 'LR', 'message' => 'srf-paramdesc-rankdir', 'values' => [ 'LR', 'RL', 'TB', 'BT' ], ]; $params['nodeshape'] = [ 'default' => false, 'message' => 'srf-paramdesc-graph-nodeshape', 'manipulatedefault' => false, 'values' => self::$NODE_SHAPES, ]; $params['relation'] = [ 'default' => 'child', 'message' => 'srf-paramdesc-graph-relation', 'manipulatedefault' => false, 'values' => [ 'parent', 'child' ], ]; $params['nameproperty'] = [ 'default' => false, 'message' => 'srf-paramdesc-graph-nameprop', 'manipulatedefault' => false, ]; $params['wordwraplimit'] = [ 'type' => 'integer', 'default' => 25, 'message' => 'srf-paramdesc-graph-wwl', 'manipulatedefault' => false, ]; $params['nodelabel'] = [ 'default' => '', 'message' => 'srf-paramdesc-nodelabel', 'values' => self::$NODE_LABELS, ]; return $params; } }