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