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