container->get_rate_limiter(); /** @psalm-suppress RedundantCastGivenDocblockType -- $_SERVER may be non-string at runtime */ $remote_addr = isset( $_SERVER['REMOTE_ADDR'] ) ? sanitize_text_field( (string) wp_unslash( $_SERVER['REMOTE_ADDR'] ) ) // @phpstan-ignore cast.string : '127.0.0.1'; $identifier = $remote_addr; // Use User ID if logged in for more precise limiting if ( is_user_logged_in() ) { $raw_uid = get_current_user_id(); /** @phpstan-ignore-next-line */ $identifier = is_scalar( $raw_uid ) ? (string) $raw_uid : '0'; } if ( $limiter->is_exceeded( $identifier, $limit, $period ) ) { return new \WP_Error( 'rest_throttle', __( 'Too many requests. Please try again later.', 'agenticdaisy-calendar' ), [ 'status' => 429, 'reset' => $limiter->get_reset_time( $identifier ), ] ); } return true; } /** * Register the routes for the objects of the controller. */ public function register_routes(): void { // To be implemented by child classes. } /** * Check if the user has permission to perform the request. * * @param string $capability Required capability. * @return bool|\WP_Error */ protected function check_permission( string $capability ): bool|\WP_Error { if ( ! current_user_can( $capability ) ) { return new \WP_Error( 'rest_forbidden', __( 'You do not have permission to perform this action.', 'agenticdaisy-calendar' ), [ 'status' => 403 ] ); } return true; } /** * Get the logger service. * * @return \WebCalendarDeps\Psr\Log\LoggerInterface */ protected function get_logger(): \WebCalendarDeps\Psr\Log\LoggerInterface { return $this->container->get_logger(); } /** * Get the current WordPress user as a core User entity. * * @return User */ protected function get_current_actor(): User { $login = wp_get_current_user()->user_login; $user_repo = $this->container->get_user_repository(); $user = $user_repo->findByLogin( $login ); if ( $user !== null ) { return $user; } // Fallback for system operations (e.g., holidays pseudo-user) return new User( login: $login, firstName: $login, lastName: '', email: $login . '@example.com', isAdmin: true, isEnabled: true ); } /** * Safely get params as an array. * * @param \WP_REST_Request $request REST request. * @return array */ protected function safe_params( \WP_REST_Request $request ): array { return (array) $request->get_params(); } /** * Safely cast a mixed value to string for PHPStan. * * @param mixed $value Value to cast. * @return string */ protected function str( mixed $value ): string { if ( $value === null ) { return ''; } if ( is_scalar( $value ) || ( is_object( $value ) && method_exists( $value, '__toString' ) ) ) { return (string) $value; } return ''; } /** * Safely cast a mixed value to int for PHPStan. * * @param mixed $value Value to cast. * @return int */ protected function int( mixed $value ): int { if ( $value === null ) { return 0; } if ( is_scalar( $value ) ) { return (int) $value; } return 0; } }