1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* @package midcom |
4
|
|
|
* @author The Midgard Project, http://www.midgard-project.org |
5
|
|
|
* @copyright The Midgard Project, http://www.midgard-project.org |
6
|
|
|
* @license http://www.gnu.org/licenses/lgpl.html GNU Lesser General Public License |
7
|
|
|
*/ |
8
|
|
|
|
9
|
|
|
use Doctrine\ORM\Query\Expr\Join; |
10
|
|
|
|
11
|
|
|
/** |
12
|
|
|
* MidCOM group implementation supporting Midgard Groups. |
13
|
|
|
* |
14
|
|
|
* @package midcom |
15
|
|
|
*/ |
16
|
|
|
class midcom_core_group |
17
|
|
|
{ |
18
|
|
|
/** |
19
|
|
|
* The storage object on which we are based. This is usually a midgard_group |
20
|
|
|
* directly, as this class has to work outside of the ACLs. It must not be used |
21
|
|
|
* from the outside. |
22
|
|
|
* |
23
|
|
|
* Access to this member is restricted to the ACL user/group core. In case you |
24
|
|
|
* need a real Storage object for this group, call get_storage() instead. |
25
|
|
|
* |
26
|
|
|
* @var midgard_group |
27
|
|
|
*/ |
28
|
|
|
protected $_storage = null; |
29
|
|
|
|
30
|
|
|
/** |
31
|
|
|
* Name of the group |
32
|
|
|
* |
33
|
|
|
* The variable is considered to be read-only. |
34
|
|
|
* |
35
|
|
|
* @var string |
36
|
|
|
*/ |
37
|
|
|
public $name = ''; |
38
|
|
|
|
39
|
|
|
/** |
40
|
|
|
* The identification string used to internally identify the group uniquely |
41
|
|
|
* in the system. This is usually some kind of group:$guid string combination. |
42
|
|
|
* |
43
|
|
|
* The variable is considered to be read-only. |
44
|
|
|
* |
45
|
|
|
* @var string |
46
|
|
|
*/ |
47
|
|
|
public $id = ''; |
48
|
|
|
|
49
|
|
|
/** |
50
|
|
|
* The scope value, which must be set during the _load callback, indicates the "depth" of the |
51
|
|
|
* group in the inheritance tree. This is used during privilege merging in the content |
52
|
|
|
* privilege code, which needs a way to determine the proper ordering. Top level groups |
53
|
|
|
* start with a scope of 1. |
54
|
|
|
* |
55
|
|
|
* The variable is considered to be read-only. |
56
|
|
|
* |
57
|
|
|
* @var integer |
58
|
|
|
*/ |
59
|
|
|
public $scope = MIDCOM_PRIVILEGE_SCOPE_ROOTGROUP; |
60
|
|
|
|
61
|
|
|
/** |
62
|
|
|
* Contains the parent of the current group, cached for repeated accesses. |
63
|
|
|
* |
64
|
|
|
* @var midcom_core_group |
65
|
|
|
*/ |
66
|
|
|
private $_cached_parent_group = null; |
67
|
|
|
|
68
|
|
|
/** |
69
|
|
|
* The constructor retrieves the group identified by its name from the database and |
70
|
|
|
* prepares the object for operation. |
71
|
|
|
* |
72
|
|
|
* It will use the Query Builder to retrieve a group by its name and populate the |
73
|
|
|
* $storage, $name and $id members accordingly. |
74
|
|
|
* |
75
|
|
|
* Any error will trigger midcom_error. |
76
|
|
|
* |
77
|
|
|
* @param mixed $id This is a valid identifier for the group to be loaded. Usually this is either |
78
|
|
|
* a database ID or GUID for Midgard Groups or a valid complete MidCOM group identifier, which |
79
|
|
|
* will work for all subclasses. |
80
|
|
|
*/ |
81
|
3 |
|
public function __construct($id = null) |
82
|
|
|
{ |
83
|
3 |
|
if (is_null($id)) { |
84
|
|
|
throw new midcom_error('The class midcom_core_group is not default constructible.'); |
85
|
|
|
} |
86
|
|
|
|
87
|
3 |
|
if (is_a($id, midcom_db_group::class) || is_a($id, 'midgard_group')) { |
88
|
1 |
|
$this->_storage = $id; |
|
|
|
|
89
|
|
|
} else { |
90
|
3 |
|
if (is_string($id)) { |
91
|
3 |
|
$id_parts = explode(':', $id); |
92
|
3 |
|
if (count($id_parts) == 2) { |
93
|
3 |
|
if ($id_parts[0] != 'group') { |
94
|
|
|
throw new midcom_error("The group type identifier {$id_parts[0]} is unknown"); |
95
|
|
|
} |
96
|
3 |
|
$id = $id_parts[1]; |
97
|
|
|
} |
98
|
|
|
} elseif (is_numeric($id) && $id == 0) { |
99
|
|
|
throw new midcom_error('0 is not a valid DB identifier'); |
100
|
|
|
} |
101
|
|
|
try { |
102
|
3 |
|
$this->_storage = new midgard_group($id); |
103
|
|
|
} catch (Exception $e) { |
104
|
|
|
debug_add('Tried to load a midcom_core_group, but got error ' . $e->getMessage(), MIDCOM_LOG_ERROR); |
105
|
|
|
debug_print_r('Passed argument was:', $id); |
106
|
|
|
throw new midcom_error($e->getMessage()); |
107
|
|
|
} |
108
|
|
|
} |
109
|
|
|
|
110
|
3 |
|
if ($this->_storage->official != '') { |
|
|
|
|
111
|
|
|
$this->name = $this->_storage->official; |
112
|
3 |
|
} elseif ($this->_storage->name != '') { |
|
|
|
|
113
|
|
|
$this->name = $this->_storage->name; |
114
|
|
|
} else { |
115
|
3 |
|
$this->name = "Group #{$this->_storage->id}"; |
|
|
|
|
116
|
|
|
} |
117
|
3 |
|
$this->id = "group:{$this->_storage->guid}"; |
|
|
|
|
118
|
|
|
|
119
|
|
|
// Determine scope |
120
|
3 |
|
$parent = $this->get_parent_group(); |
121
|
3 |
|
if (is_null($parent)) { |
122
|
3 |
|
$this->scope = MIDCOM_PRIVILEGE_SCOPE_ROOTGROUP; |
123
|
|
|
} else { |
124
|
|
|
$this->scope = $parent->scope + 1; |
125
|
|
|
} |
126
|
3 |
|
} |
127
|
|
|
|
128
|
|
|
/** |
129
|
|
|
* Retrieves a list of users for which are a member in this group. |
130
|
|
|
* |
131
|
|
|
* @return midcom_core_user[] A list of user objects in which are members of the current group, indexed by their ID. |
132
|
|
|
*/ |
133
|
|
|
public function list_members() |
134
|
|
|
{ |
135
|
|
|
$return = []; |
136
|
|
|
|
137
|
|
|
if (empty($this->_storage->id)) { |
|
|
|
|
138
|
|
|
debug_add('$this->storage is not object or id is empty', MIDCOM_LOG_ERROR); |
139
|
|
|
return $return; |
140
|
|
|
} |
141
|
|
|
|
142
|
|
|
$qb = new midgard_query_builder(midcom::get()->config->get('person_class')); |
143
|
|
|
$qb->get_doctrine() |
144
|
|
|
->leftJoin('midgard_member', 'm', Join::WITH, 'm.uid = c.id') |
145
|
|
|
->where('m.gid = :id') |
146
|
|
|
->setParameter('id', $this->_storage->id); |
147
|
|
|
|
148
|
|
|
foreach ($qb->execute() as $person) { |
149
|
|
|
$user = new midcom_core_user($person); |
150
|
|
|
$return[$user->id] = $user; |
151
|
|
|
} |
152
|
|
|
|
153
|
|
|
return $return; |
154
|
|
|
} |
155
|
|
|
|
156
|
|
|
/** |
157
|
|
|
* Return a list of all groups in which the MidCOM user passed is a member. |
158
|
|
|
* |
159
|
|
|
* @param midcom_core_user $user The user that should be looked up. |
160
|
|
|
* @return midcom_core_group[] Member groups, indexed by their ID. |
161
|
|
|
*/ |
162
|
95 |
|
public static function list_memberships(midcom_core_user $user) |
163
|
|
|
{ |
164
|
95 |
|
$qb = new midgard_query_builder('midgard_group'); |
165
|
95 |
|
$qb->get_doctrine() |
166
|
95 |
|
->leftJoin('midgard_member', 'm', Join::WITH, 'm.gid = c.id') |
167
|
95 |
|
->leftJoin('midgard_person', 'p', Join::WITH, 'm.uid = p.id') |
168
|
95 |
|
->where('p.guid = :guid') |
169
|
95 |
|
->setParameter('guid', $user->guid); |
170
|
|
|
|
171
|
95 |
|
$return = []; |
172
|
95 |
|
foreach ($qb->execute() as $group) { |
173
|
1 |
|
$return['group:' . $group->guid] = new static($group); |
174
|
|
|
} |
175
|
|
|
|
176
|
95 |
|
return $return; |
177
|
|
|
} |
178
|
|
|
|
179
|
|
|
/** |
180
|
|
|
* Returns the parent group. |
181
|
|
|
* |
182
|
|
|
* @return midcom_core_group The parent group of the current group or null if there is none. |
183
|
|
|
*/ |
184
|
3 |
|
function get_parent_group() |
185
|
|
|
{ |
186
|
3 |
|
if (is_null($this->_cached_parent_group)) { |
187
|
3 |
|
if ($this->_storage->owner == 0) { |
|
|
|
|
188
|
3 |
|
return null; |
189
|
|
|
} |
190
|
|
|
|
191
|
|
|
if ($this->_storage->id == $this->_storage->owner) { |
|
|
|
|
192
|
|
|
debug_print_r('Broken Group', $this, MIDCOM_LOG_CRIT); |
193
|
|
|
throw new midcom_error('A group was its own parent, which will result in an infinite loop. See debug log for more info.'); |
194
|
|
|
} |
195
|
|
|
|
196
|
|
|
$parent = new midgard_group(); |
197
|
|
|
$parent->get_by_id($this->_storage->owner); |
198
|
|
|
|
199
|
|
|
if (!$parent->id) { |
200
|
|
|
debug_add("Could not load Group ID {$this->_storage->owner} from the database, aborting, this should not happen. See the debug level log for details. (" |
201
|
|
|
. midcom_connection::get_error_string() . ')', |
202
|
|
|
MIDCOM_LOG_ERROR); |
203
|
|
|
debug_print_r('Group that we started from is:', $this->_storage); |
204
|
|
|
return null; |
205
|
|
|
} |
206
|
|
|
|
207
|
|
|
$this->_cached_parent_group = midcom::get()->auth->get_group($parent); |
|
|
|
|
208
|
|
|
} |
209
|
|
|
return $this->_cached_parent_group; |
210
|
|
|
} |
211
|
|
|
|
212
|
|
|
/** |
213
|
|
|
* Return a list of privileges assigned directly to the group. The default implementation |
214
|
|
|
* queries the GUID directly using the get_self_privileges method of the |
215
|
|
|
* midcom_core_privilege class, which should work fine on all MgdSchema |
216
|
|
|
* objects. If the storage object is null, an empty array is returned. |
217
|
|
|
* |
218
|
|
|
* @return midcom_core_privilege[] |
219
|
|
|
*/ |
220
|
|
|
public function get_privileges() |
221
|
|
|
{ |
222
|
|
|
if (is_null($this->_storage)) { |
223
|
|
|
return []; |
224
|
|
|
} |
225
|
|
|
return midcom_core_privilege::get_self_privileges($this->_storage->guid); |
|
|
|
|
226
|
|
|
} |
227
|
|
|
|
228
|
|
|
/** |
229
|
|
|
* Return a MidCOM DBA level storage object for the current group. Be aware, |
230
|
|
|
* that depending on ACL information, the retrieval of the user may fail. |
231
|
|
|
* |
232
|
|
|
* Also, as outlined in the member $_storage, not all groups may have a DBA object associated |
233
|
|
|
* with them, therefore this call may return null. |
234
|
|
|
* |
235
|
|
|
* The default implementation will return an instance of midcom_db_group based |
236
|
|
|
* on the member $this->_storage->id if that object is defined, or null otherwise. |
237
|
|
|
* |
238
|
|
|
* @return midcom_db_group A MidCOM DBA object that holds the information associated with |
239
|
|
|
* this group, or null if there is no storage object. |
240
|
|
|
*/ |
241
|
|
|
public function get_storage() |
242
|
|
|
{ |
243
|
|
|
if ($this->_storage === null) { |
244
|
|
|
return null; |
245
|
|
|
} |
246
|
|
|
return new midcom_db_group($this->_storage); |
247
|
|
|
} |
248
|
|
|
} |
249
|
|
|
|
Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.
For example, imagine you have a variable
$accountId
that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to theid
property of an instance of theAccount
class. This class holds a proper account, so the id value must no longer be false.Either this assignment is in error or a type check should be added for that assignment.