1<?php 2namespace dokuwiki\plugin\structjoin\types; 3 4use dokuwiki\plugin\struct\meta\QueryBuilder; 5use dokuwiki\plugin\struct\meta\QueryBuilderWhere; 6use dokuwiki\plugin\struct\meta\StructException; 7use dokuwiki\plugin\struct\types\AbstractBaseType; 8use dokuwiki\plugin\struct\types\Lookup; 9use ReflectionClass; 10 11class Join extends Lookup { 12 13 public function valueEditor($name, $rawvalue, $htmlID) 14 { 15 return "<strong>{$this->config['schema']}.{$this->config['field']}</strong>"; 16 } 17 18 /** 19 * Render using linked field 20 * 21 * @param int|string $value 22 * @param \Doku_Renderer $R 23 * @param string $mode 24 * @return bool 25 */ 26 public function renderValue($value, \Doku_Renderer $R, $mode) { 27 $column = $this->getLookupColumn(); 28 if(!$column) return false; 29 return $column->getType()->renderValue($value, $R, $mode); 30 } 31 32 /** 33 * Render using linked field 34 * 35 * @param \int[]|\string[] $values 36 * @param \Doku_Renderer $R 37 * @param string $mode 38 * @return bool 39 */ 40 public function renderMultiValue($values, \Doku_Renderer $R, $mode) { 41 $column = $this->getLookupColumn(); 42 if(!$column) return false; 43 return $column->getType()->renderMultiValue($values, $R, $mode); 44 } 45 46 /** 47 * @param string $value 48 * @return string 49 */ 50 public function rawValue($value) { 51 return $value; 52 } 53 54 /** 55 * @param string $value 56 * @return string 57 */ 58 public function displayValue($value) { 59 $column = $this->getLookupColumn(); 60 if($column) { 61 return $column->getType()->displayValue($value); 62 } else { 63 return ''; 64 } 65 } 66 67 /** 68 * This is the value to be used as argument to a filter for another column. 69 * 70 * In a sense this is the counterpart to the @see filter() function 71 * 72 * @param string $value 73 * 74 * @return string 75 */ 76 public function compareValue($value) { 77 $column = $this->getLookupColumn(); 78 if($column) { 79 return $column->getType()->rawValue($value); 80 } else { 81 return ''; 82 } 83 } 84 85 /** 86 * Merge with lookup table 87 * 88 * @param QueryBuilder $QB 89 * @param string $tablealias 90 * @param string $colname 91 * @param string $alias 92 * @throws \ReflectionException 93 */ 94 public function select(QueryBuilder $QB, $tablealias, $colname, $alias) { 95 $column = $this->getLookupColumn(); 96 if(!$column) { 97 AbstractBaseType::select($QB, $tablealias, $colname, $alias); 98 return; 99 } 100 101 $rightalias = $this->findRightAlias($QB); 102 if (!$rightalias) { 103 throw new StructException("Select Lookup column to use Join."); 104 } 105 106 $field = $column->getColName(); 107 $column->getType()->select($QB, $rightalias, $field, $alias); 108 } 109 110 /** 111 * @param QueryBuilder $QB 112 * @return false|int|string 113 * @throws \ReflectionException 114 */ 115 protected function findRightAlias(QueryBuilder $QB) { 116 $from = $this->getProtectedPropertyFromQB($QB, 'from'); 117 $leftJoinAliases = array_filter(array_map(function($from) { 118 if (preg_match('/^LEFT OUTER JOIN data_([^\s]*)/', $from, $matches)) { 119 return $matches[1]; 120 } 121 return false; 122 }, $from)); 123 124 return array_search($this->config['schema'], $leftJoinAliases); 125 } 126 127 /** 128 * @param QueryBuilder $QB 129 * @param $property 130 * @return mixed 131 * @throws \ReflectionException 132 */ 133 protected function getProtectedPropertyFromQB(QueryBuilder $QB, $property) { 134 $reflectionClass = new ReflectionClass(QueryBuilder::class); 135 $reflectionProperty = $reflectionClass->getProperty($property); 136 $reflectionProperty->setAccessible(true); 137 138 return $reflectionProperty->getValue($QB); 139 } 140 141 /** 142 * Compare against lookup table 143 * 144 * @param QueryBuilderWhere $add 145 * @param string $tablealias 146 * @param string $colname 147 * @param string $comp 148 * @param string|\string[] $value 149 * @param string $op 150 */ 151 public function filter(QueryBuilderWhere $add, $tablealias, $colname, $comp, $value, $op) { 152 $schema = 'data_' . $this->config['schema']; 153 $column = $this->getLookupColumn(); 154 if(!$column) { 155 AbstractBaseType::filter($add, $tablealias, $colname, $comp, $value, $op); 156 return; 157 } 158 $field = $column->getColName(); 159 160 // compare against lookup field 161 $QB = $add->getQB(); 162 $rightalias = $this->findRightAlias($QB); 163 if (!$rightalias) { 164 throw new StructException("Select Lookup column to use Join."); 165 } 166 $column->getType()->filter($add, $rightalias, $field, $comp, $value, $op); 167 } 168 169 /** 170 * Sort by lookup table 171 * 172 * @param QueryBuilder $QB 173 * @param string $tablealias 174 * @param string $colname 175 * @param string $order 176 * @throws \ReflectionException 177 */ 178 public function sort(QueryBuilder $QB, $tablealias, $colname, $order) { 179 $schema = 'data_' . $this->config['schema']; 180 $column = $this->getLookupColumn(); 181 if(!$column) { 182 AbstractBaseType::sort($QB, $tablealias, $colname, $order); 183 return; 184 } 185 $field = $column->getColName(); 186 187 $rightalias = $this->findRightAlias($QB); 188 if (!$rightalias) { 189 throw new StructException("Select Lookup column to use Join."); 190 } 191 $column->getType()->sort($QB, $rightalias, $field, $order); 192 } 193} 194