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