Problem/Motivation
Room reservation validation fatally errors when the reservation author references a user account that no longer exists (or is anonymous, uid 0). ReservationBase::getOwner() returns NULL in those cases, but two constraint validators call $owner->hasPermission() without a null check.
This crashes any code path that runs full entity validation on existing reservations, including:
- The
intercept_room_reservation_validationViews field onintercept_room_reservations(AJAX render of the management list) RoomReservation::validationWarnings()used by the approve confirm form
Observed error:
Error: Call to a member function hasPermission() on null in Drupal\intercept_room_reservation\Plugin\Validation\Constraint\LocationOpenHoursConstraintValidator->validate() (line 55)
The same pattern exists in ReservationMaxDurationConstraintValidator (line 68). A related issue in ReservationLimitConstraintValidator passes getReservor() (which can be FALSE or NULL) to currentUserReservations(AccountInterface $user) without guarding, which can cause a TypeError on the same validation path.
Steps to reproduce
- Create a room reservation as a staff user (or any user who will later be deleted).
- Delete that user account, leaving the reservation's
authorfield pointing at a non-existent uid.
Alternatively: create a reservation as anonymous (uid 0) sogetOwner()isNULL. - As a user with permission to manage room reservations, open the room reservations management view (
intercept_room_reservations) that includes the Reservation conflicts field (intercept_room_reservation_validation). - Observe a fatal error when the view tries to render the row for the affected reservation.
SQL to find affected records:
SELECT r.id, r.author FROM room_reservation_field_data r LEFT JOIN users_field_data u ON u.uid = r.author WHERE r.author > 0 AND u.uid IS NULL;
Proposed resolution
Null-check the reservation owner before calling hasPermission(). When the owner cannot be loaded, treat them as unable to bypass constraints (run validation normally).
LocationOpenHoursConstraintValidator.php
$owner = $entity->getOwner();
$owner_can_bypass = $owner
&& $owner->hasPermission('bypass room reservation open hours constraints');
if (!$owner_can_bypass || $entity->__get('warning')) {
// existing open-hours validation logic
}
ReservationMaxDurationConstraintValidator.php — same pattern for bypass room reservation maximum duration constraints.
ReservationLimitConstraintValidator.php — guard getReservor() before passing to currentUserReservations():
$registrant = $entity->getReservor();
if (!$registrant) {
return;
}
$reservations = array_filter(
$this->reservationManager->currentUserReservations($registrant),
function ($reservation) use ($entity) {
return $reservation->id() != $entity->id();
}
);
Optional hardening in ReservationManager::notifyStatusChange(): null-check $reservation_author before $reservation_author->id() when deduplicating cancel emails.
Remaining tasks
- Add null-safe owner bypass checks to
LocationOpenHoursConstraintValidatorandReservationMaxDurationConstraintValidator. - Guard
getReservor()inReservationLimitConstraintValidator. - Add automated test coverage: reservation with deleted
authorshould validate (and return warnings viavalidationWarnings()) without fatal error. - Confirm bypass behavior is unchanged when owner exists and has bypass permission.
- (Optional) Harden
ReservationManager::notifyStatusChange()for orphaned authors on status-change email paths.
User interface changes
None intended. The room reservations management view and approve form should render validation warnings for affected reservations instead of returning a 500 error.
API changes
None. Internal validator behavior only; no public API, hook, or service contract changes.
Data model changes
None. No schema, field, or entity definition changes. Sites with orphaned author references may still want to reassign author to a valid user for data hygiene, but that is operational cleanup, not required for the code fix.
Comments