| @@ -7,9 +7,11 @@ | ||
| 7 | 7 | use Exception; |
| 8 | 8 | use UserAccessManager\Config\MainConfig; |
| 9 | 9 | use UserAccessManager\Database\Database; |
| 10 | 10 | use UserAccessManager\Object\ObjectHandler; |
| 11 | -use UserAccessManager\ObjectMembership\Exception\MissingObjectMembershipHandlerException; | |
| 11 | +use UserAccessManager\ObjectMembership\MissingObjectMembershipHandlerException; | |
| 12 | +use UserAccessManager\Util\Util; | |
| 13 | +use UserAccessManager\Wrapper\Php; | |
| 12 | 14 | use UserAccessManager\Wrapper\Wordpress; |
| 13 | 15 | |
| 14 | 16 | abstract class AbstractUserGroup |
| 15 | 17 | { |
| @@ -29,13 +31,15 @@ | ||
| 29 | 31 | /** |
| 30 | 32 | * @throws UserGroupTypeException |
| 31 | 33 | */ |
| 32 | 34 | public function __construct( |
| 35 | + protected Php $php, | |
| 33 | 36 | protected Wordpress $wordpress, |
| 34 | 37 | protected Database $database, |
| 35 | 38 | protected MainConfig $config, |
| 39 | + protected Util $util, | |
| 36 | 40 | protected ObjectHandler $objectHandler, |
| 37 | - protected AssignedObjectsLoader $assignedObjectsLoader, | |
| 41 | + protected AssignmentInformationFactory $assignmentInformationFactory, | |
| 38 | 42 | protected int|string|null $id = null |
| 39 | 43 | ) { |
| 40 | 44 | if ($this->type === null) { |
| 41 | 45 | throw new UserGroupTypeException('User group type must not null.'); |
| @@ -112,31 +116,16 @@ | ||
| 112 | 116 | $this->objectMembership = []; |
| 113 | 117 | $this->fullObjectMembership = []; |
| 114 | 118 | } |
| 115 | 119 | |
| 116 | - private function resetObjectsAfterAssignmentChange(): void | |
| 117 | - { | |
| 118 | - $this->assignedObjectsLoader->flush(); | |
| 119 | - $this->resetObjects(); | |
| 120 | - } | |
| 121 | - | |
| 122 | 120 | /** |
| 123 | - * Returns the general object type of an assignable object type, null if the object type can't be assigned. | |
| 124 | - */ | |
| 125 | - private function getAssignableGeneralObjectType(string $objectType): ?string | |
| 126 | - { | |
| 127 | - $generalObjectType = $this->objectHandler->getGeneralObjectType($objectType); | |
| 128 | - | |
| 129 | - return ($generalObjectType !== null && $this->objectHandler->isValidObjectType($objectType) === true) ? | |
| 130 | - $generalObjectType : null; | |
| 131 | - } | |
| 132 | - | |
| 133 | - /** | |
| 134 | 121 | * @throws Exception |
| 135 | 122 | */ |
| 136 | 123 | public function delete(): bool |
| 137 | 124 | { |
| 138 | - foreach ($this->objectHandler->getAllObjectTypes() as $objectType) { | |
| 125 | + $allObjectTypes = $this->objectHandler->getAllObjectTypes(); | |
| 126 | + | |
| 127 | + foreach ($allObjectTypes as $objectType) { | |
| 139 | 128 | $this->removeObject($objectType); |
| 140 | 129 | } |
| 141 | 130 | |
| 142 | 131 | return true; |
| @@ -144,17 +133,19 @@ | ||
| 144 | 133 | |
| 145 | 134 | /** |
| 146 | 135 | * @throws Exception |
| 147 | 136 | */ |
| 148 | - public function addObject(string $objectType, int|string|null $objectId, $fromDate = null, $toDate = null): bool | |
| 137 | + public function addObject(string $objectType, int|string $objectId, $fromDate = null, $toDate = null): bool | |
| 149 | 138 | { |
| 150 | - $generalObjectType = $this->getAssignableGeneralObjectType($objectType); | |
| 139 | + $generalObjectType = $this->objectHandler->getGeneralObjectType($objectType); | |
| 151 | 140 | |
| 152 | - if ($generalObjectType === null) { | |
| 141 | + if ($generalObjectType === null | |
| 142 | + || $this->objectHandler->isValidObjectType($objectType) === false | |
| 143 | + ) { | |
| 153 | 144 | return false; |
| 154 | 145 | } |
| 155 | 146 | |
| 156 | - $success = $this->database->replace( | |
| 147 | + $return = $this->database->replace( | |
| 157 | 148 | $this->database->getUserGroupToObjectTable(), |
| 158 | 149 | [ |
| 159 | 150 | 'group_id' => $this->id, |
| 160 | 151 | 'group_type' => $this->type, |
| @@ -163,16 +154,25 @@ | ||
| 163 | 154 | 'object_type' => $objectType, |
| 164 | 155 | 'from_date' => $fromDate, |
| 165 | 156 | 'to_date' => $toDate |
| 166 | 157 | ], |
| 167 | - ['%s', '%s', '%s', '%s', '%s', '%s', '%s'] | |
| 168 | - ) !== false; | |
| 158 | + [ | |
| 159 | + '%s', | |
| 160 | + '%s', | |
| 161 | + '%s', | |
| 162 | + '%s', | |
| 163 | + '%s', | |
| 164 | + '%s', | |
| 165 | + '%s' | |
| 166 | + ] | |
| 167 | + ); | |
| 169 | 168 | |
| 170 | - if ($success === true) { | |
| 171 | - $this->resetObjectsAfterAssignmentChange(); | |
| 169 | + if ($return !== false) { | |
| 170 | + $this->resetObjects(); | |
| 171 | + return true; | |
| 172 | 172 | } |
| 173 | 173 | |
| 174 | - return $success; | |
| 174 | + return false; | |
| 175 | 175 | } |
| 176 | 176 | |
| 177 | 177 | /** |
| 178 | 178 | * @throws Exception |
| @@ -178,15 +178,17 @@ | ||
| 178 | 178 | * @throws Exception |
| 179 | 179 | */ |
| 180 | 180 | public function removeObject(string $objectType, $objectId = null, bool $ignoreGeneralType = false): bool |
| 181 | 181 | { |
| 182 | - $generalObjectType = $this->getAssignableGeneralObjectType($objectType); | |
| 182 | + $generalObjectType = $this->objectHandler->getGeneralObjectType($objectType); | |
| 183 | 183 | |
| 184 | - if ($generalObjectType === null) { | |
| 184 | + if ($generalObjectType === null | |
| 185 | + || $this->objectHandler->isValidObjectType($objectType) === false | |
| 186 | + ) { | |
| 185 | 187 | return false; |
| 186 | 188 | } |
| 187 | 189 | |
| 188 | - $objectTypeQuery = " AND `object_type` = '%s' "; | |
| 190 | + $objectTypeQuery = " AND object_type = '%s' "; | |
| 189 | 191 | $values = [ |
| 190 | 192 | $this->id, |
| 191 | 193 | $this->type, |
| 192 | 194 | $objectType |
| @@ -192,26 +194,27 @@ | ||
| 192 | 194 | $objectType |
| 193 | 195 | ]; |
| 194 | 196 | |
| 195 | 197 | if ($ignoreGeneralType === false) { |
| 196 | - $objectTypeQuery = " AND (`object_type` = '%s' OR `general_object_type` = '%s') "; | |
| 198 | + $objectTypeQuery = " AND (object_type = '%s' OR general_object_type = '%s') "; | |
| 197 | 199 | $values[] = $generalObjectType; |
| 198 | 200 | } |
| 199 | 201 | |
| 200 | - $query = "DELETE FROM `{$this->database->getUserGroupToObjectTable()}` | |
| 201 | - WHERE `group_id` = %d | |
| 202 | - AND `group_type` = '%s' | |
| 202 | + $query = "DELETE FROM {$this->database->getUserGroupToObjectTable()} | |
| 203 | + WHERE group_id = %d | |
| 204 | + AND group_type = '%s' | |
| 203 | 205 | $objectTypeQuery"; |
| 204 | 206 | |
| 205 | 207 | if ($objectId !== null) { |
| 206 | - $query .= ' AND `object_id` = %d'; | |
| 208 | + $query .= ' AND object_id = %d'; | |
| 207 | 209 | $values[] = $objectId; |
| 208 | 210 | } |
| 209 | 211 | |
| 210 | - $success = $this->database->query($this->database->prepare($query, $values)) !== false; | |
| 212 | + $query = $this->database->prepare($query, $values); | |
| 213 | + $success = ($this->database->query($query) !== false); | |
| 211 | 214 | |
| 212 | 215 | if ($success === true) { |
| 213 | - $this->resetObjectsAfterAssignmentChange(); | |
| 216 | + $this->resetObjects(); | |
| 214 | 217 | } |
| 215 | 218 | |
| 216 | 219 | return $success; |
| 217 | 220 | } |
| @@ -220,14 +223,40 @@ | ||
| 220 | 223 | * @return AssignmentInformation[] |
| 221 | 224 | */ |
| 222 | 225 | public function getAssignedObjects(string $objectType): array |
| 223 | 226 | { |
| 224 | - return $this->assignedObjects[$objectType] ??= $this->assignedObjectsLoader->getAssignedObjects( | |
| 225 | - $this->type, | |
| 226 | - $this->id, | |
| 227 | - $objectType, | |
| 228 | - $this->ignoreDates | |
| 229 | - ); | |
| 227 | + if (isset($this->assignedObjects[$objectType]) === false) { | |
| 228 | + $query = "SELECT object_id AS id, object_type AS objectType, from_date AS fromDate, to_date AS toDate | |
| 229 | + FROM {$this->database->getUserGroupToObjectTable()} | |
| 230 | + WHERE group_id = '%s' | |
| 231 | + AND group_type = '%s' | |
| 232 | + AND object_id != '' | |
| 233 | + AND (general_object_type = '%s' OR object_type = '%s')"; | |
| 234 | + | |
| 235 | + $parameters = [ | |
| 236 | + $this->id, | |
| 237 | + $this->type, | |
| 238 | + $objectType, | |
| 239 | + $objectType | |
| 240 | + ]; | |
| 241 | + | |
| 242 | + if ($this->ignoreDates === false) { | |
| 243 | + $query .= " AND (from_date IS NULL OR from_date <= '%s') AND (to_date IS NULL OR to_date >= '%s')"; | |
| 244 | + $time = $this->wordpress->currentTime('mysql'); | |
| 245 | + $parameters = array_merge($parameters, [$time, $time]); | |
| 246 | + } | |
| 247 | + | |
| 248 | + $query = $this->database->prepare($query, $parameters); | |
| 249 | + $results = (array) $this->database->getResults($query); | |
| 250 | + $this->assignedObjects[$objectType] = []; | |
| 251 | + | |
| 252 | + foreach ($results as $result) { | |
| 253 | + $this->assignedObjects[$objectType][$result->id] = $this->assignmentInformationFactory | |
| 254 | + ->createAssignmentInformation($result->objectType, $result->fromDate, $result->toDate); | |
| 255 | + } | |
| 256 | + } | |
| 257 | + | |
| 258 | + return $this->assignedObjects[$objectType]; | |
| 230 | 259 | } |
| 231 | 260 | |
| 232 | 261 | /** |
| 233 | 262 | * @throws Exception |
| @@ -251,72 +280,72 @@ | ||
| 251 | 280 | { |
| 252 | 281 | return $this->removeObject($objectType, '', true); |
| 253 | 282 | } |
| 254 | 283 | |
| 255 | - /** | |
| 256 | - * @return array<string, array{0: int|null, 1: int|null}> Time ranges keyed by the object type. | |
| 257 | - */ | |
| 258 | - public function getDefaultGroupForObjectTypes(): array | |
| 284 | + public function getDefaultGroupForObjectTypes(): ?array | |
| 259 | 285 | { |
| 260 | - return $this->defaultTypes ??= $this->loadDefaultGroupForObjectTypes(); | |
| 261 | - } | |
| 286 | + if ($this->defaultTypes === null) { | |
| 287 | + $this->defaultTypes = []; | |
| 262 | 288 | |
| 263 | - /** | |
| 264 | - * @return array<string, array{0: int|null, 1: int|null}> | |
| 265 | - */ | |
| 266 | - private function loadDefaultGroupForObjectTypes(): array | |
| 267 | - { | |
| 268 | - $query = $this->database->prepare( | |
| 269 | - "SELECT `object_type` AS `objectType`, `from_date` AS `fromDate`, `to_date` AS `toDate` | |
| 270 | - FROM `{$this->database->getUserGroupToObjectTable()}` | |
| 271 | - WHERE `group_id` = '%s' | |
| 272 | - AND `group_type` = '%s' | |
| 273 | - AND `object_id` = ''", | |
| 274 | - [ | |
| 289 | + $query = "SELECT object_type AS objectType, from_date AS fromDate, to_date AS toDate | |
| 290 | + FROM {$this->database->getUserGroupToObjectTable()} | |
| 291 | + WHERE group_id = '%s' | |
| 292 | + AND group_type = '%s' | |
| 293 | + AND object_id = ''"; | |
| 294 | + | |
| 295 | + $parameters = [ | |
| 275 | 296 | $this->id, |
| 276 | 297 | $this->type |
| 277 | - ] | |
| 278 | - ); | |
| 298 | + ]; | |
| 279 | 299 | |
| 280 | - $defaultTypes = []; | |
| 300 | + $query = $this->database->prepare($query, $parameters); | |
| 301 | + $results = (array) $this->database->getResults($query); | |
| 281 | 302 | |
| 282 | - foreach ((array) $this->database->getResults($query) as $result) { | |
| 283 | - $defaultTypes[$result->objectType] = [ | |
| 284 | - ($result->fromDate !== null) ? strtotime($result->fromDate) : null, | |
| 285 | - ($result->toDate !== null) ? strtotime($result->toDate) : null | |
| 286 | - ]; | |
| 303 | + foreach ($results as $result) { | |
| 304 | + $this->defaultTypes[$result->objectType] = [ | |
| 305 | + ($result->fromDate !== null) ? strtotime($result->fromDate) : null, | |
| 306 | + ($result->toDate !== null) ? strtotime($result->toDate) : null | |
| 307 | + ]; | |
| 308 | + } | |
| 287 | 309 | } |
| 288 | 310 | |
| 289 | - return $defaultTypes; | |
| 311 | + return $this->defaultTypes; | |
| 290 | 312 | } |
| 291 | 313 | |
| 292 | - public function isDefaultGroupForObjectType(string $objectType, ?int &$fromTime = null, ?int &$toTime = null): bool | |
| 314 | + public function isDefaultGroupForObjectType(string $objectType, int &$fromTime = null, int &$toTime = null): bool | |
| 293 | 315 | { |
| 294 | 316 | $defaultGroupForObjectTypes = $this->getDefaultGroupForObjectTypes(); |
| 295 | 317 | |
| 296 | - // The reference values have to be reset even when the group is no default group for the object type | |
| 318 | + // Reset reference values anyway | |
| 297 | 319 | $fromTime = null; |
| 298 | 320 | $toTime = null; |
| 299 | 321 | |
| 300 | - if (isset($defaultGroupForObjectTypes[$objectType]) === false) { | |
| 301 | - return false; | |
| 322 | + if (isset($defaultGroupForObjectTypes[$objectType])) { | |
| 323 | + $fromTime = $defaultGroupForObjectTypes[$objectType][0] !== null ? | |
| 324 | + (int) $defaultGroupForObjectTypes[$objectType][0] : null; | |
| 325 | + $toTime = $defaultGroupForObjectTypes[$objectType][1] !== null ? | |
| 326 | + (int) $defaultGroupForObjectTypes[$objectType][1] : null; | |
| 327 | + | |
| 328 | + return true; | |
| 302 | 329 | } |
| 303 | 330 | |
| 304 | - [$fromTimestamp, $toTimestamp] = $defaultGroupForObjectTypes[$objectType]; | |
| 305 | - $fromTime = ($fromTimestamp !== null) ? (int) $fromTimestamp : null; | |
| 306 | - $toTime = ($toTimestamp !== null) ? (int) $toTimestamp : null; | |
| 307 | - | |
| 308 | - return true; | |
| 331 | + return false; | |
| 309 | 332 | } |
| 310 | 333 | |
| 311 | 334 | public function isObjectAssignedToGroup( |
| 312 | 335 | string $objectType, |
| 313 | - int|string|null $objectId, | |
| 314 | - ?AssignmentInformation &$assignmentInformation = null | |
| 336 | + int|string $objectId, | |
| 337 | + AssignmentInformation &$assignmentInformation = null | |
| 315 | 338 | ): bool { |
| 316 | - $assignmentInformation = $this->getAssignedObjects($objectType)[$objectId] ?? null; | |
| 339 | + $assignmentInformation = null; | |
| 340 | + $assignedObjects = $this->getAssignedObjects($objectType); | |
| 317 | 341 | |
| 318 | - return $assignmentInformation !== null; | |
| 342 | + if (isset($assignedObjects[$objectId]) === true) { | |
| 343 | + $assignmentInformation = $assignedObjects[$objectId]; | |
| 344 | + return true; | |
| 345 | + } | |
| 346 | + | |
| 347 | + return false; | |
| 319 | 348 | } |
| 320 | 349 | |
| 321 | 350 | /** |
| 322 | 351 | * @throws Exception |
| @@ -323,9 +352,9 @@ | ||
| 323 | 352 | */ |
| 324 | 353 | public function isObjectMember( |
| 325 | 354 | string $objectType, |
| 326 | 355 | int|string|null $objectId, |
| 327 | - ?AssignmentInformation &$assignmentInformation = null | |
| 356 | + AssignmentInformation &$assignmentInformation = null | |
| 328 | 357 | ): bool { |
| 329 | 358 | if (isset($this->objectMembership[$objectType][$objectId]) === false) { |
| 330 | 359 | try { |
| 331 | 360 | $isMember = $this->objectHandler->getObjectMembershipHandler($objectType)->isMember( |
| @@ -337,21 +366,22 @@ | ||
| 337 | 366 | } catch (MissingObjectMembershipHandlerException) { |
| 338 | 367 | $isMember = false; |
| 339 | 368 | } |
| 340 | 369 | |
| 341 | - $this->objectMembership[$objectType][$objectId] = ($isMember === true) ? $assignmentInformation : false; | |
| 370 | + $this->objectMembership[$objectType][$objectId] = ($isMember === true) ? | |
| 371 | + $assignmentInformation : false; | |
| 342 | 372 | } |
| 343 | 373 | |
| 344 | - $membership = $this->objectMembership[$objectType][$objectId]; | |
| 345 | - $assignmentInformation = ($membership instanceof AssignmentInformation) ? $membership : null; | |
| 374 | + $assignmentInformation = ($this->objectMembership[$objectType][$objectId] instanceof AssignmentInformation) ? | |
| 375 | + $this->objectMembership[$objectType][$objectId] : null; | |
| 346 | 376 | |
| 347 | - return $membership !== false; | |
| 377 | + return ($this->objectMembership[$objectType][$objectId] !== false); | |
| 348 | 378 | } |
| 349 | 379 | |
| 350 | 380 | /** |
| 351 | 381 | * @throws Exception |
| 352 | 382 | */ |
| 353 | - public function isRoleMember(int|string|null $roleId, ?AssignmentInformation &$assignmentInformation = null): bool | |
| 383 | + public function isRoleMember(int|string $roleId, ?AssignmentInformation &$assignmentInformation = null): bool | |
| 354 | 384 | { |
| 355 | 385 | return $this->isObjectMember(ObjectHandler::GENERAL_ROLE_OBJECT_TYPE, $roleId, $assignmentInformation); |
| 356 | 386 | } |
| 357 | 387 | |
| @@ -357,9 +387,9 @@ | ||
| 357 | 387 | |
| 358 | 388 | /** |
| 359 | 389 | * @throws Exception |
| 360 | 390 | */ |
| 361 | - public function isUserMember(int|string|null $userId, ?AssignmentInformation &$assignmentInformation = null): bool | |
| 391 | + public function isUserMember(int|string $userId, AssignmentInformation &$assignmentInformation = null): bool | |
| 362 | 392 | { |
| 363 | 393 | return $this->isObjectMember(ObjectHandler::GENERAL_USER_OBJECT_TYPE, $userId, $assignmentInformation); |
| 364 | 394 | } |
| 365 | 395 | |
| @@ -365,9 +395,9 @@ | ||
| 365 | 395 | |
| 366 | 396 | /** |
| 367 | 397 | * @throws Exception |
| 368 | 398 | */ |
| 369 | - public function isTermMember(int|string|null $termId, ?AssignmentInformation &$assignmentInformation = null): bool | |
| 399 | + public function isTermMember(int|string $termId, AssignmentInformation &$assignmentInformation = null): bool | |
| 370 | 400 | { |
| 371 | 401 | return $this->isObjectMember(ObjectHandler::GENERAL_TERM_OBJECT_TYPE, $termId, $assignmentInformation); |
| 372 | 402 | } |
| 373 | 403 | |
| @@ -373,9 +403,9 @@ | ||
| 373 | 403 | |
| 374 | 404 | /** |
| 375 | 405 | * @throws Exception |
| 376 | 406 | */ |
| 377 | - public function isPostMember(int|string|null $postId, ?AssignmentInformation &$assignmentInformation = null): bool | |
| 407 | + public function isPostMember(int|string $postId, AssignmentInformation &$assignmentInformation = null): bool | |
| 378 | 408 | { |
| 379 | 409 | return $this->isObjectMember(ObjectHandler::GENERAL_POST_OBJECT_TYPE, $postId, $assignmentInformation); |
| 380 | 410 | } |
| 381 | 411 | |
| @@ -398,9 +428,16 @@ | ||
| 398 | 428 | * @throws Exception |
| 399 | 429 | */ |
| 400 | 430 | public function isLockedRecursive(string $objectType, int|string|null $objectId): bool |
| 401 | 431 | { |
| 402 | - return count($this->getRecursiveMembershipForObject($objectType, $objectId)) > 0; | |
| 432 | + /** | |
| 433 | + * @var AssignmentInformation $assignmentInformation | |
| 434 | + */ | |
| 435 | + if ($this->isObjectMember($objectType, $objectId, $assignmentInformation) === true) { | |
| 436 | + return (count($assignmentInformation->getRecursiveMembership()) > 0); | |
| 437 | + } | |
| 438 | + | |
| 439 | + return false; | |
| 403 | 440 | } |
| 404 | 441 | |
| 405 | 442 | /** |
| 406 | 443 | * @throws Exception |
| @@ -408,10 +445,10 @@ | ||
| 408 | 445 | public function getAssignedObjectsByType(string $objectType): array |
| 409 | 446 | { |
| 410 | 447 | if (isset($this->fullObjectMembership[$objectType]) === false) { |
| 411 | 448 | try { |
| 412 | - $membershipHandler = $this->objectHandler->getObjectMembershipHandler($objectType); | |
| 413 | - $this->fullObjectMembership[$objectType] = $membershipHandler->getFullObjects( | |
| 449 | + $handler = $this->objectHandler->getObjectMembershipHandler($objectType); | |
| 450 | + $this->fullObjectMembership[$objectType] = $handler->getFullObjects( | |
| 414 | 451 | $this, |
| 415 | 452 | $this->config->lockRecursive(), |
| 416 | 453 | ($objectType === $this->objectHandler->getGeneralObjectType($objectType)) ? null : $objectType |
| 417 | 454 | ); |
| @@ -429,8 +466,9 @@ | ||
| 429 | 466 | public function getFullRoles(): array |
| 430 | 467 | { |
| 431 | 468 | return $this->getAssignedObjectsByType(ObjectHandler::GENERAL_ROLE_OBJECT_TYPE); |
| 432 | 469 | } |
| 470 | + | |
| 433 | 471 | |
| 434 | 472 | /** |
| 435 | 473 | * @throws Exception |
| 436 | 474 | */ |