Jake Vanderwerf
2 days ago 235ce5716edc2f7cbe80fdccf26eac7269587839
inc/managers/ErrorHandler.php
@@ -12,8 +12,6 @@
class ErrorHandler
{
    protected object $wpdb;
   protected string $tableName;
    protected int $notification_threshold = 5; // Critical errors within 1 hour
    protected array $error_levels = [
@@ -24,11 +22,14 @@
        'critical' => 4
    ];
   protected CustomTable $table;
    public function __construct()
    {
        global $wpdb;
        $this->wpdb = $wpdb;
      $this->tableName = $wpdb->prefix . BASE . 'error_log';
      $this->defineTables();
//        global $wpdb;
//        $this->wpdb = $wpdb;
//    $this->tableName = $wpdb->prefix . BASE . 'error_log';
        add_filter(BASE.'handle_bulk_operation', [$this, 'processOperation'], 10, 3);
@@ -39,6 +40,35 @@
//        add_filter(BASE.'admin_action_filter', [$this, 'adminActionFilter'], 10, 3);
    }
   public function defineTables():void
   {
      $table = CustomTable::for('error_log');
      $table->setColumns([
         'id'        => 'bigint(20) unsigned NOT NULL AUTO_INCREMENT',
         'error_type'   => 'varchar(50) NOT NULL',
         'component'    => 'varchar(100) NOT NULL',
         'method'    => 'varchar(100) DEFAULT NULL',
         'page_url'     => 'varchar(255) DEFAULT NULL',
         'message'      => 'text NOT NULL',
         'context'      => 'JSON',
         'severity'     => 'ENUM(\'high\',\'normal\',\'low\') DEFAULT \'normal\'',
         'user_id'      => $table->getUserIDType().' DEFAULT NULL',
         'user_was_logged_in' => 'tinyint(1) NOT NULL',
         'source'    => 'ENUM(\'frontend\', \'backend\') NOT NULL',
         'created_at'   => 'timestamp DEFAULT CURRENT_TIMESTAMP',
      ]);
      $table->setKeys([
         ['key' => 'PRIMARY', 'value' => 'id'],
         '`created_at` (`created_at`)',
         '`component_severity_date` (`component`, `severity`, `created_at`)',
         '`error_type_date` (`error_type`, `created_at`)',
         '`severity_date` (`severity`, `created_at`)'
      ]);
      $table->defineTable();
      $this->table = $table;
   }
    public function registerAdminAction():void
    {
        $admin = JVB()->admin();
@@ -68,7 +98,7 @@
        }
        try {
            $table = $this->tableName;
            // Extract error data
            $component = sanitize_text_field($data['component'] ?? '');
            $message = sanitize_textarea_field($data['message'] ?? '');
@@ -94,8 +124,7 @@
            }
            // Insert into database
            $result = $this->wpdb->insert(
                $table,
            $result = $this->table->insert(
                [
                    'error_type' => $error_type,
                    'component' => $component,
@@ -104,24 +133,15 @@
                    'severity' => $severity,
                    'user_id' => get_current_user_id(),
                    'created_at' => current_time('mysql')
                ],
                [
                    '%s', // error_type
                    '%s', // component
                    '%s', // message
                    '%s', // context (JSON)
                    '%s', // severity
                    '%d', // user_id
                    '%s'  // created_at
                ]
            );
            if ($result === false) {
            if (!$result) {
                // If insert fails, log to PHP error log as fallback
                error_log("[ErrorHandler] Database insert failed: " . $this->wpdb->last_error);
                error_log("[ErrorHandler] Database insert failed: " . $this->table->getLastError());
                return [
               'success'   => false,
               'message'   => "[ErrorHandler] Database insert failed: " . $this->wpdb->last_error
               'message'   => "[ErrorHandler] Database insert failed: " . $this->table->getLastError()
            ];
            }
@@ -155,19 +175,15 @@
    protected function checkErrorThreshold(string $error_type, string $component)
    {
        // Get count of similar critical errors in the last hour
        $count = $this->wpdb->get_var($this->wpdb->prepare(
            "SELECT COUNT(*)
         FROM {$this->tableName}
         WHERE error_type = %s
         AND component = %s
         AND severity = 'critical'
         AND created_at > DATE_SUB(NOW(), INTERVAL 1 HOUR)",
            $error_type,
            $component
        ));
      $count = $this->table->count([
         'error_type' => $error_type,
         'component' => $component,
         'severity' => $this->error_levels[$error_type],
         'created_at' => ['>','DATE_SUB(NOW(), INTERVAL 1 HOUR)']
      ]);
        // If threshold reached, take additional actions (e.g., notify developers)
        if ((int)$count >= $this->notification_threshold) {
        if ($count >= $this->notification_threshold) {
            // You could send an urgent notification, Slack message, etc.
            $admin_email = get_option('admin_email');
            $subject = "[URGENT] Error Threshold Exceeded for {$component}";
@@ -189,8 +205,6 @@
   public function log(string $component, string $message, array $context = [], string $severity = 'error'): array
   {
      try {
         $table = $this->wpdb->prefix . BASE . 'error_log';
         // Validate severity
         if (!array_key_exists($severity, $this->error_levels)) {
            $severity = 'error';
@@ -207,8 +221,7 @@
         $source = isset($context['source']) ? $context['source'] :
            (isset($context['url']) ? 'frontend' : 'backend');
         $result = $this->wpdb->insert(
            $table,
         $result = $this->table->insert(
            [
               'error_type' => $error_type,
               'component' => $component,
@@ -221,20 +234,18 @@
               'user_was_logged_in' => $user_was_logged_in ? 1 : 0,
               'source' => $source,
               'created_at' => current_time('mysql')
            ],
            ['%s', '%s', '%s', '%s', '%s', '%s', '%s', '%d', '%d', '%s', '%s']
         );
            ]);
         if ($result === false) {
            error_log("[ErrorHandler] Database insert failed: " . $this->wpdb->last_error);
            return ['success' => false, 'message' => $this->wpdb->last_error];
         if (!$result) {
            error_log("[ErrorHandler] Database insert failed: " . $this->table->getLastError());
            return ['success' => false, 'message' => $this->table->getLastError()];
         }
         if ($severity === 'critical') {
            $this->checkErrorThreshold($error_type, $component);
         }
         return ['success' => true, 'id' => $this->wpdb->insert_id];
         return ['success' => true, 'id' => $result];
      } catch (Exception $e) {
         error_log("[ErrorHandler Exception] " . $e->getMessage());
@@ -283,8 +294,6 @@
     */
   public function gatherErrorSummary(?string $start_date = null, ?string $end_date = null): array
   {
      $table = $this->wpdb->prefix . BASE . 'error_log';
      if (!$start_date) {
         $start_date = gmdate('Y-m-d 00:00:00', strtotime('-1 day'));
      }
@@ -293,72 +302,14 @@
      }
      // Most frequent error patterns (deduplicated by component/method/message)
      $frequent = $this->wpdb->get_results($this->wpdb->prepare(
         "SELECT
            component,
            method,
            error_type,
            message,
            severity,
            source,
            COUNT(*) as count,
            SUM(CASE WHEN user_was_logged_in = 1 THEN 1 ELSE 0 END) as logged_in_count,
            SUM(CASE WHEN user_was_logged_in = 0 THEN 1 ELSE 0 END) as logged_out_count,
            MIN(created_at) as first_seen,
            MAX(created_at) as last_seen
         FROM {$table}
         WHERE created_at BETWEEN %s AND %s
         GROUP BY component, method, error_type, message, severity, source
         ORDER BY count DESC, severity DESC
         LIMIT 10",
         $start_date,
         $end_date
      ));
      // Critical errors
      $critical = $this->wpdb->get_results($this->wpdb->prepare(
         "SELECT
            component,
            method,
            error_type,
            message,
            source,
            COUNT(*) as count,
            SUM(CASE WHEN user_was_logged_in = 1 THEN 1 ELSE 0 END) as logged_in_count,
            SUM(CASE WHEN user_was_logged_in = 0 THEN 1 ELSE 0 END) as logged_out_count,
            MIN(created_at) as first_seen,
            MAX(created_at) as last_seen
         FROM {$table}
         WHERE created_at BETWEEN %s AND %s AND severity = 'critical'
         GROUP BY component, method, error_type, message, source
         ORDER BY count DESC
         LIMIT 5",
         $start_date,
         $end_date
      ));
      // Overall stats
      $stats = $this->wpdb->get_row($this->wpdb->prepare(
         "SELECT
            COUNT(*) as total_errors,
            COUNT(DISTINCT CONCAT(component, '-', COALESCE(method, ''), '-', error_type)) as unique_error_types,
            SUM(CASE WHEN user_was_logged_in = 1 THEN 1 ELSE 0 END) as logged_in_errors,
            SUM(CASE WHEN user_was_logged_in = 0 THEN 1 ELSE 0 END) as logged_out_errors,
            SUM(CASE WHEN source = 'frontend' THEN 1 ELSE 0 END) as frontend_errors,
            SUM(CASE WHEN source = 'backend' THEN 1 ELSE 0 END) as backend_errors,
            SUM(CASE WHEN severity = 'critical' THEN 1 ELSE 0 END) as critical_count,
            SUM(CASE WHEN severity = 'error' THEN 1 ELSE 0 END) as error_count,
            SUM(CASE WHEN severity = 'warning' THEN 1 ELSE 0 END) as warning_count
         FROM {$table}
         WHERE created_at BETWEEN %s AND %s",
         $start_date,
         $end_date
      ));
      $frequent = $this->table->getMany([
         'where' => [
            'created_at'   => ['BETWEEN', "{$start_date} AND {$end_date}"]
         ]
      ]);
      return [
         'frequent' => $frequent,
         'critical' => $critical,
         'stats' => $stats,
         'errors' => $frequent,
         'date_range' => ['start' => $start_date, 'end' => $end_date]
      ];
   }