Jake Vanderwerf
2026-09-18 a6413da67a4579866f0fd0323ddb23a7b6b9654a
inc/managers/CustomTable.php
@@ -2,6 +2,7 @@
namespace JVBase\managers;
use Exception;
use JVBase\inc\managers\ErrorHelper;
use wpdb;
if (!defined('ABSPATH')) {
@@ -20,10 +21,11 @@
 */
class CustomTable
{
   use ErrorHelper;
   private static ?wpdb $wpdb = null;
   private static string $prefix;
   protected string $tableName;
   protected bool $table_exists = false;
   protected string $definition;
   protected string $fullTableName;
   protected bool $useTransactions;
@@ -48,21 +50,27 @@
   /**
    * Fluent factory method
    *
    * @param string $tableName Table name without prefix/BASE
    * @param string $tableName
    * @param bool $user
    * @param bool $auth
    * @param bool $useTransactions
    * @return self
    *
    * @example CustomTable::for('favourites')->insert($data);
    */
   public static function for(string $tableName, bool $user = false, bool $auth = false, bool $useTransactions = false): self
   {
      if (!isset(self::$instances[$tableName])) {
         self::$instances[$tableName] = new self($tableName, $user, $auth, $useTransactions);
         self::$instances[$tableName]->setFlags();
      }
      return self::$instances[$tableName];
   }
      protected function setFlags():void
      {
         $this->table_exists = !is_null(self::$wpdb->get_var("SHOW TABLES LIKE '{$this->fullTableName}'"));
      }
   public static function destroyInstance(string $tableName):void
   {
@@ -229,7 +237,7 @@
      require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
      foreach (self::$instances as $instance) {
         if (!$instance->wpdb->get_var("SHOW TABLES LIKE '{$instance->fullTableName}'")) {
         if (!$instance->table_exists) {
            $instance->createTable();
         }
      }
@@ -241,7 +249,7 @@
         error_log('[CustomTable]No definition set for '.$this->tableName);
         return;
      }
      if (self::$wpdb->get_var("SHOW TABLES LIKE '{$this->fullTableName}'")) {
      if ($this->table_exists) {
         return;
      }
      require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
@@ -263,7 +271,7 @@
         $error_msg = "SQL Error creating table {$this->tableName}: " . self::$wpdb->last_error;
         error_log($error_msg);
         error_log("Failed SQL Query: " . $schema);
      } elseif (self::$wpdb->get_var("SHOW TABLES LIKE '{$this->fullTableName}'")) {
      } else {
         error_log("Successfully created table: {$this->fullTableName}");
      }
   }
@@ -500,7 +508,7 @@
      );
      if ($result === false) {
         $this->logError('insert', $data);
         $this->logError(self::$wpdb->last_error, 'insert', $data);
         return false;
      }
@@ -524,17 +532,15 @@
   /**
    * Find or create a record
    *
    * @param array $searchData Data to search for
    * @param array $createData Optional additional data for creation
    * @return array ['id' => int, 'created' => bool, 'record' => object]
    * @return int|false The ID of the created record, or false
    *
    * @example
    * $result = CustomTable::for('favourites')->findOrCreate(
    *     ['user_id' => 1, 'target_id' => 123],
    *     ['type' => 'tattoo']
    * );
    * // Returns: ['id' => 456, 'created' => false, 'record' => object]
    *  $result = CustomTable::for('favourites')->findOrCreate(
    *      ['user_id' => 1, 'target_id' => 123],
    *      ['type' => 'tattoo']
    *  );
    */
   public function findOrCreate(array $searchData, array $createData = []):int|false
   {
@@ -603,7 +609,7 @@
      $result = self::$wpdb->query(self::$wpdb->prepare($query, $values));
      if ($result === false) {
         $this->logError('bulkInsert', ['rows' => count($rows)]);
         $this->logError(self::$wpdb->last_error, 'bulkInsert', ['rows' => count($rows)]);
         return false;
      }
@@ -641,18 +647,17 @@
   /**
    * Get multiple records
    *
    * @param array $args Query arguments: where, orderby, order, limit, offset
    * @param bool $itemsOnly
    * @param string $output OBJECT, ARRAY_A, or ARRAY_N
    * @return array
    *
    * @example
    * $favs = $table->getMany([
    *     'where' => ['user_id' => 1],
    *     'orderby' => 'date_added',
    *     'order' => 'DESC',
    *     'per_page' => 20
    * ]);
    *  $favs = $table->getMany([
    *      'where' => ['user_id' => 1],
    *      'orderby' => 'date_added',
    *      'order' => 'DESC',
    *      'per_page' => 20
    *  ]);
    */
   public function getMany(array $args = [], bool $itemsOnly = true, string $output = OBJECT): array
   {
@@ -734,11 +739,13 @@
      return sanitize_sql_orderby($orderby);
   }
   /**
    * Get a specific column value from all matches
    * @param string $column
    * @param array $where
    * @param string|null $orderby
    * @param string|null $order
    * @param int|null $limit
    * @return array
    */
   public function pluck(string $column, array $where = [], ?string $orderby = null, ?string $order = null, ?int $limit = null): array
@@ -749,7 +756,7 @@
         $key,
         function() use ($column, $where, $orderby, $order, $limit) {
            if (!empty($this->columns) && !array_key_exists($column, $this->columns)) {
               $this->logError('pluck', ['reason' => "Column '{$column}' not in definition"]);
               $this->logError("Column '{$column}' not in definition", 'pluck');
               return [];
            }
            $args = ['where' => $where];
@@ -845,7 +852,7 @@
      );
      if ($result === false) {
         $this->logError('update', ['data' => $data, 'where' => $where]);
         $this->logError(self::$wpdb->last_error,'update', ['data' => $data, 'where' => $where]);
      }
      $this->cache->flush();
@@ -875,7 +882,7 @@
      );
      if ($result === false) {
         $this->logError('delete', ['where' => $where]);
         $this->logError(self::$wpdb->last_error, 'delete', ['where' => $where]);
      }
      $this->cache->flush();
@@ -999,7 +1006,7 @@
         return $result;
      } catch (Exception $e) {
         $this->rollback();
         $this->logError('transaction', ['error' => $e->getMessage()]);
         $this->logError(self::$wpdb->last_error,'transaction', ['error' => $e->getMessage()]);
         return false;
      }
   }
@@ -1186,22 +1193,6 @@
      return isset($cache[$this->tableName][$column]);
   }
   /**
    * Log database errors
    */
   private function logError(string $operation, array $context = []): void
   {
      if (function_exists('JVB')) {
         Errors::getInstance()->log(
            $this->tableName,
            "CustomTable {$operation} failed: " . self::$wpdb->last_error,
            $context
         );
      } else {
         error_log("[CustomTable:{$this->tableName}] {$operation} failed: " . self::$wpdb->last_error);
      }
   }
   public function sum(string $column, array $where):float
   {
      $rows = $this->pluck($column, $where);