map_wp_user_to_entity( $wp_user ); } /** * Returns all users in the system. * * @return User[] */ public function findAll(): array { $wp_users = get_users(); return array_map( [ $this, 'map_wp_user_to_entity' ], $wp_users ); } /** * Returns only enabled users. * * In WordPress, all existing users are considered enabled, * so this delegates to findAll(). * * @return User[] */ #[\Override] public function findAllEnabled(): array { return $this->findAll(); } /** * Persists a user. * * @param User $user User entity. */ public function save( User $user ): void { // In MVP, we might not want to create WP users from here. // But we could if needed using wp_insert_user. } /** * Deletes a user by their login. * * The successor becomes WordPress's reassign target, so UserLifecycle * moves the deleted user's calendar rows to them. Without one (or when * it names no user, or the deleted user), the rows go to the tombstone * login as before. * * @param string $login User login. * @param string|null $successor Login to take over the user's calendar data. */ #[\Override] public function delete( string $login, ?string $successor = null ): void { $wp_user = get_user_by( 'login', $login ); if ( ! $wp_user ) { return; } $reassign = null; if ( null !== $successor && $successor !== $login ) { $heir = get_user_by( 'login', $successor ); if ( $heir ) { $reassign = $heir->ID; } } wp_delete_user( $wp_user->ID, $reassign ); } /** * Returns all preferences for a user. * * @param string $login User login. * @return UserPreference[] */ public function getPreferences( string $login ): array { $wp_user = get_user_by( 'login', $login ); if ( ! $wp_user ) { return []; } $prefs = get_user_meta( $wp_user->ID, 'webcal_prefs', true ); if ( ! is_array( $prefs ) ) { return []; } $results = []; foreach ( $prefs as $key => $value ) { $results[] = new UserPreference( $key, is_scalar( $value ) ? (string) $value : '' ); } return $results; } /** * Saves a preference for a user. * * @param string $login User login. * @param UserPreference $preference User preference. */ public function savePreference( string $login, UserPreference $preference ): void { $wp_user = get_user_by( 'login', $login ); if ( ! $wp_user ) { return; } $prefs = get_user_meta( $wp_user->ID, 'webcal_prefs', true ); if ( ! is_array( $prefs ) ) { $prefs = []; } $prefs[ $preference->key() ] = $preference->value(); update_user_meta( $wp_user->ID, 'webcal_prefs', $prefs ); } /** * Gets the password hash for a user. * * @param string $login User login. * @return string|null */ public function getPasswordHash( string $login ): ?string { $wp_user = get_user_by( 'login', $login ); if ( ! $wp_user ) { return null; } /** @phpstan-ignore-next-line */ return is_scalar( $wp_user->user_pass ) ? (string) $wp_user->user_pass : null; } /** * Sets the password hash for a user. * * @param string $login User login. * @param string $hash Password hash. */ public function setPassword( string $login, string $hash ): void { $wp_user = get_user_by( 'login', $login ); if ( $wp_user ) { wp_set_password( $hash, $wp_user->ID ); } } /** * Maps a WP_User object to a WebCalendar User entity. * * @param WP_User $wp_user WordPress user object. * @return User */ private function map_wp_user_to_entity( WP_User $wp_user ): User { return new User( $wp_user->user_login, $wp_user->first_name ?: $wp_user->display_name, $wp_user->last_name ?: '', $wp_user->user_email, user_can( $wp_user, 'manage_options' ), true // WP users are generally enabled if they exist ); } }