15511bd5bSAndreas Gohr<?php 25511bd5bSAndreas Gohr 3ba766201SAndreas Gohrnamespace dokuwiki\plugin\struct\meta; 45511bd5bSAndreas Gohr 55511bd5bSAndreas Gohr/** 65511bd5bSAndreas Gohr * Class SearchConfig 75511bd5bSAndreas Gohr * 85511bd5bSAndreas Gohr * The same as @see Search but can be initialized by a configuration array 95511bd5bSAndreas Gohr * 10ba766201SAndreas Gohr * @package dokuwiki\plugin\struct\meta 115511bd5bSAndreas Gohr */ 12d6d97f60SAnna Dabrowskaclass SearchConfig extends Search 13d6d97f60SAnna Dabrowska{ 1416b7d914SAndreas Gohr /** @var int default aggregation caching (depends on last struct save) */ 15d6d97f60SAnna Dabrowska public static $CACHE_DEFAULT = 1; 1616b7d914SAndreas Gohr /** @var int caching depends on current user */ 17d6d97f60SAnna Dabrowska public static $CACHE_USER = 2; 1816b7d914SAndreas Gohr /** @var int caching depends on current date */ 19d6d97f60SAnna Dabrowska public static $CACHE_DATE = 4; 2016b7d914SAndreas Gohr 21668e4f8eSAndreas Gohr /** 22668e4f8eSAndreas Gohr * @var array hold the configuration as parsed and extended by dynamic params 23668e4f8eSAndreas Gohr */ 241a07b696SMichael Große protected $config; 251a07b696SMichael Große 26668e4f8eSAndreas Gohr /** 27668e4f8eSAndreas Gohr * @var SearchConfigParameters manages dynamic parameters 28668e4f8eSAndreas Gohr */ 2900f6af48SAndreas Gohr protected $dynamicParameters; 3000f6af48SAndreas Gohr 315511bd5bSAndreas Gohr /** 3216b7d914SAndreas Gohr * @var int the cache flag to use (binary flags) 3316b7d914SAndreas Gohr */ 3416b7d914SAndreas Gohr protected $cacheFlag; 3516b7d914SAndreas Gohr 3616b7d914SAndreas Gohr /** 375511bd5bSAndreas Gohr * SearchConfig constructor. 3800f6af48SAndreas Gohr * @param array $config The parsed configuration for this search 39b3a9db22SAndreas Gohr * @param bool $dynamic Should dynamic parameters be applied? 405511bd5bSAndreas Gohr */ 41b3a9db22SAndreas Gohr public function __construct($config, $dynamic = true) 42d6d97f60SAnna Dabrowska { 435511bd5bSAndreas Gohr parent::__construct(); 445511bd5bSAndreas Gohr 453ad292a8SAndreas Gohr // setup schemas and columns 460215a637SAndreas Gohr if (!empty($config['schemas'])) foreach ($config['schemas'] as $schema) { 473ad292a8SAndreas Gohr $this->addSchema($schema[0], $schema[1]); 483ad292a8SAndreas Gohr } 490215a637SAndreas Gohr if (!empty($config['cols'])) foreach ($config['cols'] as $col) { 503ad292a8SAndreas Gohr $this->addColumn($col); 513ad292a8SAndreas Gohr } 523ad292a8SAndreas Gohr 5316b7d914SAndreas Gohr // cache flag setting 5416b7d914SAndreas Gohr $this->cacheFlag = self::$CACHE_DEFAULT; 5516b7d914SAndreas Gohr if (!empty($config['filters'])) $this->cacheFlag = $this->determineCacheFlag($config['filters']); 5616b7d914SAndreas Gohr 5700f6af48SAndreas Gohr // configure search from configuration 5800f6af48SAndreas Gohr if (!empty($config['filter'])) foreach ($config['filter'] as $filter) { 595625b985SAndreas Gohr $this->addFilter($filter[0], $this->applyFilterVars($filter[2]), $filter[1], $filter[3]); 605511bd5bSAndreas Gohr } 6100f6af48SAndreas Gohr 6200f6af48SAndreas Gohr if (!empty($config['sort'])) foreach ($config['sort'] as $sort) { 63aa124708SAndreas Gohr $this->addSort($sort[0], $sort[1]); 641a07b696SMichael Große } 651a07b696SMichael Große 661a07b696SMichael Große if (!empty($config['limit'])) { 671a07b696SMichael Große $this->setLimit($config['limit']); 681a07b696SMichael Große } 6900f6af48SAndreas Gohr 7000f6af48SAndreas Gohr if (!empty($config['offset'])) { 71d2a8ce05SPaweł Czochański $this->setOffset($config['offset']); 7200f6af48SAndreas Gohr } 73668e4f8eSAndreas Gohr 74b3a9db22SAndreas Gohr // prepare dynamic parameters 75b3a9db22SAndreas Gohr $this->dynamicParameters = new SearchConfigParameters($this); 76b3a9db22SAndreas Gohr if ($dynamic) { 77b3a9db22SAndreas Gohr $this->dynamicParameters->apply(); 78b3a9db22SAndreas Gohr } 79b3a9db22SAndreas Gohr 80668e4f8eSAndreas Gohr $this->config = $config; 811a07b696SMichael Große } 825511bd5bSAndreas Gohr 8300f6af48SAndreas Gohr /** 8416b7d914SAndreas Gohr * Set the cache flag accordingly to the set filter placeholders 8516b7d914SAndreas Gohr * 8616b7d914SAndreas Gohr * @param array $filters 8716b7d914SAndreas Gohr * @return int 8816b7d914SAndreas Gohr */ 89d6d97f60SAnna Dabrowska protected function determineCacheFlag($filters) 90d6d97f60SAnna Dabrowska { 9116b7d914SAndreas Gohr $flags = self::$CACHE_DEFAULT; 9216b7d914SAndreas Gohr 9316b7d914SAndreas Gohr foreach ($filters as $filter) { 9416b7d914SAndreas Gohr if (is_array($filter)) $filter = $filter[2]; // this is the format we get fro the config parser 9516b7d914SAndreas Gohr 9616b7d914SAndreas Gohr if (strpos($filter, '$USER$') !== false) { 9716b7d914SAndreas Gohr $flags |= self::$CACHE_USER; 9816b7d914SAndreas Gohr } elseif (strpos($filter, '$TODAY$') !== false) { 9916b7d914SAndreas Gohr $flags |= self::$CACHE_DATE; 10016b7d914SAndreas Gohr } 10116b7d914SAndreas Gohr } 10216b7d914SAndreas Gohr 10316b7d914SAndreas Gohr return $flags; 10416b7d914SAndreas Gohr } 10516b7d914SAndreas Gohr 10616b7d914SAndreas Gohr /** 1075625b985SAndreas Gohr * Replaces placeholders in the given filter value by the proper value 1085625b985SAndreas Gohr * 1095625b985SAndreas Gohr * @param string $filter 11053528ecfSAndreas Gohr * @return string|string[] Result may be an array when a multi column placeholder is used 1115625b985SAndreas Gohr */ 112d6d97f60SAnna Dabrowska protected function applyFilterVars($filter) 113d6d97f60SAnna Dabrowska { 114ecf2cba2SAndreas Gohr global $INPUT; 11506fee43aSMichael Grosse global $INFO; 1161ca21e17SAnna Dabrowska if (!isset($INFO['id'])) { 117*7fe2cdf2SAndreas Gohr $INFO['id'] = ''; 11834ea6e10SAnna Dabrowska } 1195625b985SAndreas Gohr 1205625b985SAndreas Gohr // apply inexpensive filters first 1215625b985SAndreas Gohr $filter = str_replace( 122*7fe2cdf2SAndreas Gohr [ 123*7fe2cdf2SAndreas Gohr '$ID$', 124*7fe2cdf2SAndreas Gohr '$NS$', 125*7fe2cdf2SAndreas Gohr '$PAGE$', 126*7fe2cdf2SAndreas Gohr '$USER$', 127*7fe2cdf2SAndreas Gohr '$TODAY$' 128*7fe2cdf2SAndreas Gohr ], 129*7fe2cdf2SAndreas Gohr [ 130*7fe2cdf2SAndreas Gohr $INFO['id'], 131*7fe2cdf2SAndreas Gohr getNS($INFO['id']), 132*7fe2cdf2SAndreas Gohr noNS($INFO['id']), 133*7fe2cdf2SAndreas Gohr $INPUT->server->str('REMOTE_USER'), 134*7fe2cdf2SAndreas Gohr date('Y-m-d') 135*7fe2cdf2SAndreas Gohr ], 1365625b985SAndreas Gohr $filter 1375625b985SAndreas Gohr ); 1385625b985SAndreas Gohr 13953528ecfSAndreas Gohr // apply struct column placeholder (we support only one!) 140888559e1Ssaggi-dw // or apply date formula, given as strtotime 14153528ecfSAndreas Gohr if (preg_match('/^(.*?)(?:\$STRUCT\.(.*?)\$)(.*?)$/', $filter, $match)) { 142e983bcdaSSzymon Olewniczak $filter = $this->applyFilterVarsStruct($match); 143e983bcdaSSzymon Olewniczak } elseif (preg_match('/^(.*?)(?:\$USER\.(.*?)\$)(.*?)$/', $filter, $match)) { 144e983bcdaSSzymon Olewniczak $filter = $this->applyFilterVarsUser($match); 145888559e1Ssaggi-dw } elseif (preg_match('/^(.*?)(?:\$DATE\((.*?)\)\$?)(.*?)$/', $filter, $match)) { 1467f610bd5Ssaggi-dw $toparse = $match[2]; 147888559e1Ssaggi-dw if ($toparse == '') { 148888559e1Ssaggi-dw $toparse = 'now'; 149888559e1Ssaggi-dw } 150888559e1Ssaggi-dw $timestamp = strtotime($toparse); 151888559e1Ssaggi-dw if ($timestamp === false) { 1527f610bd5Ssaggi-dw throw new StructException('datefilter', hsc($toparse)); 1537f610bd5Ssaggi-dw } else { 1547f610bd5Ssaggi-dw $filter = str_replace($filter, date('Y-m-d', $timestamp), $filter); 1557f610bd5Ssaggi-dw } 156e983bcdaSSzymon Olewniczak } 157e983bcdaSSzymon Olewniczak 158e983bcdaSSzymon Olewniczak return $filter; 159e983bcdaSSzymon Olewniczak } 160e983bcdaSSzymon Olewniczak 161e983bcdaSSzymon Olewniczak /** 162e983bcdaSSzymon Olewniczak * Replaces struct placeholders in the given filter value by the proper value 163e983bcdaSSzymon Olewniczak * 164e983bcdaSSzymon Olewniczak * @param string $match 165e983bcdaSSzymon Olewniczak * @return string|string[] Result may be an array when a multi column placeholder is used 166e983bcdaSSzymon Olewniczak */ 167d6d97f60SAnna Dabrowska protected function applyFilterVarsStruct($match) 168d6d97f60SAnna Dabrowska { 169e983bcdaSSzymon Olewniczak global $INFO; 170e983bcdaSSzymon Olewniczak 17153528ecfSAndreas Gohr $key = $match[2]; 172d19ba4b1SAndreas Gohr 1730280da9aSFrieder Schrempf // we try to resolve the key via the assigned schemas first, otherwise take it literally 1740280da9aSFrieder Schrempf $column = $this->findColumn($key, true); 1755625b985SAndreas Gohr if ($column) { 1765625b985SAndreas Gohr $label = $column->getLabel(); 1775625b985SAndreas Gohr $table = $column->getTable(); 178aec9051bSAndreas Gohr } else { 179*7fe2cdf2SAndreas Gohr [$table, $label] = sexplode('.', $key, 2, ''); 180aec9051bSAndreas Gohr } 181aec9051bSAndreas Gohr 182aec9051bSAndreas Gohr // get the data from the current page 183aec9051bSAndreas Gohr if ($table && $label) { 1844cd5cc28SAnna Dabrowska $schemaData = AccessTable::getPageAccess($table, $INFO['id']); 1857717c082SMichael Große $data = $schemaData->getData(); 18634db2096SMichael Große if (!isset($data[$label])) { 187e87d1e74SMichael Große throw new StructException("column not in table", $label, $table); 18834db2096SMichael Große } 1897717c082SMichael Große $value = $data[$label]->getCompareValue(); 190c75f25cfSAndreas Gohr 1917234bfb1Ssplitbrain if (is_array($value) && $value === []) { 192c75f25cfSAndreas Gohr $value = ''; 193c75f25cfSAndreas Gohr } 1945625b985SAndreas Gohr } else { 1955625b985SAndreas Gohr $value = ''; 1965625b985SAndreas Gohr } 1978b8243b2SAndreas Gohr 19853528ecfSAndreas Gohr // apply any pre and postfixes, even when multi value 19953528ecfSAndreas Gohr if (is_array($value)) { 2007234bfb1Ssplitbrain $filter = []; 20153528ecfSAndreas Gohr foreach ($value as $item) { 20253528ecfSAndreas Gohr $filter[] = $match[1] . $item . $match[3]; 20353528ecfSAndreas Gohr } 20453528ecfSAndreas Gohr } else { 20553528ecfSAndreas Gohr $filter = $match[1] . $value . $match[3]; 20653528ecfSAndreas Gohr } 207e983bcdaSSzymon Olewniczak 208e983bcdaSSzymon Olewniczak return $filter; 209e983bcdaSSzymon Olewniczak } 210e983bcdaSSzymon Olewniczak 211e983bcdaSSzymon Olewniczak /** 212e983bcdaSSzymon Olewniczak * Replaces user placeholders in the given filter value by the proper value 213e983bcdaSSzymon Olewniczak * 214e983bcdaSSzymon Olewniczak * @param string $match 215e983bcdaSSzymon Olewniczak * @return string|string[] String for name and mail, array for grps 216e983bcdaSSzymon Olewniczak */ 217d6d97f60SAnna Dabrowska protected function applyFilterVarsUser($match) 218d6d97f60SAnna Dabrowska { 219e983bcdaSSzymon Olewniczak global $INFO; 220e983bcdaSSzymon Olewniczak 221daa4b09dSSzymon Olewniczak $key = strtolower($match[2]); 222daa4b09dSSzymon Olewniczak 2237234bfb1Ssplitbrain if (!in_array($key, ['name', 'mail', 'grps'])) { 224daa4b09dSSzymon Olewniczak throw new StructException('"%s" is not a valid USER key', $key); 225daa4b09dSSzymon Olewniczak } 226daa4b09dSSzymon Olewniczak 227daa4b09dSSzymon Olewniczak if (empty($INFO['userinfo'])) { 228daa4b09dSSzymon Olewniczak $filter = ''; 229daa4b09dSSzymon Olewniczak } else { 230daa4b09dSSzymon Olewniczak $filter = $INFO['userinfo'][$key]; 231daa4b09dSSzymon Olewniczak } 2325625b985SAndreas Gohr 2335625b985SAndreas Gohr return $filter; 2345625b985SAndreas Gohr } 2355625b985SAndreas Gohr 2365625b985SAndreas Gohr /** 23716b7d914SAndreas Gohr * @return int cacheflag for this search 23816b7d914SAndreas Gohr */ 239d6d97f60SAnna Dabrowska public function getCacheFlag() 240d6d97f60SAnna Dabrowska { 24116b7d914SAndreas Gohr return $this->cacheFlag; 24216b7d914SAndreas Gohr } 24316b7d914SAndreas Gohr 24416b7d914SAndreas Gohr /** 245fd9c77d3SAndreas Gohr * Access the dynamic parameters of this search 24600f6af48SAndreas Gohr * 247668e4f8eSAndreas Gohr * Note: This call returns a clone of the parameters as they were initialized 24800f6af48SAndreas Gohr * 24900f6af48SAndreas Gohr * @return SearchConfigParameters 25000f6af48SAndreas Gohr */ 251d6d97f60SAnna Dabrowska public function getDynamicParameters() 252d6d97f60SAnna Dabrowska { 25300f6af48SAndreas Gohr return clone $this->dynamicParameters; 2545511bd5bSAndreas Gohr } 2555511bd5bSAndreas Gohr 25600f6af48SAndreas Gohr /** 257fdf37115SAndreas Gohr * Get the config this search was initialized with 258fdf37115SAndreas Gohr * 259fdf37115SAndreas Gohr * Note that the search may have been modified by dynamic parameters or additional member calls 260fdf37115SAndreas Gohr * 261fdf37115SAndreas Gohr * @return array 26200f6af48SAndreas Gohr */ 263d6d97f60SAnna Dabrowska public function getConf() 264d6d97f60SAnna Dabrowska { 2651a07b696SMichael Große return $this->config; 2661a07b696SMichael Große } 2675511bd5bSAndreas Gohr} 268