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