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