1<?php
2
3/**
4 * @noinspection PhpUndefinedMethodInspection
5 * @noinspection PhpComposerExtensionStubsInspection
6 */
7
8namespace dokuwiki\plugin\sqlite;
9
10/**
11 * SQLite registered functions
12 */
13class Functions
14{
15    /**
16     * Register all standard functions
17     *
18     * @param \PDO $pdo
19     */
20    public static function register($pdo)
21    {
22        $pdo->sqliteCreateAggregate(
23            'GROUP_CONCAT_DISTINCT',
24            [Functions::class, 'groupConcatStep'],
25            [Functions::class, 'groupConcatFinalize']
26        );
27
28        $pdo->sqliteCreateFunction('GETACCESSLEVEL', [Functions::class, 'getAccessLevel'], 1);
29        $pdo->sqliteCreateFunction('PAGEISHIDDEN', [Functions::class, 'pageIsHidden'], 1);
30        $pdo->sqliteCreateFunction('PAGEEXISTS', [Functions::class, 'pageExists'], 1);
31        $pdo->sqliteCreateFunction('REGEXP', [Functions::class, 'regExp'], 2);
32        $pdo->sqliteCreateFunction('CLEANID', 'cleanID', 1);
33        $pdo->sqliteCreateFunction('RESOLVEPAGE', [Functions::class, 'resolvePage'], 1);
34    }
35
36    /**
37     * Aggregation function for SQLite via PDO
38     *
39     * @link http://devzone.zend.com/article/863-SQLite-Lean-Mean-DB-Machine
40     *
41     * @param null|array &$context (reference) argument where processed data can be stored
42     * @param int $rownumber current row number
43     * @param string $string column value
44     * @param string $separator separator added between values
45     */
46    public static function groupConcatStep(&$context, $rownumber, $string, $separator = ',')
47    {
48        if (is_null($context)) {
49            $context = [
50                'sep' => $separator,
51                'data' => []
52            ];
53        }
54
55        $context['data'][] = $string;
56        return $context;
57    }
58
59    /**
60     * Aggregation function for SQLite via PDO
61     *
62     * @link http://devzone.zend.com/article/863-SQLite-Lean-Mean-DB-Machine
63     *
64     * @param null|array &$context (reference) data as collected in step callback
65     * @param int $rownumber number of rows over which the aggregate was performed.
66     * @return null|string
67     */
68    public static function groupConcatFinalize(&$context, $rownumber)
69    {
70        if (!is_array($context)) {
71            return null;
72        }
73        $context['data'] = array_unique($context['data']);
74        if (empty($context['data'][0])) {
75            return null;
76        }
77        return implode($context['sep'], $context['data']);
78    }
79
80
81    /**
82     * Callback checks the permissions for the current user
83     *
84     * This function is registered as a SQL function named GETACCESSLEVEL
85     *
86     * @param string $pageid page ID (needs to be resolved and cleaned)
87     * @return int permission level
88     */
89    public static function getAccessLevel($pageid)
90    {
91        global $auth;
92        if (!$auth) return AUTH_DELETE;
93
94        static $aclcache = [];
95
96        if (isset($aclcache[$pageid])) {
97            return $aclcache[$pageid];
98        }
99
100        $acl = auth_quickaclcheck($pageid);
101        $aclcache[$pageid] = $acl;
102        return $acl;
103    }
104
105    /**
106     * Check if a page is hidden
107     *
108     * @param string $pageid
109     * @return int 1 if the page is hidden
110     */
111    public static function pageIsHidden($pageid)
112    {
113        static $hiddenCache = [];
114        if (isset($hiddenCache[$pageid])) {
115            return $hiddenCache[$pageid];
116        }
117
118
119        $ishidden = (int) isHiddenPage($pageid);
120        $hiddenCache[$pageid] = $ishidden;
121        return $ishidden;
122    }
123
124    /**
125     * Wrapper around page_exists() with static caching
126     *
127     * This function is registered as a SQL function named PAGEEXISTS
128     *
129     * @param string $pageid
130     * @return int 0|1
131     */
132    public static function pageExists($pageid)
133    {
134        static $cache = [];
135        if (!isset($cache[$pageid])) {
136            $cache[$pageid] = page_exists($pageid);
137        }
138        return (int)$cache[$pageid];
139    }
140
141    /**
142     * Match a regular expression against a value
143     *
144     * This function is registered as a SQL function named REGEXP
145     *
146     * @param string $regexp
147     * @param string $value
148     * @return bool
149     */
150    public static function regExp($regexp, $value)
151    {
152        $regexp = addcslashes($regexp, '/');
153        return (bool)preg_match('/' . $regexp . '/u', $value);
154    }
155
156    /**
157     * Resolves a page ID (relative namespaces, plurals etc)
158     *
159     * This function is registered as a SQL function named RESOLVEPAGE
160     *
161     * @param string $page The page ID to resolve
162     * @param string $context The page ID (not namespace!) to resolve the page with
163     * @return null|string
164     */
165    public static function resolvePage($page, $context)
166    {
167        if (is_null($page)) return null;
168        if (is_null($context)) return cleanID($page);
169
170        $ns = getNS($context);
171        resolve_pageid($ns, $page, $exists);
172        return $page;
173    }
174}
175