• File: CacheBase.php
  • Full Path: /home/matthif/www/wp-content/plugins/wpforms-lite/src/Helpers/CacheBase.php
  • Date Modified: 02/16/2024 11:45 AM
  • File size: 7.07 KB
  • MIME-type: text/x-php
  • Charset: utf-8
<?php

namespace WPForms\Helpers;

use 
WPForms\Tasks\Tasks;
use 
WPForms\Helpers\File;

/**
 * Remote data cache handler.
 *
 * Usage example in `WPForms\Admin\Addons\AddonsCache` and `WPForms\Admin\Builder\TemplatesCache`.
 *
 * @since 1.6.8
 */
abstract class CacheBase {

    
/**
     * Indicates whether the cache was updated during the current run.
     *
     * @since 1.6.8
     *
     * @var bool
     */
    
protected static $updated false;

    
/**
     * Settings.
     *
     * @since 1.6.8
     *
     * @var array
     */
    
protected $settings;

    
/**
     * Cache key.
     *
     * @since 1.8.2
     *
     * @var string
     */
    
private $cache_key;

    
/**
     * Cache dir.
     *
     * @since 1.8.2
     *
     * @var string
     */
    
private $cache_dir;

    
/**
     * Cache file.
     *
     * @since 1.8.2
     *
     * @var string
     */
    
private $cache_file;

    
/**
     * Determine if the class is allowed to load.
     *
     * @since 1.6.8
     *
     * @return bool
     */
    
abstract protected function allow_load();

    
/**
     * Initialize.
     *
     * @since 1.6.8
     */
    
public function init() {

        
// Init settings before allow_load() as settings are used in get().
        
$this->update_settings();

        
$this->cache_key  $this->settings['cache_file'];
        
$this->cache_dir  $this->get_cache_dir(); // See comment in the method.
        
$this->cache_file $this->cache_dir $this->settings['cache_file'];

        if ( ! 
$this->allow_load() ) {
            return;
        }

        
// Quit if settings wasn't provided.
        
if (
            empty( 
$this->settings['remote_source'] ) ||
            empty( 
$this->settings['cache_file'] )
        ) {
            return;
        }

        
$this->hooks();
    }

    
/**
     * Base hooks.
     *
     * @since 1.6.8
     */
    
private function hooks() {

        
add_action'shutdown', [ $this'cache_dir_complete' ] );

        if ( empty( 
$this->settings['update_action'] ) ) {
            return;
        }

        
// Schedule recurring updates.
        
add_action'admin_init', [ $this'schedule_update_cache' ] );
        
add_action$this->settings['update_action'], [ $this'update' ] );
    }

    
/**
     * Set up settings.
     *
     * @since 1.6.8
     */
    
private function update_settings() {

        
$default_settings = [

            
// Remote source URL.
            // For instance: 'https://wpforms.com/wp-content/addons.json'.
            
'remote_source' => '',

            
// Cache file.
            // Just file name. For instance: 'addons.json'.
            
'cache_file'    => '',

            
// Cache time to live in seconds.
            
'cache_ttl'     => WEEK_IN_SECONDS,

            
// Scheduled update action.
            // For instance: 'wpforms_admin_addons_cache_update'.
            
'update_action' => '',
        ];

        
$this->settings wp_parse_args$this->setup(), $default_settings );
    }

    
/**
     * Provide settings.
     *
     * @since 1.6.8
     *
     * @return array Settings array.
     */
    
abstract protected function setup();

    
/**
     * Get cache directory path.
     *
     * @since 1.6.8
     *
     * @return string
     */
    
protected function get_cache_dir() {

        return 
File::get_cache_dir();
    }

    
/**
     * Get data from cache or from API call.
     *
     * @since 1.8.2
     *
     * @return array
     */
    
public function get() {

        if ( 
$this->is_invalid_cache() || $this->is_expired_cache() ) {
            
$this->update();
        }

        return 
$this->get_from_cache();
    }

    
/**
     * Determine if the cache is expired.
     *
     * @since 1.8.2
     *
     * @return bool
     */
    
private function is_expired_cache(): bool {
        
// phpcs:ignore WPForms.Formatting.EmptyLineBeforeReturn.RemoveEmptyLineBeforeReturnStatement
        
return $this->cache_time() + $this->settings['cache_ttl'] < time();
    }

    
/**
     * Determine if the cache is expired.
     *
     * @since 1.8.2
     *
     * @return bool
     */
    
private function is_invalid_cache() {

        return empty( 
$this->get_from_cache() );
    }

    
/**
     * Get cache creation time.
     *
     * @since 1.8.2
     *
     * @return int
     */
    
private function cache_time() {

        return (int) 
Transient::get$this->cache_key );
    }

    
/**
     * Determine if the cache file exists.
     *
     * @since 1.8.2
     *
     * @return bool
     */
    
private function exists() {

        return 
is_file$this->cache_file ) && is_readable$this->cache_file );
    }

    
/**
     * Get cache from cache file.
     *
     * @since 1.8.2
     *
     * @return array
     */
    
private function get_from_cache() {

        if ( ! 
$this->exists() ) {
            return [];
        }

        return (array) 
json_decodeFile::get_contents$this->cache_file ), true );
    }

    
/**
     * Update cache.
     *
     * @since 1.8.2
     *
     * @param bool $force Force update.
     *
     * @return bool
     */
    
public function update$force false ) {

        if (
            ! 
$force &&
            
time() < $this->cache_time() + 15 MINUTE_IN_SECONDS
        
) {
            return 
false;
        }

        
Transient::set$this->cache_keytime(), $this->settings['cache_ttl'] );

        if ( ! 
wp_mkdir_p$this->cache_dir ) ) {
            return 
false;
        }

        
$data $this->perform_remote_request();

        
// phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_file_put_contents
        
if ( File::put_contents$this->cache_filewp_json_encode$data ) ) === false ) {
            return 
false;
        }

        
self::$updated true;

        return 
true;
    }

    
/**
     * Get cached data.
     *
     * @since 1.6.8
     * @deprecated 1.8.2
     *
     * @return array Cached data.
     * @noinspection PhpUnused
     */
    
public function get_cached() {

        
_deprecated_function__METHOD__'1.8.2 of the WPForms plugin'__CLASS__ '::get()' );

        return 
$this->get();
    }

    
/**
     * Update cached data with actual data retrieved from the remote source.
     *
     * @since 1.6.8
     * @deprecated 1.8.2
     *
     * @return array
     * @noinspection PhpUnused
     */
    
public function update_cache() {

        
_deprecated_function__METHOD__'1.8.2 of the WPForms plugin' );

        
$this->update();

        return 
$this->get();
    }

    
/**
     * Get data from API.
     *
     * @since 1.8.2
     *
     * @return array
     */
    
private function perform_remote_request() {

        
$wpforms_key wpforms()->is_pro() ? wpforms_get_license_key() : 'lite';

        
$request wp_remote_get(
            
add_query_arg'tgm-updater-key'$wpforms_key$this->settings['remote_source'] ),
            [
                
'timeout'    => 10,
                
'user-agent' => wpforms_get_default_user_agent(),
            ]
        );

        if ( 
is_wp_error$request ) ) {
            return [];
        }

        
$json wp_remote_retrieve_body$request );

        if ( empty( 
$json ) ) {
            return [];
        }

        return 
$this->prepare_cache_datajson_decode$jsontrue ) );
    }

    
/**
     * Schedule updates.
     *
     * @since 1.6.8
     */
    
public function schedule_update_cache() {

        
// Just skip if not need to register scheduled action.
        
if ( empty( $this->settings['update_action'] ) ) {
            return;
        }

        
$tasks wpforms()->get'tasks' );

        if (
            ! 
$tasks instanceof Tasks ||
            
$tasks->is_scheduled$this->settings['update_action'] ) !== false
        
) {
            return;
        }

        
$tasks->create$this->settings['update_action'] )
            ->
recurringtime() + $this->settings['cache_ttl'], $this->settings['cache_ttl'] )
            ->
params()
            ->
register();
    }

    
/**
     * Complete the cache directory.
     *
     * @since 1.6.8
     */
    
public function cache_dir_complete() {

        if ( ! 
self::$updated ) {
            return;
        }

        
wpforms_create_upload_dir_htaccess_file();
        
wpforms_create_index_html_file$this->cache_dir );
    }

    
/**
     * Prepare data to store in a local cache.
     *
     * @since 1.6.8
     *
     * @param array $data Raw data received by the remote request.
     *
     * @return array Prepared data for caching.
     */
    
protected function prepare_cache_data$data ) {

        if ( empty( 
$data ) || ! is_array$data ) ) {
            return [];
        }

        return 
$data;
    }
}