xref: /plugin/struct/meta/SearchConfig.php (revision 7f803aa873894c400484b80e8b543a49fdf1f9d5)
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