xref: /plugin/structpublish/meta/Assignments.php (revision 910e7e15ab7eacafbaa096c48916ba3bb1c5258f)
1*910e7e15SAnna Dabrowska<?php
2*910e7e15SAnna Dabrowska
3*910e7e15SAnna Dabrowskanamespace dokuwiki\plugin\structpublish\meta;
4*910e7e15SAnna Dabrowska
5*910e7e15SAnna Dabrowska/**
6*910e7e15SAnna Dabrowska * Class Assignments
7*910e7e15SAnna Dabrowska *
8*910e7e15SAnna Dabrowska * Manages the assignment of users to pages and namespaces
9*910e7e15SAnna Dabrowska * This is a singleton. Assignment data is only loaded once per request.
10*910e7e15SAnna Dabrowska *
11*910e7e15SAnna Dabrowska * @see \dokuwiki\plugin\struct\meta\Assignments
12*910e7e15SAnna Dabrowska */
13*910e7e15SAnna Dabrowskaclass Assignments
14*910e7e15SAnna Dabrowska{
15*910e7e15SAnna Dabrowska    /** @var \helper_plugin_sqlite|null */
16*910e7e15SAnna Dabrowska    protected $sqlite;
17*910e7e15SAnna Dabrowska
18*910e7e15SAnna Dabrowska    /** @var  array All the assignments patterns */
19*910e7e15SAnna Dabrowska    protected $patterns;
20*910e7e15SAnna Dabrowska
21*910e7e15SAnna Dabrowska    /** @var Assignments */
22*910e7e15SAnna Dabrowska    protected static $instance = null;
23*910e7e15SAnna Dabrowska
24*910e7e15SAnna Dabrowska    /**
25*910e7e15SAnna Dabrowska     * Get the singleton instance of the Assignments
26*910e7e15SAnna Dabrowska     *
27*910e7e15SAnna Dabrowska     * @param bool $forcereload create a new instace to reload the assignment data
28*910e7e15SAnna Dabrowska     * @return Assignments
29*910e7e15SAnna Dabrowska     */
30*910e7e15SAnna Dabrowska    public static function getInstance($forcereload = false)
31*910e7e15SAnna Dabrowska    {
32*910e7e15SAnna Dabrowska        if (is_null(self::$instance) or $forcereload) {
33*910e7e15SAnna Dabrowska            $class = get_called_class();
34*910e7e15SAnna Dabrowska            self::$instance = new $class();
35*910e7e15SAnna Dabrowska        }
36*910e7e15SAnna Dabrowska        return self::$instance;
37*910e7e15SAnna Dabrowska    }
38*910e7e15SAnna Dabrowska
39*910e7e15SAnna Dabrowska    /**
40*910e7e15SAnna Dabrowska     * Assignments constructor.
41*910e7e15SAnna Dabrowska     *
42*910e7e15SAnna Dabrowska     * Not public. Use Assignments::getInstance() instead
43*910e7e15SAnna Dabrowska     */
44*910e7e15SAnna Dabrowska    protected function __construct()
45*910e7e15SAnna Dabrowska    {
46*910e7e15SAnna Dabrowska        /** @var \helper_plugin_structpublish_db $helper */
47*910e7e15SAnna Dabrowska        $helper = plugin_load('helper', 'struct_db');
48*910e7e15SAnna Dabrowska        $this->sqlite = $helper->getDB();
49*910e7e15SAnna Dabrowska
50*910e7e15SAnna Dabrowska        $this->loadPatterns();
51*910e7e15SAnna Dabrowska    }
52*910e7e15SAnna Dabrowska    /**
53*910e7e15SAnna Dabrowska     * Load existing assignment patterns
54*910e7e15SAnna Dabrowska     */
55*910e7e15SAnna Dabrowska    protected function loadPatterns()
56*910e7e15SAnna Dabrowska    {
57*910e7e15SAnna Dabrowska        $sql = 'SELECT * FROM structpublish_assignments_patterns ORDER BY pattern';
58*910e7e15SAnna Dabrowska        $res = $this->sqlite->query($sql);
59*910e7e15SAnna Dabrowska        $this->patterns = $this->sqlite->res2arr($res);
60*910e7e15SAnna Dabrowska        $this->sqlite->res_close($res);
61*910e7e15SAnna Dabrowska    }
62*910e7e15SAnna Dabrowska
63*910e7e15SAnna Dabrowska    /**
64*910e7e15SAnna Dabrowska     * Add a new assignment pattern to the pattern table
65*910e7e15SAnna Dabrowska     *
66*910e7e15SAnna Dabrowska     * @param string $pattern
67*910e7e15SAnna Dabrowska     * @param string $user
68*910e7e15SAnna Dabrowska     * @param string $status
69*910e7e15SAnna Dabrowska     * @return bool
70*910e7e15SAnna Dabrowska     */
71*910e7e15SAnna Dabrowska    public function addPattern($pattern, $user, $status)
72*910e7e15SAnna Dabrowska    {
73*910e7e15SAnna Dabrowska        // add the pattern
74*910e7e15SAnna Dabrowska        $sql = 'REPLACE INTO structpublish_assignments_patterns (pattern, user, status) VALUES (?,?,?)';
75*910e7e15SAnna Dabrowska        $ok = (bool)$this->sqlite->query($sql, [$pattern, $user, $status]);
76*910e7e15SAnna Dabrowska
77*910e7e15SAnna Dabrowska        // reload patterns
78*910e7e15SAnna Dabrowska        $this->loadPatterns();
79*910e7e15SAnna Dabrowska
80*910e7e15SAnna Dabrowska        // FIXME how to update / propagate assignments?
81*910e7e15SAnna Dabrowska
82*910e7e15SAnna Dabrowska        return $ok;
83*910e7e15SAnna Dabrowska    }
84*910e7e15SAnna Dabrowska
85*910e7e15SAnna Dabrowska    /**
86*910e7e15SAnna Dabrowska     * Remove an existing assignment pattern from the pattern table
87*910e7e15SAnna Dabrowska     *
88*910e7e15SAnna Dabrowska     * @param string $pattern
89*910e7e15SAnna Dabrowska     * @param string $user
90*910e7e15SAnna Dabrowska     * @param string $status
91*910e7e15SAnna Dabrowska     * @return bool
92*910e7e15SAnna Dabrowska     */
93*910e7e15SAnna Dabrowska    public function removePattern($pattern, $user, $status)
94*910e7e15SAnna Dabrowska    {
95*910e7e15SAnna Dabrowska        // remove the pattern
96*910e7e15SAnna Dabrowska        $sql = 'DELETE FROM structpublish_assignments_patterns WHERE pattern = ? AND user = ? AND status = ?';
97*910e7e15SAnna Dabrowska        $ok = (bool)$this->sqlite->query($sql, [$pattern, $user, $status]);
98*910e7e15SAnna Dabrowska
99*910e7e15SAnna Dabrowska        // reload patterns
100*910e7e15SAnna Dabrowska        $this->loadPatterns();
101*910e7e15SAnna Dabrowska
102*910e7e15SAnna Dabrowska        // fetch possibly affected pages
103*910e7e15SAnna Dabrowska        $sql = 'SELECT pid FROM structpublish_assignments WHERE user = ? AND status = ?';
104*910e7e15SAnna Dabrowska        $res = $this->sqlite->query($sql, [$user, $status]);
105*910e7e15SAnna Dabrowska        $pagerows = $this->sqlite->res2arr($res);
106*910e7e15SAnna Dabrowska        $this->sqlite->res_close($res);
107*910e7e15SAnna Dabrowska
108*910e7e15SAnna Dabrowska        // reevalute the pages and unassign when needed
109*910e7e15SAnna Dabrowska        foreach ($pagerows as $row) {
110*910e7e15SAnna Dabrowska            $rules = $this->getPageAssignments($row['pid'], true);
111*910e7e15SAnna Dabrowska            // remove assignments matching the rule
112*910e7e15SAnna Dabrowska            foreach ($rules as $status => $users) {
113*910e7e15SAnna Dabrowska                foreach ($users as $user) {
114*910e7e15SAnna Dabrowska                    $this->deassignPage($row['pid'], $user, $status);
115*910e7e15SAnna Dabrowska                }
116*910e7e15SAnna Dabrowska            }
117*910e7e15SAnna Dabrowska        }
118*910e7e15SAnna Dabrowska
119*910e7e15SAnna Dabrowska        return $ok;
120*910e7e15SAnna Dabrowska    }
121*910e7e15SAnna Dabrowska
122*910e7e15SAnna Dabrowska    /**
123*910e7e15SAnna Dabrowska     * Updates all assignments of a given page against the current patterns
124*910e7e15SAnna Dabrowska     *
125*910e7e15SAnna Dabrowska     * @param string $pid
126*910e7e15SAnna Dabrowska     */
127*910e7e15SAnna Dabrowska    public function updatePageAssignments($pid)
128*910e7e15SAnna Dabrowska    {
129*910e7e15SAnna Dabrowska        // reload patterns
130*910e7e15SAnna Dabrowska        $this->loadPatterns();
131*910e7e15SAnna Dabrowska        $rules = $this->getPageAssignments($pid, true);
132*910e7e15SAnna Dabrowska
133*910e7e15SAnna Dabrowska        foreach ($rules as $status => $users) {
134*910e7e15SAnna Dabrowska            foreach ($users as $user) {
135*910e7e15SAnna Dabrowska                $this->assignPage($pid, $user, $status);
136*910e7e15SAnna Dabrowska            }
137*910e7e15SAnna Dabrowska        }
138*910e7e15SAnna Dabrowska
139*910e7e15SAnna Dabrowska        // fetch known pages
140*910e7e15SAnna Dabrowska        /** @var \helper_plugin_structpublish_db $helper */
141*910e7e15SAnna Dabrowska        $helper = plugin_load('helper', 'structpublish_db');
142*910e7e15SAnna Dabrowska        $pages = $helper->getPages($pid);
143*910e7e15SAnna Dabrowska
144*910e7e15SAnna Dabrowska        // FIXME reevalute existing assignments
145*910e7e15SAnna Dabrowska    }
146*910e7e15SAnna Dabrowska
147*910e7e15SAnna Dabrowska    /**
148*910e7e15SAnna Dabrowska     * Clear all patterns - deassigns all pages
149*910e7e15SAnna Dabrowska     *
150*910e7e15SAnna Dabrowska     * This is mostly useful for testing and not used in the interface currently
151*910e7e15SAnna Dabrowska     *
152*910e7e15SAnna Dabrowska     * @param bool $full fully delete all previous assignments
153*910e7e15SAnna Dabrowska     * @return bool
154*910e7e15SAnna Dabrowska     */
155*910e7e15SAnna Dabrowska    public function clear($full = false)
156*910e7e15SAnna Dabrowska    {
157*910e7e15SAnna Dabrowska        $sql = 'DELETE FROM structpublish_assignments_patterns';
158*910e7e15SAnna Dabrowska        $ok = (bool)$this->sqlite->query($sql);
159*910e7e15SAnna Dabrowska
160*910e7e15SAnna Dabrowska        if ($full) {
161*910e7e15SAnna Dabrowska            $sql = 'DELETE FROM structpublish_assignments';
162*910e7e15SAnna Dabrowska        } else {
163*910e7e15SAnna Dabrowska            $sql = 'UPDATE structpublish_assignments SET assigned = 0';
164*910e7e15SAnna Dabrowska        }
165*910e7e15SAnna Dabrowska        $ok = $ok && (bool)$this->sqlite->query($sql);
166*910e7e15SAnna Dabrowska
167*910e7e15SAnna Dabrowska        // reload patterns
168*910e7e15SAnna Dabrowska        $this->loadPatterns();
169*910e7e15SAnna Dabrowska
170*910e7e15SAnna Dabrowska        return $ok;
171*910e7e15SAnna Dabrowska    }
172*910e7e15SAnna Dabrowska
173*910e7e15SAnna Dabrowska    /**
174*910e7e15SAnna Dabrowska     * Add page to assignments
175*910e7e15SAnna Dabrowska     *
176*910e7e15SAnna Dabrowska     * @param string $page
177*910e7e15SAnna Dabrowska     * @param string $user
178*910e7e15SAnna Dabrowska     * @param string $status
179*910e7e15SAnna Dabrowska     * @return bool
180*910e7e15SAnna Dabrowska     */
181*910e7e15SAnna Dabrowska    public function assignPage($page, $user = null, $status = null)
182*910e7e15SAnna Dabrowska    {
183*910e7e15SAnna Dabrowska        $sql = 'REPLACE INTO structpublish_assignments (pid, user, status, assigned) VALUES (?, ?, ?, 1)';
184*910e7e15SAnna Dabrowska        return (bool)$this->sqlite->query($sql, [$page, $user, $status]);
185*910e7e15SAnna Dabrowska    }
186*910e7e15SAnna Dabrowska
187*910e7e15SAnna Dabrowska    /**
188*910e7e15SAnna Dabrowska     * Remove page from assignments
189*910e7e15SAnna Dabrowska     *
190*910e7e15SAnna Dabrowska     * @param string $page
191*910e7e15SAnna Dabrowska     * @param string $user
192*910e7e15SAnna Dabrowska     * @return bool
193*910e7e15SAnna Dabrowska     */
194*910e7e15SAnna Dabrowska    public function deassignPage($page, $user, $status)
195*910e7e15SAnna Dabrowska    {
196*910e7e15SAnna Dabrowska        $sql = 'REPLACE INTO structpublish_assignments (pid, user, status, assigned) VALUES (?, ?, ?, 0)';
197*910e7e15SAnna Dabrowska        return (bool)$this->sqlite->query($sql, [$page, $user, $status]);
198*910e7e15SAnna Dabrowska    }
199*910e7e15SAnna Dabrowska
200*910e7e15SAnna Dabrowska    /**
201*910e7e15SAnna Dabrowska     * Get the whole pattern table
202*910e7e15SAnna Dabrowska     *
203*910e7e15SAnna Dabrowska     * @return array
204*910e7e15SAnna Dabrowska     */
205*910e7e15SAnna Dabrowska    public function getAllPatterns()
206*910e7e15SAnna Dabrowska    {
207*910e7e15SAnna Dabrowska        return $this->patterns;
208*910e7e15SAnna Dabrowska    }
209*910e7e15SAnna Dabrowska
210*910e7e15SAnna Dabrowska    /**
211*910e7e15SAnna Dabrowska     * Returns a list of users per status assigned to the given page
212*910e7e15SAnna Dabrowska     *
213*910e7e15SAnna Dabrowska     * @param string $page
214*910e7e15SAnna Dabrowska     * @param bool $checkpatterns Should the current patterns be re-evaluated?
215*910e7e15SAnna Dabrowska     * @return array users assigned
216*910e7e15SAnna Dabrowska     */
217*910e7e15SAnna Dabrowska    public function getPageAssignments($page, $checkpatterns = true)
218*910e7e15SAnna Dabrowska    {
219*910e7e15SAnna Dabrowska        $rules = [];
220*910e7e15SAnna Dabrowska        $page = cleanID($page);
221*910e7e15SAnna Dabrowska
222*910e7e15SAnna Dabrowska        if ($checkpatterns) {
223*910e7e15SAnna Dabrowska            $helper = plugin_load('helper', 'structpublish_assignments');
224*910e7e15SAnna Dabrowska            // evaluate patterns
225*910e7e15SAnna Dabrowska            $pns = ':' . getNS($page) . ':';
226*910e7e15SAnna Dabrowska            foreach ($this->patterns as $row) {
227*910e7e15SAnna Dabrowska                if ($helper->matchPagePattern($row['pattern'], $page, $pns)) {
228*910e7e15SAnna Dabrowska                    $rules[$row['status']][] = $row['user'];
229*910e7e15SAnna Dabrowska                }
230*910e7e15SAnna Dabrowska            }
231*910e7e15SAnna Dabrowska        } else {
232*910e7e15SAnna Dabrowska            // just select
233*910e7e15SAnna Dabrowska            $sql = 'SELECT user, status FROM structpublish_assignments WHERE pid = ? AND assigned = 1';
234*910e7e15SAnna Dabrowska            $res = $this->sqlite->query($sql, [$page]);
235*910e7e15SAnna Dabrowska            $list = $this->sqlite->res2arr($res);
236*910e7e15SAnna Dabrowska            $this->sqlite->res_close($res);
237*910e7e15SAnna Dabrowska            foreach ($list as $row) {
238*910e7e15SAnna Dabrowska                $rules[$row['status']][] = $row['user'];
239*910e7e15SAnna Dabrowska            }
240*910e7e15SAnna Dabrowska        }
241*910e7e15SAnna Dabrowska
242*910e7e15SAnna Dabrowska        return $rules;
243*910e7e15SAnna Dabrowska    }
244*910e7e15SAnna Dabrowska
245*910e7e15SAnna Dabrowska    /**
246*910e7e15SAnna Dabrowska     * Get the pages known to struct and their assignment state
247*910e7e15SAnna Dabrowska     *
248*910e7e15SAnna Dabrowska     * @param bool $assignedonly limit results to currently assigned only
249*910e7e15SAnna Dabrowska     * @return array
250*910e7e15SAnna Dabrowska     */
251*910e7e15SAnna Dabrowska    public function getPages($assignedOnly = false)
252*910e7e15SAnna Dabrowska    {
253*910e7e15SAnna Dabrowska        $sql = 'SELECT pid, user, status, assigned FROM structpublish_assignments WHERE 1=1';
254*910e7e15SAnna Dabrowska
255*910e7e15SAnna Dabrowska        $opts = array();
256*910e7e15SAnna Dabrowska
257*910e7e15SAnna Dabrowska        if ($assignedOnly) {
258*910e7e15SAnna Dabrowska            $sql .= ' AND assigned = 1';
259*910e7e15SAnna Dabrowska        }
260*910e7e15SAnna Dabrowska
261*910e7e15SAnna Dabrowska        $sql .= ' ORDER BY pid, user, status';
262*910e7e15SAnna Dabrowska
263*910e7e15SAnna Dabrowska        $res = $this->sqlite->query($sql, $opts);
264*910e7e15SAnna Dabrowska        $list = $this->sqlite->res2arr($res);
265*910e7e15SAnna Dabrowska        $this->sqlite->res_close($res);
266*910e7e15SAnna Dabrowska
267*910e7e15SAnna Dabrowska        $result = array();
268*910e7e15SAnna Dabrowska        foreach ($list as $row) {
269*910e7e15SAnna Dabrowska            $pid = $row['pid'];
270*910e7e15SAnna Dabrowska            $user = $row['user'];
271*910e7e15SAnna Dabrowska            $status = $row['status'];
272*910e7e15SAnna Dabrowska            if (!isset($result[$pid])) $result[$pid] = array();
273*910e7e15SAnna Dabrowska            $result[$pid][$user][$status] = (bool)$row['assigned'];
274*910e7e15SAnna Dabrowska        }
275*910e7e15SAnna Dabrowska
276*910e7e15SAnna Dabrowska        return $result;
277*910e7e15SAnna Dabrowska    }
278*910e7e15SAnna Dabrowska}
279