outputFormat = $format; return $this; } /** * Generate the full table name with prefix for JOIN operations. * * @param string $tableName The raw table name without prefix. * @return string The full prefixed table name. * @throws \InvalidArgumentException If the table name is empty. */ protected function getFullJoinTableName($tableName) { if (empty($tableName)) { throw new \InvalidArgumentException('Join table name must be set before proceeding.'); } /** * Filter the prefix segment used between wpdb prefix and table name. * * @param string $prefix The default 'statistics' (no trailing underscore). * @param string $tableName The logical table name. */ $tableNamePrefix = apply_filters('wp_statistics_table_prefix', 'statistics', $tableName); return $this->wpdb->prefix . $tableNamePrefix . '_' . $tableName; } /** * Executes the SELECT query based on arguments. * * @return $this * @throws RuntimeException if the query fails. */ public function execute() { try { $this->ensureConnection(); $this->validateTableName(); $this->setFullTableName(); if (empty($this->args['columns'])) { throw new RuntimeException("No columns specified for SELECT query."); } // Build SELECT statement dynamically $columns = implode(', ', $this->args['columns']); $sql = "SELECT {$columns} FROM {$this->fullName}"; if (!empty($this->args['joins']) && is_array($this->args['joins'])) { foreach ($this->args['joins'] as $join) { if (!isset($join['table'], $join['on'], $join['type'])) { throw new RuntimeException("Invalid JOIN configuration."); } $joinTable = $this->getFullJoinTableName($join['table']); $joinAlias = isset($join['alias']) ? $join['alias'] : $join['table']; $sql .= " {$join['type']} JOIN {$joinTable} AS {$joinAlias} ON {$join['on']}"; } } // Add WHERE clause if provided $params = []; $whereClauses = []; $connector = strtoupper($this->args['raw_where_type'] ?? 'AND'); if (!empty($this->args['where'])) { foreach ($this->args['where'] as $column => $value) { $whereClauses[] = "`$column` = %s"; $params[] = $value; } } // Add WHERE IN clause if provided if (!empty($this->args['where_in'])) { foreach ($this->args['where_in'] as $column => $values) { if (!is_array($values) || empty($values)) { throw new RuntimeException("Invalid value for WHERE IN clause."); } $placeholders = implode(',', array_fill(0, count($values), '%s')); $whereClauses[] = "`$column` IN ($placeholders)"; foreach ($values as $value) { $params[] = $value; } } } if (!empty($this->args['raw_where']) && is_array($this->args['raw_where'])) { foreach ($this->args['raw_where'] as $condition) { if (!empty($condition) && is_string($condition)) { $whereClauses[] = "($condition)"; } } } // Add WHERE conditions to SQL query if (!empty($whereClauses)) { $sql .= ' WHERE ' . implode(" $connector ", $whereClauses); } // Add GROUP BY clause if provided if (!empty($this->args['group_by'])) { $sql .= " GROUP BY {$this->args['group_by']}"; } // Add ORDER BY clause if provided if (!empty($this->args['order_by'])) { $sql .= " ORDER BY {$this->args['order_by']}"; } // Add LIMIT clause if provided if (!empty($this->args['limit']) && is_array($this->args['limit']) && count($this->args['limit']) === 2) { $sql .= " LIMIT %d OFFSET %d"; $params[] = $this->args['limit'][0]; $params[] = $this->args['limit'][1]; } // Prepare the query with parameters if (!empty($params)) { array_unshift($params, $sql); $preparedQuery = call_user_func_array([$this->wpdb, 'prepare'], $params); } else { $preparedQuery = $sql; } // Execute the query $this->result = $this->wpdb->get_results($preparedQuery, $this->outputFormat); if ($this->result === false) { throw new RuntimeException("Database query failed: " . $this->wpdb->last_error); } return $this; } catch (Exception $e) { throw new RuntimeException("SELECT operation failed: " . $e->getMessage()); } } /** * Returns the result of the executed query. * * @return array|null The query result. */ public function getResult() { return $this->result; } }