prefix . 'mybot_cache'; } /** * Builds the cache key from the question and the context. * * @param string $question Normalized question. * @param array $extra Data that affects the answer. * @return string */ public static function key( $question, $extra = array() ) { return hash( 'sha256', $question . '|' . wp_json_encode( $extra ) ); } /** * Normalizes the question to increase the cache hit rate. * * @param string $question Raw question. * @return string */ public static function normalize( $question ) { $question = function_exists( 'mb_strtolower' ) ? mb_strtolower( (string) $question, 'UTF-8' ) : strtolower( (string) $question ); $question = preg_replace( '/[^\p{L}\p{N}\s]/u', ' ', $question ); $question = preg_replace( '/\s+/u', ' ', (string) $question ); return trim( (string) $question ); } /** * Reads from the cache. * * @param string $key Cache key. * @return string|null */ public function get( $key ) { if ( wp_using_ext_object_cache() ) { $value = wp_cache_get( $key, self::GROUP ); return is_string( $value ) ? $value : null; } global $wpdb; $table = self::table(); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching $row = $wpdb->get_var( $wpdb->prepare( 'SELECT cache_value FROM %i WHERE cache_key = %s AND expires_at > %s', $table, $key, current_time( 'mysql' ) ) ); return is_string( $row ) ? $row : null; } /** * Writes to the cache. * * @param string $key Cache key. * @param string $value Value. * @param int $ttl Time to live in seconds. 0 means do not cache. * @return void */ public function set( $key, $value, $ttl ) { $ttl = (int) $ttl; if ( $ttl <= 0 ) { return; } if ( wp_using_ext_object_cache() ) { wp_cache_set( $key, $value, self::GROUP, $ttl ); return; } global $wpdb; $table = self::table(); $expires_at = gmdate( 'Y-m-d H:i:s', current_time( 'timestamp' ) + $ttl ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching $wpdb->query( $wpdb->prepare( 'INSERT INTO %i (cache_key, cache_value, expires_at) VALUES (%s, %s, %s) ON DUPLICATE KEY UPDATE cache_value = VALUES(cache_value), expires_at = VALUES(expires_at)', $table, $key, $value, $expires_at ) ); } /** * Deletes a single key. * * @param string $key Cache key. * @return void */ public function delete( $key ) { if ( wp_using_ext_object_cache() ) { wp_cache_delete( $key, self::GROUP ); return; } global $wpdb; // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching $wpdb->delete( self::table(), array( 'cache_key' => $key ), array( '%s' ) ); } /** * Flushes the entire cache. * * @return int Number of deleted rows. */ public function flush() { if ( wp_using_ext_object_cache() ) { wp_cache_flush_group( self::GROUP ); return 0; } global $wpdb; $table = self::table(); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching return (int) $wpdb->query( $wpdb->prepare( 'DELETE FROM %i', $table ) ); } /** * Deletes expired entries. * * @return int Number of deleted rows. */ public function purge_expired() { if ( wp_using_ext_object_cache() ) { return 0; } global $wpdb; $table = self::table(); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching return (int) $wpdb->query( $wpdb->prepare( 'DELETE FROM %i WHERE expires_at < %s', $table, current_time( 'mysql' ) ) ); } /** * Number of entries currently in the cache. * * @return int */ public function count() { if ( wp_using_ext_object_cache() ) { return 0; } global $wpdb; $table = self::table(); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching return (int) $wpdb->get_var( $wpdb->prepare( 'SELECT COUNT(*) FROM %i', $table ) ); } }