event_repo = $event_repo; $this->resource_repo = $resource_repo; } /** * Get participants for an event. * * @param int $event_id Event ID. * @return array List of participant logins. */ public function get_participants( int $event_id ): array { return $this->event_repo->getParticipants( new EventId( $event_id ) ); } /** * Get participants for multiple events in a single query. * * @param array $event_ids Event IDs. * @return array> Map of event_id => participant logins. */ public function get_participants_batch( array $event_ids ): array { if ( empty( $event_ids ) ) { return []; } return $this->event_repo->getParticipantsBatch( array_map( fn( int $id ) => new EventId( $id ), $event_ids ) ); } /** * Save participants for an event. * * Keeps only logins that name a WordPress user or a shared/remote * calendar, then delegates to core. * * @param int $event_id Event ID. * @param array $participants List of participant logins. */ public function save_participants( int $event_id, array $participants ): void { $validated = []; foreach ( $participants as $login ) { $login = trim( sanitize_text_field( $login ) ); if ( '' === $login || strlen( $login ) > 60 ) { continue; } if ( ! get_user_by( 'login', $login ) && ! $this->is_calendar( $login ) ) { continue; } $validated[] = $login; } $this->event_repo->saveParticipants( new EventId( $event_id ), $validated ); } /** * Whether a login names a shared or remote calendar. * * Resources are optional: if they cannot be loaded the login is treated * as unknown and dropped, as it was before calendars were accepted. * * @param string $login Sanitized login. * @return bool */ private function is_calendar( string $login ): bool { if ( null === $this->resource_repo ) { return false; } try { return null !== $this->resource_repo->findByLogin( $login ); } catch ( \Exception $e ) { unset( $e ); return false; } } }