1<?php 2namespace dokuwiki\plugin\struct\types; 3 4use dokuwiki\plugin\struct\meta\Column; 5use dokuwiki\plugin\struct\meta\QueryBuilder; 6use dokuwiki\plugin\struct\meta\Schema; 7use dokuwiki\plugin\struct\meta\Search; 8use dokuwiki\plugin\struct\meta\StructException; 9use dokuwiki\plugin\struct\meta\Value; 10 11class Lookup extends Dropdown { 12 13 protected $config = array( 14 'schema' => '', 15 'field' => '' 16 ); 17 18 /** 19 * Dropdown constructor. 20 * 21 * @param array|null $config 22 * @param string $label 23 * @param bool $ismulti 24 * @param int $tid 25 */ 26 public function __construct($config = null, $label = '', $ismulti = false, $tid = 0) { 27 parent::__construct($config, $label, $ismulti, $tid); 28 $this->config['schema'] = Schema::cleanTableName($this->config['schema']); 29 } 30 31 /** 32 * @throws StructException 33 * @return Column|false 34 */ 35 protected function getLookupColumn() { 36 global $conf; 37 38 static $column = null; 39 if($column !== null) return $column; 40 41 $schema = new Schema($this->config['schema']); 42 if(!$schema->getId()) { 43 // schema does not exist 44 msg(sprintf('Schema %s does not exist', $this->config['schema']), -1); 45 return false; 46 } 47 48 // apply language replacement 49 $field = str_replace('$LANG', $conf['lang'], $this->config['field']); 50 $column = $schema->findColumn($field); 51 if(!$column) { 52 $field = str_replace('$LANG', 'en', $this->config['field']); // fallback to en 53 $column = $schema->findColumn($field); 54 } 55 if(!$column) { 56 // field does not exist 57 msg(sprintf('Field %s.%s does not exist', $this->config['schema'], $this->config['field']), -1); 58 return false; 59 } 60 61 if($column->isMulti()) { 62 // field is multi 63 msg(sprintf('Field %s.%s is a multi field - not allowed for lookup', $this->config['schema'], $this->config['field']), -1); 64 return false; 65 } 66 67 return $column; 68 } 69 70 /** 71 * Creates the options array 72 * 73 * @return array 74 */ 75 protected function getOptions() { 76 $schema = $this->config['schema']; 77 $column = $this->getLookupColumn(); 78 if(!$column) return array(); 79 $field = $column->getLabel(); 80 81 $search = new Search(); 82 $search->addSchema($schema); 83 $search->addColumn($field); 84 $search->addSort($field); 85 $result = $search->execute(); 86 $pids = $search->getPids(); 87 $len = count($result); 88 89 /** @var Value[][] $result */ 90 $options = array('' => ''); 91 for($i = 0; $i < $len; $i++) { 92 $options[$pids[$i]] = $result[$i][0]->getDisplayValue(); 93 } 94 return $options; 95 } 96 97 /** 98 * Render using linked field 99 * 100 * @param int|string $value 101 * @param \Doku_Renderer $R 102 * @param string $mode 103 * @return bool 104 */ 105 public function renderValue($value, \Doku_Renderer $R, $mode) { 106 list(, $value) = json_decode($value); 107 $column = $this->getLookupColumn(); 108 if(!$column) return false; 109 return $column->getType()->renderValue($value, $R, $mode); 110 } 111 112 /** 113 * Render using linked field 114 * 115 * @param \int[]|\string[] $values 116 * @param \Doku_Renderer $R 117 * @param string $mode 118 * @return bool 119 */ 120 public function renderMultiValue($values, \Doku_Renderer $R, $mode) { 121 $values = array_map( 122 function ($val) { 123 list(, $val) = json_decode($val); 124 return $val; 125 }, $values 126 ); 127 $column = $this->getLookupColumn(); 128 if(!$column) return false; 129 return $column->getType()->renderMultiValue($values, $R, $mode); 130 } 131 132 /** 133 * @param string $value 134 * @return string 135 */ 136 public function rawValue($value) { 137 list($value) = json_decode($value); 138 return $value; 139 } 140 141 /** 142 * @param string $value 143 * @return string 144 */ 145 public function displayValue($value) { 146 list(, $value) = json_decode($value); 147 $column = $this->getLookupColumn(); 148 if($column) { 149 return $column->getType()->displayValue($value); 150 } else { 151 return ''; 152 } 153 } 154 155 /** 156 * Merge with lookup table 157 * 158 * @param QueryBuilder $QB 159 * @param string $tablealias 160 * @param string $colname 161 * @param string $alias 162 */ 163 public function select(QueryBuilder $QB, $tablealias, $colname, $alias) { 164 $schema = 'data_' . $this->config['schema']; 165 $column = $this->getLookupColumn(); 166 if(!$column) { 167 parent::select($QB, $tablealias, $colname, $alias); 168 return; 169 } 170 171 $field = $column->getColName(); 172 $rightalias = $QB->generateTableAlias(); 173 $QB->addLeftJoin( 174 $tablealias, $schema, $rightalias, 175 "$tablealias.$colname = $rightalias.pid AND $rightalias.latest = 1" 176 ); 177 $column->getType()->select($QB, $rightalias, $field, $alias); 178 $sql = $QB->getSelectStatement($alias); 179 $QB->addSelectStatement("STRUCT_JSON($tablealias.$colname, $sql)", $alias); 180 } 181 182 /** 183 * Compare against lookup table 184 * 185 * @param QueryBuilder $QB 186 * @param string $tablealias 187 * @param string $colname 188 * @param string $comp 189 * @param string|\string[] $value 190 * @param string $op 191 */ 192 public function filter(QueryBuilder $QB, $tablealias, $colname, $comp, $value, $op) { 193 $schema = 'data_' . $this->config['schema']; 194 $column = $this->getLookupColumn(); 195 if(!$column) { 196 parent::filter($QB, $tablealias, $colname, $comp, $value, $op); 197 return; 198 } 199 $field = $column->getColName(); 200 201 // compare against lookup field 202 $rightalias = $QB->generateTableAlias(); 203 $QB->addLeftJoin( 204 $tablealias, $schema, $rightalias, 205 "$tablealias.$colname = $rightalias.pid AND $rightalias.latest = 1" 206 ); 207 $column->getType()->filter($QB, $rightalias, $field, $comp, $value, $op); 208 } 209 210 /** 211 * Sort by lookup table 212 * 213 * @param QueryBuilder $QB 214 * @param string $tablealias 215 * @param string $colname 216 * @param string $order 217 */ 218 public function sort(QueryBuilder $QB, $tablealias, $colname, $order) { 219 $schema = 'data_' . $this->config['schema']; 220 $column = $this->getLookupColumn(); 221 if(!$column) { 222 parent::sort($QB, $tablealias, $colname, $order); 223 return; 224 } 225 $field = $column->getColName(); 226 227 $rightalias = $QB->generateTableAlias(); 228 $QB->addLeftJoin( 229 $tablealias, $schema, $rightalias, 230 "$tablealias.$colname = $rightalias.pid AND $rightalias.latest = 1" 231 ); 232 $column->getType()->sort($QB, $rightalias, $field, $order); 233 } 234 235} 236