1<?php 2 3namespace dokuwiki\plugin\struct\meta; 4 5/** 6 * Class AggregationList 7 * 8 * @package dokuwiki\plugin\struct\meta 9 */ 10class AggregationList extends Aggregation 11{ 12 /** @var int number of all results */ 13 protected $resultColumnCount; 14 15 /** @inheritdoc */ 16 public function __construct($id, $mode, \Doku_Renderer $renderer, SearchConfig $searchConfig) 17 { 18 parent::__construct($id, $mode, $renderer, $searchConfig); 19 $this->resultColumnCount = count($this->columns); 20 } 21 22 /** @inheritdoc */ 23 public function render($showNotFound = false) 24 { 25 $this->startScope(); 26 if ($this->result) { 27 $nestedResult = new NestedResult($this->result); 28 $root = $nestedResult->getRoot($this->data['nesting'], $this->data['index']); 29 $this->renderNode($root); 30 } elseif ($showNotFound) { 31 $this->renderer->cdata($this->helper->getLang('none')); 32 } 33 $this->finishScope(); 34 } 35 36 /** 37 * Recursively render the result tree 38 * 39 * @param NestedValue $node 40 * @return void 41 */ 42 protected function renderNode(NestedValue $node) 43 { 44 $self = $node->getValueObject(); // null for root node 45 $children = $node->getChildren(); 46 $results = $node->getResultRows(); 47 48 // all our content is in a listitem, unless we are the root node 49 if ($self) { 50 $this->renderer->listitem_open($node->getDepth() + 1); // levels are 1 based 51 } 52 53 // render own value if available 54 if ($self) { 55 $this->renderer->listcontent_open(); 56 $this->renderListItem([$self], $node->getDepth()); // zero based depth 57 $this->renderer->listcontent_close(); 58 } 59 60 // render children or results as sub-list 61 if ($children || $results) { 62 $this->renderer->listu_open(); 63 64 foreach ($children as $child) { 65 $this->renderNode($child); 66 } 67 68 foreach ($results as $result) { 69 $this->renderer->listitem_open($node->getDepth() + 2); // levels are 1 based, this is one deeper 70 $this->renderer->listcontent_open(); 71 $this->renderListItem($result, $node->getDepth() + 1); // zero based depth, one deeper 72 $this->renderer->listcontent_close(); 73 $this->renderer->listitem_close(); 74 } 75 76 $this->renderer->listu_close(); 77 } 78 79 // close listitem if opened 80 if ($self) { 81 $this->renderer->listitem_close(); 82 } 83 } 84 85 /** 86 * Adds additional info to document and renderer in XHTML mode 87 * 88 * @see finishScope() 89 */ 90 protected function startScope() 91 { 92 // wrapping div 93 if ($this->mode != 'xhtml') return; 94 $this->renderer->doc .= "<div class=\"structaggregation listaggregation\">"; 95 } 96 97 /** 98 * Closes anything opened in startScope() 99 * 100 * @see startScope() 101 */ 102 protected function finishScope() 103 { 104 // wrapping div 105 if ($this->mode != 'xhtml') return; 106 $this->renderer->doc .= '</div>'; 107 } 108 109 110 /** 111 * Render the content of a single list item 112 * 113 * @param Value[] $resultrow 114 * @param int $depth The current nesting depth (zero based) 115 */ 116 protected function renderListItem($resultrow, $depth) 117 { 118 $sepbyheaders = $this->searchConfig->getConf()['sepbyheaders']; 119 $headers = $this->searchConfig->getConf()['headers']; 120 121 foreach ($resultrow as $index => $value) { 122 if ($value->isEmpty()) continue; 123 $column = $index + $depth; // the resultrow is shifted by the nesting depth 124 if ($sepbyheaders && !empty($headers[$column])) { 125 $header = $headers[$column]; 126 } else { 127 $header = ''; 128 } 129 130 if ($this->mode === 'xhtml') { 131 $this->renderValueXHTML($value, $header); 132 } else { 133 $this->renderValueGeneric($value, $header); 134 } 135 } 136 } 137 138 /** 139 * Render the given Value in a XHTML renderer 140 * @param Value $value 141 * @param string $header 142 * @return void 143 */ 144 protected function renderValueXHTML($value, $header) 145 { 146 $attributes = [ 147 'data-struct-column' => strtolower($value->getColumn()->getFullQualifiedLabel()), 148 'data-struct-type' => strtolower($value->getColumn()->getType()->getClass()), 149 'class' => 'li', // default dokuwiki content wrapper 150 ]; 151 152 $this->renderer->doc .= sprintf('<div %s>', buildAttributes($attributes)); // wrapper 153 if ($header !== '') { 154 $this->renderer->doc .= sprintf('<span class="struct_header">%s</span> ', hsc($header)); 155 } 156 $this->renderer->doc .= '<div class="struct_value">'; 157 $value->render($this->renderer, $this->mode); 158 $this->renderer->doc .= '</div>'; 159 $this->renderer->doc .= '</div> '; // wrapper 160 } 161 162 /** 163 * Render the given Value in any non-XHTML renderer 164 * @param Value $value 165 * @param string $header 166 * @return void 167 */ 168 protected function renderValueGeneric($value, $header) 169 { 170 $this->renderer->listcontent_open(); 171 if ($header !== '') $this->renderer->cdata($header . ' '); 172 $value->render($this->renderer, $this->mode); 173 $this->renderer->listcontent_close(); 174 } 175} 176