get_class( $value ), 'message' => $value->getMessage(), ); } // Arrayable class object. if ( is_object( $value ) && $value instanceof Arrayable && method_exists( get_class( $value ), 'from_array' ) ) { return array( 'classname' => get_class( $value ), 'data' => $value->to_array(), ); } // Array (recursion necessary). if ( is_array( $value ) ) { foreach ( $value as $key => $item ) { $value[ $key ] = self::sanitize_value_for_cache( $item ); } } return $value; } /** * Parses the given value from the cache. * * This converts any sanitized exceptions back to their original exception form. * * @since 0.1.0 * * @param mixed $value Value from the cache. * @return mixed Parsed value. * * @throws RuntimeException Thrown if the cached value uses an invalid class. */ private static function parse_value_from_cache( $value ) { // Exception thrown. if ( is_array( $value ) && isset( $value['classname'], $value['message'] ) ) { $class = $value['classname']; if ( ! class_exists( $class ) ) { // This should never be true, but a reasonable safeguard. $class = Exception::class; } $message = $value['message']; return new $class( $message ); } // Arrayable class object. if ( is_array( $value ) && isset( $value['classname'], $value['data'] ) ) { $class = $value['classname']; if ( ! class_exists( $class ) || ! method_exists( $class, 'from_array' ) ) { // This should never be true, but a reasonable safeguard. throw new RuntimeException( sprintf( /* translators: %s: class name */ esc_html__( 'The class %s from the cached value does not exist or does not have a from_array method.', 'ai-services' ), esc_html( $class ) ) ); } $data = $value['data']; return call_user_func( array( $class, 'from_array' ), $data ); } // Array (recursion necessary). if ( is_array( $value ) ) { foreach ( $value as $key => $item ) { $value[ $key ] = self::parse_value_from_cache( $item ); } } return $value; } /** * Gets the cache key for a method call. * * The returned key does not include the service slug, so the service slug has to be separately included as part of * the identifier for where to cache the value. * * @since 0.1.0 * * @param callable $method Method to cache. * @param mixed[] $args Optional. Method arguments. Default empty array. * @return string Cache key. * * @throws InvalidArgumentException Thrown if the method is not a method on a service or model instance. */ private static function get_cache_key( callable $method, array $args = array() ): string { if ( ! is_array( $method ) || ! is_object( $method[0] ) || ! is_string( $method[1] ) ) { throw new InvalidArgumentException( esc_html__( 'Only methods on service and model instances can be cached.', 'ai-services' ) ); } if ( $method[0] instanceof Generative_AI_Service ) { $type = 'service'; } elseif ( $method[0] instanceof Generative_AI_Model ) { $type = 'model'; } else { throw new InvalidArgumentException( esc_html__( 'Only methods on service and model instances can be cached.', 'ai-services' ) ); } return $type . ':' . self::get_cache_hash( $method[1], $args ); } /** * Gets the cache hash for a method call. * * @since 0.1.0 * * @param string $method_name Method name. * @param mixed[] $args Optional. Method arguments. Default empty array. * @return string Cache hash. */ private static function get_cache_hash( string $method_name, array $args = array() ): string { $hash = $method_name; if ( ! empty( $args ) ) { // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.serialize_serialize $hash .= '_' . md5( serialize( $args ) ); } return $hash; } /** * Gets the last changed value for a service. * * @since 0.1.0 * * @param string $service_slug Service slug. * @return string UNIX timestamp for when the configuration of the service was last changed. */ private static function get_last_changed( string $service_slug ): string { if ( wp_using_ext_object_cache() ) { return wp_cache_get_last_changed( $service_slug ); } $last_changed_option = (array) get_option( 'ais_services_last_changed', array() ); if ( ! isset( $last_changed_option[ $service_slug ] ) ) { $last_changed_option[ $service_slug ] = microtime(); update_option( 'ais_services_last_changed', $last_changed_option ); } return $last_changed_option[ $service_slug ]; } /** * Sets the last changed value for a service to the current UNIX timestamp. * * @since 0.1.0 * * @param string $service_slug Service slug. */ private static function set_last_changed( string $service_slug ): void { if ( wp_using_ext_object_cache() ) { wp_cache_set_last_changed( $service_slug ); return; } $last_changed_option = (array) get_option( 'ais_services_last_changed', array() ); $last_changed_option[ $service_slug ] = microtime(); update_option( 'ais_services_last_changed', $last_changed_option ); } }