/** * Send a query to the database and retrieve the results * * Results can be formatted using 'auto', 'object' or 'array'. * * auto - Automatically detects 'object' and 'array' results (default) * object - Provides a single object as the result * array - Provides a list of records/objects * * Processing results can also be automated by specifying a record processor * function. A custom callback function can be provided using standard PHP * callback notation, or there are builtin record processing methods * supported that can be specified as a string in the callback * parameter: 'auto', 'index' or 'col' * * auto - Simply adds a record to the result set as a numerically indexed array of records * * index - Indexes record objects into an associative array using a given column name as the key * sDB::query('query', 'format', 'index', 'column', (bool)collate) * A column name is provided (4th argument) for the index key value * A 'collate' boolean flag can also be provided (5th argument) to collect records with identical index column values into an array * * col - Builds records as an associative array with a single column as the array value * sDB::query('query', 'format', 'column', 'indexcolumn', (bool)collate) * A column name is provided (4th argument) as the column for the array value * An index column name can be provided (5th argument) to index records as an associative array using the index column value as the key * A 'collate' boolean flag can also be provided (6th argument) to collect records with identical index column values into an array * * Collating records using the 'index' or 'col' record processors require an index column. * When a record's column value matches another record, the two records are collected into * a nested array. The results array will have a single entry where the key is the * index column's value and the value of the entry is an array of all the records that share * the index column value. * * @author Jonathan Davis * @since 1.0 * @version 1.2 * * @param string $query The SQL query to send * @param string $format (optional) Supports 'auto' (default), 'object', or 'array' * @return array|object The query results as an object or array of result rows **/ public static function query($query, $format = 'auto', $callback = false) { $db = sDB::get(); $args = func_get_args(); $args = count($args) > 3 ? array_slice($args, 3) : array(); if (SHOPP_QUERY_DEBUG) { $timer = microtime(true); } $result = $db->api->query($query); if (SHOPP_QUERY_DEBUG) { $db->queries[] = array($query, microtime(true) - $timer, sDB::caller()); } // Error handling if ($db->dbh && ($error = $db->api->error())) { shopp_add_error(sprintf('Query failed: %s - DB Query: %s', $error, str_replace("\n", "", $query)), SHOPP_DB_ERR); return false; } /** Results handling **/ // Handle special cases if (preg_match("/^\\s*(create|drop|insert|delete|update|replace) /i", $query)) { if (!$result) { return false; } $db->affected = $db->api->affected(); if (preg_match("/^\\s*(insert|replace) /i", $query)) { $insert = $db->api->object($db->api->query("SELECT LAST_INSERT_ID() AS id")); if (!empty($insert->id)) { return (int) $insert->id; } } if ($db->affected > 0) { return $db->affected; } else { return true; } } elseif (preg_match("/ SQL_CALC_FOUND_ROWS /i", $query)) { $rows = $db->api->object($db->api->query("SELECT FOUND_ROWS() AS found")); } // Default data processing if (is_bool($result)) { return (bool) $result; } // Setup record processing callback if (is_string($callback) && !function_exists($callback)) { $callback = array(__CLASS__, $callback); } // Failsafe if callback isn't valid if (!$callback || is_array($callback) && !method_exists($callback[0], $callback[1])) { $callback = array(__CLASS__, 'auto'); } // Process each row through the record processing callback $records = array(); while ($row = $db->api->object($result)) { call_user_func_array($callback, array_merge(array(&$records, &$row), $args)); } // Free the results immediately to save memory $db->api->free(); // Save the found count if it is present if (isset($rows->found)) { $db->found = (int) $rows->found; } // Handle result format post processing switch (strtolower($format)) { case 'object': return reset($records); break; case 'array': return $records; break; default: return count($records) == 1 ? reset($records) : $records; break; } }