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