Issues (1844)

Security Analysis    not enabled

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  Header Injection
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

class/MembershipHandler.php (22 issues)

1
<?php declare(strict_types=1);
2
3
namespace XoopsModules\Xhelp;
4
5
/*
6
 * You may not change or alter any portion of this comment or credits
7
 * of supporting developers from this source code or any supporting source code
8
 * which is considered copyrighted (c) material of the original comment or credit authors.
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13
 */
14
15
/**
16
 * @copyright    {@link https://xoops.org/ XOOPS Project}
17
 * @license      {@link https://www.gnu.org/licenses/gpl-2.0.html GNU GPL 2 or later}
18
 * @author       Brian Wahoff <[email protected]>
19
 * @author       Eric Juden <[email protected]>
20
 * @author       XOOPS Development Team
21
 */
22
23
/**
24
 * Class MembershipHandler
25
 */
26
class MembershipHandler
27
{
28
    private $db;
29
    private $staffHandler;
30
    private $departmentHandler;
31
    private $ticketHandler;
32
33
//    private const TABLE = 'xhelp_mailevent';
34
//    private const ENTITY = MailEvent::class;
35
//    private const ENTITYNAME = 'MailEvent';
36
//    private const KEYNAME = 'id';
37
//    private const IDENTIFIER = 'mbox_id';
38
39
    /**
40
     * Constructor
41
     *
42
     * @param \XoopsMySQLDatabase|null $db reference to a xoopsDB object
43
     */
44
    public function __construct(\XoopsMySQLDatabase $db = null)
45
    {
46
        $this->db = $db;
47
        $this->helper = Helper::getInstance();
0 ignored issues
show
Bug Best Practice introduced by
The property helper does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
48
//        parent::__construct($db, static::TABLE, static::ENTITY, static::KEYNAME, static::IDENTIFIER);
49
50
        /** @var \XoopsModules\Xhelp\StaffHandler $this- >staffHandler */
51
        $this->staffHandler = $this->helper->getHandler('Staff');
52
        /** @var \XoopsModules\Xhelp\DepartmentHandler $this- >departmentHandler */
53
        $this->departmentHandler = $this->helper->getHandler('Department');
54
        /** @var \XoopsModules\Xhelp\TicketHandler $this- >ticketHandler */
55
        $this->ticketHandler = $this->helper->getHandler('Ticket');
56
    }
57
58
    /**
59
     * count objects matching a criteria
60
     *
61
     * @param \CriteriaElement|\CriteriaCompo|null $criteria {@link \CriteriaElement} to match
62
     * @return int    count of objects
63
     */
64
    public function getCount($criteria = null): int
65
    {
66
        $sql = \sprintf('SELECT COUNT(*) FROM `%s` s INNER JOIN %s j ON s.uid = j.uid', $this->db->prefix('xhelp_staff'), $this->db->prefix('xhelp_jstaffdept'));
0 ignored issues
show
The method prefix() does not exist on null. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

66
        $sql = \sprintf('SELECT COUNT(*) FROM `%s` s INNER JOIN %s j ON s.uid = j.uid', $this->db->/** @scrutinizer ignore-call */ prefix('xhelp_staff'), $this->db->prefix('xhelp_jstaffdept'));

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
67
        if (($criteria instanceof \CriteriaCompo) || ($criteria instanceof \Criteria)) {
68
            $sql .= ' ' . $criteria->renderWhere();
69
        }
70
        if (!$result = $this->db->query($sql)) {
71
            return 0;
72
        }
73
        [$count] = $this->db->fetchRow($result);
0 ignored issues
show
It seems like $result can also be of type true; however, parameter $result of XoopsMySQLDatabase::fetchRow() does only seem to accept mysqli_result, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

73
        [$count] = $this->db->fetchRow(/** @scrutinizer ignore-type */ $result);
Loading history...
74
75
        return (int)$count;
76
    }
77
78
    /**
79
     * Get all departments a staff user is assigned to
80
     *
81
     * @param int  $uid staff user id
82
     * @param bool $id_as_key
83
     * @return array array of <a href='psi_element://Department'>Department</a> objects
84
     *                  objects
85
     */
86
    public function &membershipByStaff(int $uid, bool $id_as_key = false): array
87
    {
88
        $uid = $uid;
89
        $sql = \sprintf('SELECT d.* FROM `%s` d INNER JOIN %s j ON d.id = j.department WHERE j.uid = %u', $this->db->prefix('xhelp_departments'), $this->db->prefix('xhelp_jstaffdept'), $uid);
90
91
        $ret = $this->db->query($sql);
92
        $arr = [];
93
94
        while (false !== ($temp = $this->db->fetchArray($ret))) {
0 ignored issues
show
It seems like $ret can also be of type boolean; however, parameter $result of XoopsMySQLDatabase::fetchArray() does only seem to accept mysqli_result, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

94
        while (false !== ($temp = $this->db->fetchArray(/** @scrutinizer ignore-type */ $ret))) {
Loading history...
95
            $dept = $this->departmentHandler->create();
96
            $dept->assignVars($temp);
97
            if ($id_as_key) {
98
                $arr[$dept->getVar('id')] = $dept;
99
            } else {
100
                $arr[] = $dept;
101
            }
102
            unset($temp);
103
        }
104
105
        return $arr;
106
    }
107
108
    /**
109
     * @param int $uid
110
     * @return array
111
     */
112
    public function &getVisibleDepartments(int $uid): array
113
    {
114
        $uid         = $uid;
115
        $xoopsModule = Utility::getModule();
116
        $module_id   = $xoopsModule->getVar('mid');
117
        /** @var \XoopsMemberHandler $memberHandler */
118
        $memberHandler = \xoops_getHandler('member');
119
        $groups        = $memberHandler->getGroupsByUser($uid);
120
        $group_string  = '(' . \implode(',', \array_values($groups)) . ')';
121
122
        $sql = \sprintf("SELECT d.* FROM `%s` d INNER JOIN %s g ON d.id = g.gperm_itemid WHERE g.gperm_name = '%s' AND g.gperm_modid = '%s' AND g.gperm_groupid IN %s", $this->db->prefix('xhelp_departments'), $this->db->prefix('group_permission'), \_XHELP_GROUP_PERM_DEPT, $module_id, $group_string);
0 ignored issues
show
It seems like $module_id can also be of type array and array; however, parameter $values of sprintf() does only seem to accept double|integer|string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

122
        $sql = \sprintf("SELECT d.* FROM `%s` d INNER JOIN %s g ON d.id = g.gperm_itemid WHERE g.gperm_name = '%s' AND g.gperm_modid = '%s' AND g.gperm_groupid IN %s", $this->db->prefix('xhelp_departments'), $this->db->prefix('group_permission'), \_XHELP_GROUP_PERM_DEPT, /** @scrutinizer ignore-type */ $module_id, $group_string);
Loading history...
123
        $ret = $this->db->query($sql);
124
        $arr = [];
125
126
        while (false !== ($temp = $this->db->fetchArray($ret))) {
0 ignored issues
show
It seems like $ret can also be of type boolean; however, parameter $result of XoopsMySQLDatabase::fetchArray() does only seem to accept mysqli_result, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

126
        while (false !== ($temp = $this->db->fetchArray(/** @scrutinizer ignore-type */ $ret))) {
Loading history...
127
            $dept = $this->departmentHandler->create();
128
            $dept->assignVars($temp);
129
            $arr[$dept->getVar('id')] = $dept;
130
            unset($temp);
131
        }
132
133
        return $arr;
134
    }
135
136
    /**
137
     * @param int $uid
138
     * @param int $deptid
139
     * @return bool
140
     */
141
    public function isStaffMember(int $uid, int $deptid): bool
142
    {
143
        $sql = \sprintf('SELECT COUNT(*) AS MemberCount FROM `%s` WHERE uid = %u AND department = %u', $this->db->prefix('xhelp_jstaffdept'), $uid, $deptid);
144
        $ret = $this->db->query($sql);
145
        [$memberCount] = $this->db->fetchRow($ret);
0 ignored issues
show
It seems like $ret can also be of type boolean; however, parameter $result of XoopsMySQLDatabase::fetchRow() does only seem to accept mysqli_result, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

145
        [$memberCount] = $this->db->fetchRow(/** @scrutinizer ignore-type */ $ret);
Loading history...
146
147
        return ($memberCount > 0);
148
    }
149
150
    /**
151
     * Get all staff members assigned to a department
152
     *
153
     * @param int|array $deptid department id
154
     * @param int       $limit
155
     * @param int       $start
156
     * @return array array of <a href='psi_element://Staff'>Staff</a> objects
157
     *                          objects
158
     */
159
    public function &membershipByDept($deptid, int $limit = 0, int $start = 0): array
160
    {
161
        $limit   = $limit;
162
        $start   = $start;
163
        $a_depts = [];
164
165
        if (\is_array($deptid)) {
166
            foreach ($deptid as $dept) {
167
                if (\is_object($dept)) {
168
                    $a_depts[] = $dept->getVar('id');
169
                } else {
170
                    $a_depts[] = (int)$dept;
171
                }
172
            }
173
        } else {
174
            if (\is_object($deptid)) {
0 ignored issues
show
The condition is_object($deptid) is always false.
Loading history...
175
                $a_depts[] = $deptid->getVar('id');
176
            } else {
177
                $a_depts[] = (int)$deptid;
178
            }
179
        }
180
        if (1 == \count($a_depts)) {
181
            $sql = \sprintf('SELECT s.* FROM `%s` s INNER JOIN %s j ON s.uid = j.uid WHERE j.department = %u', $this->db->prefix('xhelp_staff'), $this->db->prefix('xhelp_jstaffdept'), $a_depts[0]);
182
        } else {
183
            $uids = $this->uidsInDepts($a_depts);
184
            $sql  = \sprintf('SELECT s.* FROM `%s` s WHERE s.uid IN (%s)', $this->db->prefix('xhelp_staff'), \implode(',', $uids));
185
        }
186
187
        $ret = $this->db->query($sql, $limit, $start);
188
        $arr = [];
189
190
        while (false !== ($temp = $this->db->fetchArray($ret))) {
0 ignored issues
show
It seems like $ret can also be of type boolean; however, parameter $result of XoopsMySQLDatabase::fetchArray() does only seem to accept mysqli_result, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

190
        while (false !== ($temp = $this->db->fetchArray(/** @scrutinizer ignore-type */ $ret))) {
Loading history...
191
            $staff = $this->staffHandler->create();
192
            $staff->assignVars($temp);
193
            $arr[$staff->getVar('uid')] = $staff;
194
            unset($temp);
195
        }
196
197
        return $arr;
198
    }
199
200
    /**
201
     * @param array|int $deptid
202
     * @param int       $limit
203
     * @param int       $start
204
     * @return array
205
     */
206
    public function &xoopsUsersByDept($deptid, int $limit = 0, int $start = 0): array
207
    {
208
        $limit       = $limit;
209
        $start       = $start;
210
        $a_depts     = [];
211
        $userHandler = \xoops_getHandler('user');
212
213
        if (\is_array($deptid)) {
214
            foreach ($deptid as $dept) {
215
                if (\is_object($dept)) {
216
                    $a_depts[] = $dept->getVar('id');
217
                } else {
218
                    $a_depts[] = (int)$dept;
219
                }
220
            }
221
        } else {
222
            if (\is_object($deptid)) {
0 ignored issues
show
The condition is_object($deptid) is always false.
Loading history...
223
                $a_depts[] = $deptid->getVar('id');
224
            } else {
225
                $a_depts[] = (int)$deptid;
226
            }
227
        }
228
        if (1 == \count($a_depts)) {
229
            $sql = \sprintf('SELECT u.* FROM `%s` u INNER JOIN %s j ON u.uid = j.uid WHERE j.department = %u', $this->db->prefix('users'), $this->db->prefix('xhelp_jstaffdept'), $a_depts[0]);
230
        } else {
231
            $uids = $this->uidsInDepts($a_depts);
232
            $sql  = \sprintf('SELECT u.* FROM `%s` u WHERE u.uid IN (%s)', $this->db->prefix('users'), \implode(',', $uids));
233
        }
234
235
        $ret = $this->db->query($sql, $limit, $start);
236
        $arr = [];
237
238
        while (false !== ($temp = $this->db->fetchArray($ret))) {
0 ignored issues
show
It seems like $ret can also be of type boolean; however, parameter $result of XoopsMySQLDatabase::fetchArray() does only seem to accept mysqli_result, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

238
        while (false !== ($temp = $this->db->fetchArray(/** @scrutinizer ignore-type */ $ret))) {
Loading history...
239
            $staff = $userHandler->create();
240
            $staff->assignVars($temp);
241
            $arr[$staff->getVar('uid')] = $staff;
242
            unset($temp);
243
        }
244
245
        return $arr;
246
    }
247
248
    /**
249
     * @param array $staffDepts
250
     * @return bool
251
     */
252
    public function inAllDepts(array $staffDepts): bool
253
    {
254
        $helper = Helper::getInstance();
255
        /** @var \XoopsModules\Xhelp\DepartmentHandler $departmentHandler */
256
        $departmentHandler = $helper->getHandler('Department');
257
        $allDepts          = $departmentHandler->getCount();
258
259
        $numDepts = 0;
260
        foreach ($staffDepts as $dept) {
261
            ++$numDepts;
262
        }
263
264
        if ($allDepts != $numDepts) {
265
            return false;
266
        }
267
268
        return true;
269
    }
270
271
    /**
272
     * Add the given staff member(s) to the given department
273
     *
274
     * @param mixed $staff  single or array of uids or {@link Staff} objects
275
     * @param int   $deptid Department ID
276
     * @return bool  True if successful, False if not
277
     */
278
    public function addStaffToDept($staff, int $deptid): bool
279
    {
280
        $ret = false;
281
        if (!\is_array($staff)) {
282
            return $this->addMembership($staff, $deptid);
283
        }
284
285
        foreach ($staff as $member) {
286
            $ret = $this->addMembership($member, $deptid);
287
            if (!$ret) {
288
                exit;
0 ignored issues
show
Bug Best Practice introduced by
In this branch, the function will implicitly return null which is incompatible with the type-hinted return boolean. Consider adding a return statement or allowing null as return value.

For hinted functions/methods where all return statements with the correct type are only reachable via conditions, ?null? gets implicitly returned which may be incompatible with the hinted type. Let?s take a look at an example:

interface ReturnsInt {
    public function returnsIntHinted(): int;
}

class MyClass implements ReturnsInt {
    public function returnsIntHinted(): int
    {
        if (foo()) {
            return 123;
        }
        // here: null is implicitly returned
    }
}
Loading history...
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
289
            }
290
        }
291
292
        return $ret;
293
    }
294
295
    /**
296
     * Add the given department(s) to the given user
297
     *
298
     * @param mixed $dept single or array of department id's or {@link Department} objects
299
     * @param int   $uid  User ID
300
     * @return bool  True if successful, False if not
301
     */
302
    public function addDeptToStaff($dept, int $uid): bool
303
    {
304
        $ret = false;
305
        if (!\is_array($dept)) {
306
            return $this->addMembership($uid, $dept);
307
        }
308
309
        foreach ($dept as $member) {
310
            $ret = $this->addMembership($uid, $member);
311
            if (!$ret) {
312
                break;
313
            }
314
        }
315
316
        return $ret;
317
    }
318
319
    /**
320
     * Remove the given staff member(s) to the given department
321
     *
322
     * @param mixed $staff  single or array of uids or {@link Staff} objects
323
     * @param int   $deptid Department ID
324
     * @return bool  True if successful, False if not
325
     */
326
    public function removeStaffFromDept($staff, int $deptid): bool
327
    {
328
        $ret = false;
329
        if (!\is_array($staff)) {
330
            return $this->removeMembership($staff, $deptid);
331
        }
332
333
        foreach ($staff as $member) {
334
            $ret = $this->removeMembership($member, $deptid);
335
            if (!$ret) {
336
                exit;
0 ignored issues
show
Bug Best Practice introduced by
In this branch, the function will implicitly return null which is incompatible with the type-hinted return boolean. Consider adding a return statement or allowing null as return value.

For hinted functions/methods where all return statements with the correct type are only reachable via conditions, ?null? gets implicitly returned which may be incompatible with the hinted type. Let?s take a look at an example:

interface ReturnsInt {
    public function returnsIntHinted(): int;
}

class MyClass implements ReturnsInt {
    public function returnsIntHinted(): int
    {
        if (foo()) {
            return 123;
        }
        // here: null is implicitly returned
    }
}
Loading history...
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
337
            }
338
        }
339
340
        return $ret;
341
    }
342
343
    /**
344
     * Remove the given user from the given department(s)
345
     *
346
     * @param mixed $dept single or array of department id's or {@link Department} objects
347
     * @param int   $uid  User ID
348
     * @return bool  True if successful, False if not
349
     */
350
    public function removeDeptFromStaff($dept, int $uid): bool
351
    {
352
        $ret = false;
353
        if (!\is_array($dept)) {
354
            return $this->removeMembership($uid, $dept);
355
        }
356
357
        foreach ($dept as $member) {
358
            $ret = $this->removeMembership($uid, $member);
359
            if (!$ret) {
360
                exit;
0 ignored issues
show
Bug Best Practice introduced by
In this branch, the function will implicitly return null which is incompatible with the type-hinted return boolean. Consider adding a return statement or allowing null as return value.

For hinted functions/methods where all return statements with the correct type are only reachable via conditions, ?null? gets implicitly returned which may be incompatible with the hinted type. Let?s take a look at an example:

interface ReturnsInt {
    public function returnsIntHinted(): int;
}

class MyClass implements ReturnsInt {
    public function returnsIntHinted(): int
    {
        if (foo()) {
            return 123;
        }
        // here: null is implicitly returned
    }
}
Loading history...
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
361
            }
362
        }
363
364
        return $ret;
365
    }
366
367
    /**
368
     * Remove the specified user from all departments
369
     *
370
     * @param int $uid User ID
371
     * @return bool True if successful, False if not
372
     */
373
    public function clearStaffMembership(int $uid): bool
374
    {
375
        $sql = \sprintf('DELETE FROM `%s` WHERE uid=%u', $this->db->prefix('xhelp_jstaffdept'), $uid);
376
377
        return $this->db->query($sql);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->db->query($sql) could return the type mysqli_result which is incompatible with the type-hinted return boolean. Consider adding an additional type-check to rule them out.
Loading history...
378
    }
379
380
    /**
381
     * Remove all users from the specified department
382
     *
383
     * @param int $deptid Department ID
384
     * @return bool True if successful, False if not
385
     */
386
    public function clearDeptMembership(int $deptid): bool
387
    {
388
        $sql = \sprintf('DELETE FROM `%s` WHERE department=%u', $this->db->prefix('xhelp_jstaffdept'), $deptid);
389
390
        return $this->db->query($sql);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->db->query($sql) could return the type mysqli_result which is incompatible with the type-hinted return boolean. Consider adding an additional type-check to rule them out.
Loading history...
391
    }
392
393
    /**
394
     * Add a staff member to a department
395
     *
396
     * @param mixed $staff uid or {@link Staff} object
397
     * @param mixed $dept  department id or {@link Department} object
398
     * @return bool  True if successful, False if not
399
     */
400
    public function addMembership($staff, $dept): bool
401
    {
402
        $deptid  = 0;
403
        $staffid = 0;
404
405
        if (\is_object($staff)) {
406
            $staffid = $staff->getVar('uid');
407
        } else {
408
            $staffid = (int)$staff;
409
        }
410
411
        if (\is_object($dept)) {
412
            $deptid = $dept->getVar('id');
413
        } else {
414
            $deptid = (int)$dept;
415
        }
416
417
        return $this->addJoinerRecord($staffid, $deptid);
418
    }
419
420
    /**
421
     * Add a record to the joiner database table
422
     *
423
     * @param int $staffid user id
424
     * @param int $deptid  department id
425
     * @return bool True if successful, False if not
426
     */
427
    private function addJoinerRecord(int $staffid, int $deptid): bool
428
    {
429
        $sql = \sprintf('INSERT INTO `%s` (uid, department) VALUES(%u, %u)', $this->db->prefix('xhelp_jstaffdept'), $staffid, $deptid);
430
431
        return $this->db->query($sql);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->db->query($sql) could return the type mysqli_result which is incompatible with the type-hinted return boolean. Consider adding an additional type-check to rule them out.
Loading history...
432
    }
433
434
    /**
435
     * Remove a staff member from a department
436
     *
437
     * @param mixed $staff uid or {@link Staff} object
438
     * @param mixed $dept  department id or {@link Department} object
439
     * @return bool  True if successful, False if not
440
     */
441
    private function removeMembership($staff, $dept): bool
442
    {
443
        $deptid  = 0;
444
        $staffid = 0;
445
446
        if (\is_object($staff)) {
447
            $staffid = $staff->getVar('uid');
448
        } else {
449
            $staffid = (int)$staff;
450
        }
451
452
        if (\is_object($dept)) {
453
            $deptid = $dept->getVar('id');
454
        } else {
455
            $deptid = (int)$dept;
456
        }
457
458
        return $this->removeJoinerRecord($staffid, $deptid);
459
    }
460
461
    /**
462
     * Remove a record from the joiner db table
463
     *
464
     * @param int $staffid user id
465
     * @param int $deptid  department id
466
     * @return bool True if successful, False if not
467
     */
468
    private function removeJoinerRecord(int $staffid, int $deptid): bool
469
    {
470
        $sql = \sprintf('DELETE FROM `%s` WHERE uid=%u AND department=%u', $this->db->prefix('xhelp_jstaffdept'), $staffid, $deptid);
471
472
        return $this->db->queryF($sql);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->db->queryF($sql) could return the type mysqli_result which is incompatible with the type-hinted return boolean. Consider adding an additional type-check to rule them out.
Loading history...
473
    }
474
475
    /**
476
     * @param array $depts
477
     * @return array
478
     */
479
    private function &uidsInDepts(array $depts): array
480
    {
481
        $sql = \sprintf('SELECT j.uid FROM `%s` j WHERE j.department IN (%s) GROUP BY j.uid HAVING COUNT(*) = %u', $this->db->prefix('xhelp_jstaffdept'), \implode(',', $depts), \count($depts));
482
483
        $ret = $this->db->query($sql);
484
        $arr = [];
485
486
        while (false !== ($temp = $this->db->fetchArray($ret))) {
0 ignored issues
show
It seems like $ret can also be of type boolean; however, parameter $result of XoopsMySQLDatabase::fetchArray() does only seem to accept mysqli_result, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

486
        while (false !== ($temp = $this->db->fetchArray(/** @scrutinizer ignore-type */ $ret))) {
Loading history...
487
            $arr[] = $temp['uid'];
488
            unset($temp);
489
        }
490
491
        return $arr;
492
    }
493
}
494
495
/* Example Usages
496
497
1. Get all departments for a user
498
$uid = 14;
499
$membershipHandler &= $helper->getHandler('Membership');
500
$depts &= $membershipHandler->membershipByStaff($uid);
501
502
2. Get all staff members of a dept
503
$deptid = 5;
504
$membershipHandler &= $helper->getHandler('Membership');
505
$staff &= $membershipHandler->membershipByDept($deptid);
506
507
3. Add the current user to a department
508
$dept = 5;
509
$membershipHandler &= $helper->getHandler('Membership');
510
$bRet = $membershipHandler->addStaffToDept($xoopsUser, $dept);
511
512
or
513
514
$dept = 5;
515
$membershipHandler &= $helper->getHandler('Membership');
516
$bRet = $membershipHandler->addStaffToDept($xoopsUser->getVar('uid'), $dept);
517
518
4. Add an array of users to a department
519
$dept = 5;
520
$arr = array(5, 14, 18); //Array of uid's to add
521
$membershipHandler &= $helper->getHandler('Membership');
522
$bRet = $membershipHandler->addStaffToDept($arr, $dept);
523
*/
524