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