AlkantarClanX12

Your IP : 216.73.217.24


Current Path : /www/capitalgmcbuickregina_830/public/wp-content/plugins/leadbox/lib/
Upload File :
Current File : /www/capitalgmcbuickregina_830/public/wp-content/plugins/leadbox/lib/class-inventory-manager.php

<?php
/**
 * Inventory Manager - Request-level caching for inventory data
 *
 * Ensures inventory.json is only read ONCE per request
 *
 * CRITICAL PERFORMANCE FIX:
 * - Problem: Theme calls get_inventory() 4-720 times per page load
 * - Each call reads 1.0MB file from disk, parses 28,291 lines of JSON
 * - Impact: Model pages alone = 59.25GB/day waste
 *
 * Solution: Request-level caching (NOT persistent caching)
 * - First call in request: Reads from disk (fresh data)
 * - Subsequent calls in SAME request: Returns cached data (no disk read)
 * - Next page load: Reads from disk again (always fresh data)
 *
 * @package LBX
 */

// Exit if accessed directly.
if (!defined('ABSPATH')) {
    exit;
}

class LB_Inventory_Manager {
    private static $instance = null;
    private $inventory_cache = null;
    private $vehicle_cache = [];

    /**
     * Get singleton instance
     *
     * @return LB_Inventory_Manager
     */
    public static function getInstance() {
        if (self::$instance === null) {
            self::$instance = new self();
        }
        return self::$instance;
    }

    /**
     * Private constructor prevents direct instantiation
     */
    private function __construct() {
        // Private constructor for singleton pattern
    }

    /**
     * Get inventory data (cached for current request only)
     *
     * IMPORTANT: This is request-level caching, NOT persistent caching.
     * - First call: Reads from disk (fresh data)
     * - Subsequent calls in SAME request: Returns cached data
     * - Next page load: Reads from disk again (always fresh)
     *
     * @return array|null Inventory data or null on failure
     */
    public function get_inventory() {
        // Return cached data if already loaded THIS request
        if ($this->inventory_cache !== null) {
            return $this->inventory_cache;
        }

        // Read from disk (first call of THIS request)
        // Check for idiom-specific inventory file first (matches original logic)
        $json_path = wp_get_upload_dir()['basedir'] . '/data/inventory';
        $idiom_path = $this->makeUrl($json_path);

        if (file_exists($idiom_path)) {
            $json = file_get_contents($idiom_path);
            if ($json === false) {
                leadbox_logger()->error('Failed to read inventory file', array(
                    'file' => $idiom_path,
                ));
                return null;
            }

            $data = json_decode($json, true);
            if ($data === null) {
                leadbox_logger()->error('Failed to parse inventory JSON', array(
                    'file' => $idiom_path,
                    'json_error' => json_last_error_msg(),
                ));
                return null;
            }

            // Cache for remainder of request
            $this->inventory_cache = $data;
            return $data;
        }

        // Fallback to default inventory.json
        $file = wp_get_upload_dir()['basedir'] . '/data/inventory.json';

        if (!file_exists($file)) {
            leadbox_logger()->error('Inventory file not found', array(
                'file' => $file,
            ));
            return null;
        }

        $json = file_get_contents($file);
        if ($json === false) {
            leadbox_logger()->error('Failed to read inventory file', array(
                'file' => $file,
            ));
            return null;
        }

        $data = json_decode($json, true);
        if ($data === null) {
            leadbox_logger()->error('Failed to parse inventory JSON', array(
                'file' => $file,
                'json_error' => json_last_error_msg(),
            ));
            return null;
        }

        // Cache for remainder of request
        $this->inventory_cache = $data;

        return $data;
    }

    /**
     * Get individual vehicle by ID
     *
     * Always reads individual vehicle file (has full data including description)
     *
     * @param string $id Vehicle stock number
     * @return array|null Vehicle data or null
     */
    public function get_vehicle_by_id($id) {
        // Check cache first
        if (isset($this->vehicle_cache[$id])) {
            return $this->vehicle_cache[$id];
        }

        // Individual vehicle files have FULL data (description, features, categories)
        // Always read individual file, don't use inventory.json
        $file = wp_get_upload_dir()['basedir'] . '/data/' . $id . '.json';

        if (!file_exists($file)) {
            // Fallback: try to find in inventory
            $inventory = $this->get_inventory();
            if ($inventory && isset($inventory['vehicles'])) {
                foreach ($inventory['vehicles'] as $vehicle) {
                    if ($vehicle['stocknumber'] === $id) {
                        $this->vehicle_cache[$id] = $vehicle;
                        return $vehicle;
                    }
                }
            }
            return null;
        }

        $json = file_get_contents($file);
        if ($json === false) {
            return null;
        }

        $vehicle = json_decode($json, true);
        if ($vehicle === null) {
            return null;
        }

        // Cache for remainder of request
        $this->vehicle_cache[$id] = $vehicle;

        return $vehicle;
    }

    /**
     * Clear cache (for testing or manual refresh)
     */
    public function clear_cache() {
        $this->inventory_cache = null;
        $this->vehicle_cache = [];
    }

    /**
     * Helper function to construct idiom-specific path
     * (matches original makeUrl logic from lib/functions.php)
     *
     * @param string $json_path Base path
     * @return string Idiom-specific path
     */
    private function makeUrl($json_path) {
        // Check if makeUrl function exists globally
        if (function_exists('makeUrl')) {
            return makeUrl($json_path);
        }

        // Fallback: try to construct idiom path manually
        // This matches common WordPress multilingual patterns
        if (function_exists('pll_current_language')) {
            $idiom = pll_current_language();
            return $json_path . '-' . $idiom . '.json';
        }

        return $json_path . '.json';
    }
}

/**
 * Global helper function for backward compatibility
 *
 * @return array|null Inventory data
 */
function lb_get_inventory() {
    return LB_Inventory_Manager::getInstance()->get_inventory();
}

/**
 * Global helper function for getting individual vehicles
 *
 * @param string $id Vehicle stock number
 * @return array|null Vehicle data
 */
function lb_get_vehicle_by_id($id) {
    return LB_Inventory_Manager::getInstance()->get_vehicle_by_id($id);
}