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