1<?php 2 3namespace dokuwiki\plugin\struct\meta; 4 5/** 6 * Class SearchConfig 7 * 8 * The same as @see Search but can be initialized by a configuration array 9 * 10 * @package dokuwiki\plugin\struct\meta 11 */ 12class SearchConfig extends Search { 13 14 /** @var int default aggregation caching (depends on last struct save) */ 15 static public $CACHE_DEFAULT = 1; 16 /** @var int caching depends on current user */ 17 static public $CACHE_USER = 2; 18 /** @var int caching depends on current date */ 19 static public $CACHE_DATE = 4; 20 21 /** 22 * @var array hold the configuration as parsed and extended by dynamic params 23 */ 24 protected $config; 25 26 /** 27 * @var SearchConfigParameters manages dynamic parameters 28 */ 29 protected $dynamicParameters; 30 31 /** 32 * @var int the cache flag to use (binary flags) 33 */ 34 protected $cacheFlag; 35 36 /** 37 * SearchConfig constructor. 38 * @param array $config The parsed configuration for this search 39 */ 40 public function __construct($config) { 41 parent::__construct(); 42 43 // setup schemas and columns 44 if(!empty($config['schemas'])) foreach($config['schemas'] as $schema) { 45 $this->addSchema($schema[0], $schema[1]); 46 } 47 if(!empty($config['cols'])) foreach($config['cols'] as $col) { 48 $this->addColumn($col); 49 } 50 51 // cache flag setting 52 $this->cacheFlag = self::$CACHE_DEFAULT; 53 if(!empty($config['filters'])) $this->cacheFlag = $this->determineCacheFlag($config['filters']); 54 55 // apply dynamic paramters 56 $this->dynamicParameters = new SearchConfigParameters($this); 57 $config = $this->dynamicParameters->updateConfig($config); 58 59 // configure search from configuration 60 if(!empty($config['filter'])) foreach($config['filter'] as $filter) { 61 $this->addFilter($filter[0], $this->applyFilterVars($filter[2]), $filter[1], $filter[3]); 62 } 63 64 if(!empty($config['sort'])) foreach($config['sort'] as $sort) { 65 $this->addSort($sort[0], $sort[1]); 66 } 67 68 if(!empty($config['limit'])) { 69 $this->setLimit($config['limit']); 70 } 71 72 if(!empty($config['offset'])) { 73 $this->setOffset($config['offset']); 74 } 75 76 $this->config = $config; 77 } 78 79 /** 80 * Set the cache flag accordingly to the set filter placeholders 81 * 82 * @param array $filters 83 * @return int 84 */ 85 protected function determineCacheFlag($filters) { 86 $flags = self::$CACHE_DEFAULT; 87 88 foreach($filters as $filter) { 89 if(is_array($filter)) $filter = $filter[2]; // this is the format we get fro the config parser 90 91 if(strpos($filter, '$USER$') !== false) { 92 $flags |= self::$CACHE_USER; 93 } else if(strpos($filter, '$TODAY$') !== false) { 94 $flags |= self::$CACHE_DATE; 95 } 96 } 97 98 return $flags; 99 } 100 101 /** 102 * Replaces placeholders in the given filter value by the proper value 103 * 104 * @param string $filter 105 * @return string|string[] Result may be an array when a multi column placeholder is used 106 */ 107 protected function applyFilterVars($filter) { 108 global $INFO; 109 110 // apply inexpensive filters first 111 $filter = str_replace( 112 array( 113 '$ID$', 114 '$NS$', 115 '$PAGE$', 116 '$USER$', 117 '$TODAY$' 118 ), 119 array( 120 $INFO['id'], 121 getNS($INFO['id']), 122 noNS($INFO['id']), 123 isset($_SERVER['REMOTE_USER']) ? $_SERVER['REMOTE_USER'] : '', 124 date('Y-m-d') 125 ), 126 $filter 127 ); 128 129 // apply struct column placeholder (we support only one!) 130 if(preg_match('/^(.*?)(?:\$STRUCT\.(.*?)\$)(.*?)$/', $filter, $match)) { 131 $filter = $this->applyFilterVarsStruct($match); 132 } elseif(preg_match('/^(.*?)(?:\$USER\.(.*?)\$)(.*?)$/', $filter, $match)) { 133 $filter = $this->applyFilterVarsUser($match); 134 } 135 136 return $filter; 137 } 138 139 /** 140 * Replaces struct placeholders in the given filter value by the proper value 141 * 142 * @param string $match 143 * @return string|string[] Result may be an array when a multi column placeholder is used 144 */ 145 protected function applyFilterVarsStruct($match) { 146 global $INFO; 147 148 $key = $match[2]; 149 150 // we try to resolve the key via current schema aliases first, otherwise take it literally 151 $column = $this->findColumn($key); 152 if($column) { 153 $label = $column->getLabel(); 154 $table = $column->getTable(); 155 } else { 156 list($table, $label) = explode('.', $key); 157 } 158 159 // get the data from the current page 160 if($table && $label) { 161 $schemaData = AccessTable::byTableName($table, $INFO['id'], time()); 162 $data = $schemaData->getData(); 163 if (!isset($data[$label])) { 164 throw new StructException("column not in table", $label, $table); 165 } 166 $value = $data[$label]->getCompareValue(); 167 168 if(is_array($value) && !count($value)) { 169 $value = ''; 170 } 171 } else { 172 $value = ''; 173 } 174 175 // apply any pre and postfixes, even when multi value 176 if(is_array($value)) { 177 $filter = array(); 178 foreach($value as $item) { 179 $filter[] = $match[1] . $item . $match[3]; 180 } 181 } else { 182 $filter = $match[1] . $value . $match[3]; 183 } 184 185 return $filter; 186 } 187 188 /** 189 * Replaces user placeholders in the given filter value by the proper value 190 * 191 * @param string $match 192 * @return string|string[] String for name and mail, array for grps 193 */ 194 protected function applyFilterVarsUser($match) { 195 global $INFO; 196 197 $key = strtolower($match[2]); 198 199 if (!in_array($key, array('name', 'mail', 'grps'))) { 200 throw new StructException('"%s" is not a valid USER key', $key); 201 } 202 203 if (empty($INFO['userinfo'])) { 204 $filter = ''; 205 } else { 206 $filter = $INFO['userinfo'][$key]; 207 } 208 209 return $filter; 210 } 211 212 /** 213 * @return int cacheflag for this search 214 */ 215 public function getCacheFlag() { 216 return $this->cacheFlag; 217 } 218 219 /** 220 * Access the dynamic paramters of this search 221 * 222 * Note: This call returns a clone of the parameters as they were initialized 223 * 224 * @return SearchConfigParameters 225 */ 226 public function getDynamicParameters() { 227 return clone $this->dynamicParameters; 228 } 229 230 /** 231 * @return array the current config 232 */ 233 public function getConf() { 234 return $this->config; 235 } 236 237} 238