public function __construct($args = null) { $args_default = array('max_offset' => 2147483646, 'server' => array('ip' => '127.0.0.1', 'port' => 6379, 'database' => 15, 'alias' => 'first')); $args = FOX_sUtil::parseArgs($args, $args_default); foreach ($args as $key => $var) { $this->{$key} = $var; } unset($key, $var); // Handle process-id binding // =========================================================== if (FOX_sUtil::keyExists('process_id', $args)) { // Binding to a reference is important. It makes the cache engine $process_id // update if the FOX_mCache is changed, which we do during unit testing. $this->process_id =& $args['process_id']; } else { global $fox; $this->process_id = $fox->process_id; } $this->has_libs = true; if ($this->enable == true) { require_once FOX_PATH_BASE . '/lib/predis/autoload.php'; $this->engine = new Predis\Client($this->server); $this->is_active = true; } }
public function __construct($ctrl = null) { $this->store = array(); $ctrl_default = array('prefix' => 'K'); $ctrl = FOX_sUtil::parseArgs($ctrl, $ctrl_default); $this->prefix = $ctrl['prefix']; }
/** * Implodes an array of heirarchical datastore keys into a single query $args array * * @version 1.0 * @since 1.0 * * @param array $trie | Trie structure * * @param array $columns | Array of column names * * @param array $ctrl | Control args * => VAL @param string $null_token | String to use as null token * * @return bool | Exception on failure. True on success. */ function __construct($trie, $columns, $ctrl = null) { $this->trie = $trie; $this->columns = $columns; $this->max_depth = count($columns); $ctrl_default = array('null_token' => '*'); $this->ctrl = FOX_sUtil::parseArgs($ctrl, $ctrl_default); $this->null_token = $this->ctrl['null_token']; return true; }
/** * Implodes an array of heirarchical datastore keys into a single query $args array * * @version 1.0 * @since 1.0 * * @param array $trie | Trie structure * @param array $columns | Array of column names * * @param array $ctrl | Control args * => VAL @param string $null_token | String to use as null token * * @return array | Exception on failure. True on success. */ function __construct($trie, $columns, $ctrl = null) { $this->trie = $trie; $this->columns = $columns; $ctrl_default = array('null_token' => '*', 'mode' => 'control'); $this->ctrl = FOX_sUtil::parseArgs($ctrl, $ctrl_default); $this->null_token = $this->ctrl['null_token']; $this->mode = $this->ctrl['mode']; if ($this->mode == 'data') { $this->data_key = array_pop($this->columns); } $this->max_depth = count($this->columns) - 1; try { $result = $this->build(); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 1, 'text' => "Error during build process", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => $child)); } return $result; }
/** * Implodes an array of heirarchical datastore keys into a single query $args array * * @version 1.0 * @since 1.0 * * @param array $columns | Array of column names * * @param array $args | Array of key arrays * => ARR @param int '' | Array containing "column_name"=>"value" * * @param array $ctrl | Control args * => VAL @param bool $optimize | True to optimize the $args matrix * => VAL @param string $prefix | Prefix to add to column names * => VAL @param bool $trap_null | Throw an exception if one or more walks * in the args array collapses to "WHERE 1 = 1" * * @return array | Exception on failure. True on success. */ function __construct($struct, $columns, $args, $ctrl = null) { $this->struct = $struct; $this->columns = $columns; $this->args = $args; $this->max_depth = count($columns) - 1; $ctrl_default = array('prefix' => '', 'optimize' => true, 'trap_null' => true, 'hash_token_vals' => true, 'null_token' => '*', 'mode' => 'matrix'); $this->ctrl = FOX_sUtil::parseArgs($ctrl, $ctrl_default); if ($this->ctrl['hash_token_vals'] == true) { $this->hash_table = new FOX_hashTable(); } $this->null_token = $this->ctrl['null_token']; $this->mode = $this->ctrl['mode']; try { $result = $this->build(); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 1, 'text' => "Error during build process", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => $child)); } return $result; }
/** * Validates a trie structure * * @version 1.0 * @since 1.0 * * @param array $data | trie structure to validate * * @param array $ctrl | Control parameters * => VAL @param int $order | Order of trie structure * => VAL @param string $mode | Operation mode 'control' | 'data' * => VAL @param bool $allow_wildcard | Allow wildcards (universal selector) to be used in control tries * => VAL @param string $wildcard_token | String to use as wildcard token * => VAL @param int $clip_order | Order to clip keys at when in 'data' mode * * @return bool/array | Exception on failure, (bool)true on success, (array)data_array on failure. */ public function validateTrie($data, $ctrl = null) { $ctrl_default = array('order' => $this->order, 'mode' => 'control', 'allow_wildcard' => false, 'wildcard_token' => '*', 'clip_order' => false); $ctrl = FOX_sUtil::parseArgs($ctrl, $ctrl_default); if ($ctrl['order'] > $this->order || $ctrl['order'] < 0) { throw new FOX_exception(array('numeric' => 1, 'text' => "Specified order is not valid", 'data' => array("order" => $ctrl['order'], "class_order" => $this->order), 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => null)); } if ($ctrl['mode'] != 'data' && $ctrl['mode'] != 'control') { throw new FOX_exception(array('numeric' => 2, 'text' => "Invalid 'mode' parameter", 'data' => array('ctrl' => $ctrl), 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => null)); } if ($ctrl['mode'] == 'data' && !is_int($ctrl['clip_order'])) { throw new FOX_exception(array('numeric' => 3, 'text' => "The 'clip_order' parameter must be set when operating in 'data' mode", 'data' => array('ctrl' => $ctrl), 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => null)); } if ($ctrl['mode'] == 'data' && $ctrl['allow_wildcard'] != false) { throw new FOX_exception(array('numeric' => 4, 'text' => "Wildcard selectors cannot be used in 'data' mode", 'data' => array('ctrl' => $ctrl), 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => null)); } try { if ($ctrl['order'] == 0) { // We're at L0 in a walk return true; } if (is_array($data) && !empty($data)) { foreach ($data as $parent_id => $children) { if (!($ctrl['allow_wildcard'] == true && $parent_id == $ctrl['wildcard_token'])) { $check_result = self::validateKey(array('type' => $this->order_dict[$ctrl['order']]['type'], 'format' => 'scalar', 'var' => $parent_id)); if ($check_result !== true) { return array('numeric' => 1, 'message' => $check_result, 'key' => $ctrl['order'], 'val' => $parent_id); } } $child_result = self::validateTrie($children, array('order' => $ctrl['order'] - 1, 'mode' => $ctrl['mode'], 'allow_wildcard' => $ctrl['allow_wildcard'], 'clip_order' => $ctrl['clip_order'])); if ($child_result !== true) { if (FOX_sUtil::keyExists('trace', $child_result)) { $trace = array_merge($child_result['trace'], array($ctrl['order'] => $parent_id)); } else { $trace = array($ctrl['order'] => $parent_id); } return array('numeric' => 2, 'message' => $child_result['message'], 'key' => $ctrl['order'], 'val' => $parent_id, 'trace' => $trace); } } unset($parent_id, $children); } else { if ($ctrl['mode'] == 'control') { if (!is_array($data) && (!is_bool($data) || $data === false)) { $message = "Each walk in a control trie must terminate with either (bool)true, "; $message .= "or an empty array, or must extend to the L1 key."; return array('numeric' => 3, 'message' => $message, 'key' => $ctrl['order'], 'val' => $parent_id); } else { return true; } } elseif ($ctrl['mode'] == 'data') { if ($ctrl['order'] == $ctrl['clip_order'] - 1) { if (!is_array($data) && (!is_bool($data) || $data === false)) { $message = "Each walk in a data trie, that terminates at the clip_order, must "; $message .= "terminate with an empty array."; return array('numeric' => 4, 'message' => $message, 'key' => $ctrl['order'], 'val' => $parent_id); } else { return true; } } else { $message = "Each walk in a data trie must terminate either at the clip_order "; $message .= "or at the L1 key."; return array('numeric' => 5, 'message' => $message, 'key' => $ctrl['order'], 'val' => $parent_id); } } } // ENDOF: if( is_array($data) && !empty($data) ) } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 5, 'text' => "Error in validator", 'data' => array("columns" => $this->order_dict), 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => $child)); } return true; }
/** * Strips ASCII and Latin1 control characters. Passes spaces. * * @version 1.0 * @since 1.0 * * @param string $input | input string to process * @param array $ctrl | control parameters * @return string | the processed string */ public function printableCharacter($input, $ctrl = null, &$valid = null, &$error = null) { $ctrl_default = array("null_input" => "null", "min_len" => 0, "max_len" => 50000); // crash on very large strings. For example, preg_replace() crashes // at about 94,000 characters. $ctrl = FOX_sUtil::parseArgs($ctrl, $ctrl_default); if ($input === null) { if ($ctrl["null_input"] == "null") { $valid = true; return null; } elseif ($ctrl["null_input"] == "trap") { $valid = false; $error = "null input value"; return null; } } else { // Make absolutely sure PHP treats the input data as a string $result = (string) $input; // We can't use the [:print:] character class because its a POSIX regex class and it's // not available in PHP's PCRE regex implementation (POSIX was deprecated in PHP 5.3). // Remove ASCII control characters $result = preg_replace('[\\x00-\\x1F\\x7F]', '', $result); // Remove Latin1 control characters $result = preg_replace('[\\x80-\\x9F]', '', $result); $len = strlen($result); // Handle string being zero length after trimming off padding characters if ($len == 0) { if ($ctrl["null_input"] == "null") { $valid = true; return null; } elseif ($ctrl["null_input"] == "trap") { $valid = false; $error = "null input value"; return null; } } // Truncate strings that exceed the max length if ($len > $ctrl["max_len"]) { $valid = true; $result = substr($result, 0, $ctrl["max_len"]); return $result; } elseif ($len < $ctrl["min_len"]) { $valid = false; $error = "string exceeds min_len"; return $result; } else { $valid = true; return $result; } } }
/** * Drops one or more items of the specified level from ALL WALKS in the datastore. * * @version 1.0 * @since 1.0 * @param int $level | Level to drop items from * @param int/string/array $items | Single item as int/string, multiple as array of int/string. * * @return int | Exception on failure. Number of rows changed on success. */ public function dropGlobal($level, $items, $ctrl = null) { if (!$this->init) { throw new FOX_exception(array('numeric' => 0, 'text' => "Descendent class must call init() before using class methods", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => null)); } if ($this->debug_on) { extract($this->debug_handler->event(array('pid' => $this->process_id, 'text' => "method_start", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'parent' => $this, 'vars' => compact(array_keys(get_defined_vars()))))); } $col = "L" . $level . "_col"; $ctrl_default = array("validate" => true); $ctrl = FOX_sUtil::parseArgs($ctrl, $ctrl_default); // Validate // =================================================== if ($ctrl['validate'] != false) { if ($this->debug_on) { extract($this->debug_handler->event(array('pid' => $this->process_id, 'text' => "validate_start", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'parent' => $this, 'vars' => compact(array_keys(get_defined_vars()))))); } // Each variable has to be validated individually. If we spin the variables // into a trie, PHP will automatically convert strings that map to ints ("17") // into (int) keys, which will defeat the validators $struct = $this->_struct(); try { $validator = new FOX_dataStore_validator($struct); // If a single item is sent in, we validate it *before* spinning it into an array, // so we can trap strings that PHP automatically converts to ints ("17") if (!is_array($items)) { $is_valid = $validator->validateKey(array('type' => $struct['columns'][$this->{$col}]['php'], 'format' => 'scalar', 'var' => $items)); } else { foreach ($items as $key => $val) { $is_valid = $validator->validateKey(array('type' => $struct['columns'][$this->{$col}]['php'], 'format' => 'scalar', 'var' => $val)); // Break the loop if we hit an invalid key if ($is_valid !== true) { break; } } unset($key, $val); } } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 1, 'text' => "Error in validator", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => $child)); } // This structure has to be outside the validator try-catch block to prevent it from // catching the exceptions we throw (which would cause confusing exception chains) if ($is_valid !== true) { throw new FOX_exception(array('numeric' => 2, 'text' => "Invalid item", 'data' => $is_valid, 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => null)); } if ($this->debug_on) { extract($this->debug_handler->event(array('pid' => $this->process_id, 'text' => "validate_end", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'parent' => $this, 'vars' => compact(array_keys(get_defined_vars()))))); } } // ENDOF: if($ctrl['validate'] != false){ // Lock the entire cache namespace // =========================================================== if ($this->debug_on) { extract($this->debug_handler->event(array('pid' => $this->process_id, 'text' => "persistent_cache_lock_start", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'parent' => $this, 'vars' => compact(array_keys(get_defined_vars()))))); } try { self::lockNamespace(); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 3, 'text' => "Error locking cache namespace", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => $child)); } if ($this->debug_on) { extract($this->debug_handler->event(array('pid' => $this->process_id, 'text' => "persistent_cache_lock_end", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'parent' => $this, 'vars' => compact(array_keys(get_defined_vars()))))); } if ($this->debug_on) { extract($this->debug_handler->event(array('pid' => $this->process_id, 'text' => "db_delete_start", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'parent' => $this, 'vars' => compact(array_keys(get_defined_vars()))))); } $args = array(array("col" => $this->{$col}, "op" => "=", "val" => $items)); try { $rows_changed = $this->db->runDeleteQuery($struct, $args, $ctrl = null); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 4, 'text' => "Error while deleting from database", 'data' => $args, 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => $child)); } if ($this->debug_on) { extract($this->debug_handler->event(array('pid' => $this->process_id, 'text' => "db_delete_end", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'parent' => $this, 'vars' => compact(array_keys(get_defined_vars()))))); } // Since this operation affects ALL L5 pages, we have to flush the // entire cache namespace if ($this->debug_on) { extract($this->debug_handler->event(array('pid' => $this->process_id, 'text' => "persistent_cache_flush_start", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'parent' => $this, 'vars' => compact(array_keys(get_defined_vars()))))); } try { self::flushCache(); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 5, 'text' => "Cache flush error", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => $child)); } if ($this->debug_on) { extract($this->debug_handler->event(array('pid' => $this->process_id, 'text' => "persisent_cache_flush_end", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'parent' => $this, 'vars' => compact(array_keys(get_defined_vars()))))); } if ($this->debug_on) { extract($this->debug_handler->event(array('pid' => $this->process_id, 'text' => "method_end", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'parent' => $this, 'vars' => compact(array_keys(get_defined_vars()))))); } return (int) $rows_changed; }
/** * Runs a DELETE query on one of the plugin's db tables. * * @version 1.0 * @since 1.0 * * @param array $struct | Structure of the db table, @see class FOX_db header for examples * * @param array $args | Args in the form: array("col"=>column_name, "op" => "<, >, =, !=", "val" => "int | string | array()") * => ARR @param int '' | Array index * => VAL @param string $col | Name of the column in the db table this key describes * => VAL @param string $op | SQL comparison operator to use: ">=" | "<=" | ">" | "<" | "=" | "!=" | "<>" * => VAL @param int/string/array $val | Value or values to test against. Single value as int/string. Multiple values as array. * * @param array $ctrl | Control parameters for the query * => VAL @param string $args_format | "default" to use standard format, "multi", "matrix", or "trie" * * @return int | Exception on failure. Int number of rows deleted on success. */ public function runDeleteQuery($struct, $args, $ctrl = null) { if ($this->debug_on) { extract($this->debug_handler->event(array('pid' => $this->process_id, 'text' => "method_start", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'parent' => $this, 'vars' => compact(array_keys(get_defined_vars()))))); } // Add default control params // ========================== $ctrl_default = array("args_format" => "default"); $ctrl = FOX_sUtil::parseArgs($ctrl, $ctrl_default); // Build query string // ======================= if ($this->debug_on) { extract($this->debug_handler->event(array('pid' => $this->process_id, 'text' => "build_query", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'parent' => $this, 'vars' => compact(array_keys(get_defined_vars()))))); } try { $query = $this->builder->buildDeleteQuery($struct, $args, $ctrl); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 1, 'text' => "Error in query generator", 'data' => array("struct" => $struct, "args" => $args, 'ctrl' => $ctrl), 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => $child)); } // Run on SQL server // ======================= if ($this->debug_on) { extract($this->debug_handler->event(array('pid' => $this->process_id, 'text' => "run_query", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'parent' => $this, 'vars' => compact(array_keys(get_defined_vars()))))); } try { $this->runner->runQuery($query, array('format' => 'var')); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 2, 'text' => "Error executing query on SQL server", 'data' => array("query" => $query), 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => $child)); } if ($this->debug_on) { extract($this->debug_handler->event(array('pid' => $this->process_id, 'text' => "method_end", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'parent' => $this, 'vars' => compact(array_keys(get_defined_vars()))))); } return $this->rows_affected; }
/** * Locks the class' entire namespace, giving the locking PID exclusive control of it. * * @version 1.0 * @since 1.0 * * @param array $ctrl | Control parameters * => VAL @param int $seconds | Time in seconds from present time until lock expires * * @return mixed | Exception on failure. True on success. */ public function lockNamespace($ctrl = null) { if ($this->debug_on) { extract($this->debug_handler->event(array('pid' => $this->process_id, 'text' => "method_start", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'parent' => $this, 'vars' => compact(array_keys(get_defined_vars()))))); } $struct = $this->_struct(); if ($struct['cache_strategy'] != 'paged') { throw new FOX_exception(array('numeric' => 1, 'text' => "This method can only be used on classes that use a paged cache", 'data' => array('struct' => $struct), 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => null)); } $ctrl_default = array('seconds' => 5); $ctrl = FOX_sUtil::parseArgs($ctrl, $ctrl_default); try { $result = $this->mCache->lockNamespace(array('process_id' => $this->process_id, 'engine' => $struct["cache_engine"], 'namespace' => $struct["cache_namespace"], 'seconds' => $ctrl['seconds'])); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 2, 'text' => "Error in mCache->lockNamespace()", 'data' => array('struct' => $struct), 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => $child)); } if ($this->debug_on) { extract($this->debug_handler->event(array('pid' => $this->process_id, 'text' => "method_end", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'parent' => $this, 'vars' => compact(array_keys(get_defined_vars()))))); } return $result; }
/** * Builds a delete query for processing by $wpdb->prepare(). * * @version 1.0 * @since 1.0 * * @param array $struct | Structure of the db table, @see class FOX_db header for examples * * @param array $args | Args in the form: array("col"=>column_name, "op" => "<, >, =, !=", "val" => "int | string | array()") * => ARR @param int '' | Array index * => VAL @param string $col | Name of the column in the db table this key describes * => VAL @param string $op | SQL comparison operator to use: ">=" | "<=" | ">" | "<" | "=" | "!=" | "<>" * => VAL @param int/string/array $val | Value or values to test against. Single value as int/string. Multiple values as array. * * @param array $ctrl | Control parameters for the query * => VAL @param string $args_format | "default" to use standard format, "multi", or "matrix" * * @return array | Exception on failure. Query array on success. */ public function buildDeleteQuery($struct, $args, $ctrl = null) { $ctrl_default = array('args_format' => 'default'); $ctrl = FOX_sUtil::parseArgs($ctrl, $ctrl_default); // Switch between unit test mode (pass as array) and // normal mode (pass as class name) // ==================================================== if (is_string($struct)) { $struct = call_user_func(array($struct, '_struct')); } // ==================================================== // Build WHERE statement // ###################################################### $where = "1 = 1"; // We need to pre-load it with a value in case the user adds zero 'where' conditions // Primary table args. The "if" clause handles the case where the user passes no args because // they do not want to constrain the query using a column in the primary table. if ($args) { try { switch ($ctrl['args_format']) { case "multi": $result = self::buildWhereMulti($struct, $args, __FUNCTION__, $prefix = null); break; case "matrix": // Forward the 'hash_token_vals' flag, if set if (FOX_sUtil::keyExists('hash_token_vals', $args)) { $matrix_ctrl = array('hash_token_vals' => $args['hash_token_vals']); } else { $matrix_ctrl = null; } $result = self::buildWhereMatrix($struct, $args["key_col"], $args["args"], $matrix_ctrl); break; case "trie": // Forward the 'hash_token_vals' flag, if set if (FOX_sUtil::keyExists('hash_token_vals', $args)) { $trie_ctrl = array('hash_token_vals' => $args['hash_token_vals']); } else { $trie_ctrl = null; } $result = self::buildWhereTrie($struct, $args["key_col"], $args["args"], $trie_ctrl); break; default: $result = self::buildWhere($struct, $args, __FUNCTION__, $prefix = null); break; } } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 1, 'text' => "Error in buildWhere generator", 'data' => array("struct" => $struct, "args" => $args, "ctrl" => $ctrl), 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => $child)); } $where .= $result['where']; $params_list = $result['params']; unset($result); } else { // From the MySQL site: "DELETE FROM tbl_name does not regenerate the table but instead deletes all rows, one by one." // @link http://dev.mysql.com/doc/refman/5.5/en/innodb-restrictions.html $text = "\nSAFTEY INTERLOCK TRIP [DESTROY TABLE] - buildDeleteQuery() called with no WHERE args. Running this query would delete "; $text .= " ALL rows in the target table. If this is what you really want to do, use buildTruncateTable().\n"; throw new FOX_exception(array('numeric' => 2, 'text' => $text, 'data' => array("struct" => $struct, "args" => $args, "ctrl" => $ctrl), 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => null)); } $query = "DELETE FROM " . $this->base_prefix . $struct["table"] . " WHERE " . $where; // Merge all return data into an array // ############################################################### $result = array('query' => $query, 'params' => $params_list); return $result; }
/** * Runs a query on the database. Returns results in a specific format. * * @version 1.0 * @since 1.0 * @link https://github.com/FoxFire/foxfirewiki/DOCS_FOX_db_select_formatter * * @param string $sql | SQL query string * * @param array $ctrl | Control parameters for the query * => VAL @param string $format | Return format for query: "col", "row", "var", "array_key_object", "array_key_array" * "array_key_single", "array_object", "array_array", "raw", or (null) * @see result formatter headers inside this method for detailed docs * * => VAL @see FOX_db::runSelectQuery() and FOX_db::runSelectQueryJoin() for docs on remaining $ctrl options * * @return bool | Exception on failure. Query results array on success. */ public function runQuery($query, $ctrl = null) { $ctrl_default = array('format' => 'raw'); $ctrl = FOX_sUtil::parseArgs($ctrl, $ctrl_default); if ($this->print_query_args == true) { ob_start(); print_r($query); print_r($ctrl); $out = ob_get_clean(); FOX_debug::addToFile($out); } // Handle single parameter as string/int, or multiple // parameters passed as an array // ================================================== if (is_array($query)) { $sql = $this->driver->prepare($query['query'], $query['params']); } else { $sql = $query; $query = array('types' => array()); $ctrl = array("format" => "raw"); } // TODO: This prevents PHP from throwing a warning in queryResult() when the table // builder methods run their queries (which have no return type), but it should be // improved to prevent queries that are accidentally missing return data types // from leaking through if (!array_key_exists('types', $query)) { $query['types'] = array(); } if ($this->print_query_sql == true) { FOX_debug::addToFile($sql); } // EXAMPLE TABLE "test_table" // ================================= // col_1 | col_2 | col_3 | col_4 | // ================================= // 1 | red | dog | big | // 2 | green| cat | med | // 3 | blue | bird | small | // 4 | black| fish | tiny | $cast = new FOX_cast(); switch ($ctrl["format"]) { // VAR // ============================================================================= // Used when fetching query results that return a single variable. // // EXAMPLE: "SELECT COUNT(*) FROM test_table WHERE col_2 = red" // RESULT: string "1" (all data is returned in string format) case "var": try { $sql_result = $this->driver->get_var($sql); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 1, 'text' => "Error in database driver", 'data' => array('query' => $query, 'sql' => $sql), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } if ($this->print_result_raw == true) { ob_start(); echo "\nRAW, format = var\n"; print_r($sql_result); $out = ob_get_clean(); FOX_debug::addToFile($out); } if ($this->disable_typecast_read == true) { $result = $sql_result; } else { $result = $cast->queryResult($format = "var", $sql_result, $query["types"]); if ($this->print_result_cast == true) { ob_start(); echo "\nCAST, format = var\n"; print_r($result); $out = ob_get_clean(); FOX_debug::addToFile($out); } } break; // COL // ============================================================================= // Used when fetching query results which only contain values from a single column. // // EXAMPLE: "SELECT col2 FROM test_table" // RESULT: array("red", "green", "blue", "black") // COL // ============================================================================= // Used when fetching query results which only contain values from a single column. // // EXAMPLE: "SELECT col2 FROM test_table" // RESULT: array("red", "green", "blue", "black") case "col": try { $sql_result = $this->driver->get_col($sql); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 2, 'text' => "Error in database driver", 'data' => array('query' => $query, 'sql' => $sql), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } if ($this->print_result_raw == true) { ob_start(); echo "\nRAW, format = col\n"; print_r($sql_result); $out = ob_get_clean(); FOX_debug::addToFile($out); } if ($this->disable_typecast_read == true) { $result = $sql_result; } else { $result = $cast->queryResult($format = "col", $sql_result, $query["types"]); if ($this->print_result_cast == true) { ob_start(); echo "\nCAST, format = col\n"; print_r($result); $out = ob_get_clean(); FOX_debug::addToFile($out); } } break; // ROW_OBJECT // ============================================================================= // Returns a single database row as an object, with variable names mapped to // column names. If the query returns multiple rows, only the first row is returned. // // EXAMPLE: "SELECT * FROM test_table WHERE col_1 = 2" // RESULT: object stdClass( // col_1->2 // col_2->"green" // col_3->"cat" // col_4->"med" // ) // ROW_OBJECT // ============================================================================= // Returns a single database row as an object, with variable names mapped to // column names. If the query returns multiple rows, only the first row is returned. // // EXAMPLE: "SELECT * FROM test_table WHERE col_1 = 2" // RESULT: object stdClass( // col_1->2 // col_2->"green" // col_3->"cat" // col_4->"med" // ) case "row_object": try { $sql_result = $this->driver->get_row($sql); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 3, 'text' => "Error in database driver", 'data' => array('query' => $query, 'sql' => $sql), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } if ($this->print_result_raw == true) { ob_start(); echo "\nRAW, format = row\n"; print_r($sql_result); $out = ob_get_clean(); FOX_debug::addToFile($out); } if ($this->disable_typecast_read == true) { $result = $sql_result; } else { $result = $cast->queryResult($format = "row_object", $sql_result, $query["types"]); if ($this->print_result_cast == true) { ob_start(); echo "\nCAST, format = row_object\n"; print_r($result); $out = ob_get_clean(); FOX_debug::addToFile($out); } } break; // ROW_ARRAY // ============================================================================= // Returns a single database row as an array, with key names mapped to column // names. If the query returns multiple rows, only the first row is returned. // // EXAMPLE: "SELECT * FROM test_table WHERE col_1 = 2" // RESULT: array( // "col_1"=>2 // "col_2"=>"green" // "col_3"=>"cat" // "col_4"=>"med" // ) // ROW_ARRAY // ============================================================================= // Returns a single database row as an array, with key names mapped to column // names. If the query returns multiple rows, only the first row is returned. // // EXAMPLE: "SELECT * FROM test_table WHERE col_1 = 2" // RESULT: array( // "col_1"=>2 // "col_2"=>"green" // "col_3"=>"cat" // "col_4"=>"med" // ) case "row_array": try { $sql_result = $this->driver->get_row($sql); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 4, 'text' => "Error in database driver", 'data' => array('query' => $query, 'sql' => $sql), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } if ($this->print_result_raw == true) { ob_start(); echo "\nRAW, format = row_array\n"; print_r($sql_result); $out = ob_get_clean(); FOX_debug::addToFile($out); } if ($this->disable_typecast_read == true) { $data = $sql_result; } else { $data = $cast->queryResult($format = "row_object", $sql_result, $query["types"]); if ($this->print_result_cast == true) { ob_start(); echo "\nCAST, format = row_array\n"; print_r($data); $out = ob_get_clean(); FOX_debug::addToFile($out); } } if ($data) { $result = array(); // Convert row object into array foreach ($data as $key => $value) { $result[$key] = $value; } if ($this->print_result_formatted == true) { ob_start(); echo "\nFORMATTED, format = row_array\n"; print_r($result); $out = ob_get_clean(); FOX_debug::addToFile($out); } unset($data); // Reduce memory usage } break; // ARRAY_KEY_OBJECT // ============================================================================= // // When used with a single column name passed as a string: // // Returns results as an array of objects, where the primary array key names are // set based on the contents of a database column. // // EXAMPLE: "SELECT * FROM test_table" + $ctrl["key_col"]="col_3" // RESULT: array( // "dog" =>stdClass( "col_1"->1, "col_2"->"red", "col_3"->"dog", "col_4"->"big"), // "cat" =>stdClass( "col_1"->2, "col_2"->"green", "col_3"->"cat", "col_4"->"med"), // "bird"=>stdClass( "col_1"->3, "col_2"->"blue", "col_3"->"bird", "col_4"->"small"), // "fish"=>stdClass( "col_1"->4, "col_2"->"black", "col_3"->"fish", "col_4"->"tiny"), // ) // When used with multiple column names passed as an array of strings: // // Returns results as an array of arrays^N, where the array key names and heirarchy // are set based on the contents of the $key_col array. This output format REQUIRES // that each taxonomy group (in the example below "col_3" + "col_4") is UNIQUE // // EXAMPLE TABLE "test_table_2" // ====================================== // col_1 | col_2 | col_3 | col_4 | col_5 // ====================================== // 1 | red | dog | big | heavy // 2 | green| dog | med | light // 3 | blue | bird | small | light // 4 | black| fish | tiny | average // 5 | black| fish | large | light // // UNIQUE KEY col_3_col4(col_3, col_4) // // EXAMPLE: "SELECT * FROM test_table" + $ctrl["key_col"] = array("col_3, "col_4") // RESULT: array( // "dog" =>array( // "big"=>stdClass("col_1"->1, "col_2"->"red", "col_5"->"heavy"), // "med"=>stdClass("col_1"->2, "col_2"->"green", "col_5"->"light") // ), // "bird"=>array( // "small"=>stdClass("col_1"->3, "col_2"->"blue", "col_5"->"light") // ), // "fish"=>array( // "tiny"=>stdClass("col_1"->4, "col_2"->"black", "col_5"->"average"), // "large"=>stdClass("col_1"->5, "col_2"->"black", "col_5"->"light") // ) // ) // ARRAY_KEY_OBJECT // ============================================================================= // // When used with a single column name passed as a string: // // Returns results as an array of objects, where the primary array key names are // set based on the contents of a database column. // // EXAMPLE: "SELECT * FROM test_table" + $ctrl["key_col"]="col_3" // RESULT: array( // "dog" =>stdClass( "col_1"->1, "col_2"->"red", "col_3"->"dog", "col_4"->"big"), // "cat" =>stdClass( "col_1"->2, "col_2"->"green", "col_3"->"cat", "col_4"->"med"), // "bird"=>stdClass( "col_1"->3, "col_2"->"blue", "col_3"->"bird", "col_4"->"small"), // "fish"=>stdClass( "col_1"->4, "col_2"->"black", "col_3"->"fish", "col_4"->"tiny"), // ) // When used with multiple column names passed as an array of strings: // // Returns results as an array of arrays^N, where the array key names and heirarchy // are set based on the contents of the $key_col array. This output format REQUIRES // that each taxonomy group (in the example below "col_3" + "col_4") is UNIQUE // // EXAMPLE TABLE "test_table_2" // ====================================== // col_1 | col_2 | col_3 | col_4 | col_5 // ====================================== // 1 | red | dog | big | heavy // 2 | green| dog | med | light // 3 | blue | bird | small | light // 4 | black| fish | tiny | average // 5 | black| fish | large | light // // UNIQUE KEY col_3_col4(col_3, col_4) // // EXAMPLE: "SELECT * FROM test_table" + $ctrl["key_col"] = array("col_3, "col_4") // RESULT: array( // "dog" =>array( // "big"=>stdClass("col_1"->1, "col_2"->"red", "col_5"->"heavy"), // "med"=>stdClass("col_1"->2, "col_2"->"green", "col_5"->"light") // ), // "bird"=>array( // "small"=>stdClass("col_1"->3, "col_2"->"blue", "col_5"->"light") // ), // "fish"=>array( // "tiny"=>stdClass("col_1"->4, "col_2"->"black", "col_5"->"average"), // "large"=>stdClass("col_1"->5, "col_2"->"black", "col_5"->"light") // ) // ) case "array_key_object": try { $sql_result = $this->driver->get_results($sql); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 5, 'text' => "Error in database driver", 'data' => array('query' => $query, 'sql' => $sql), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } if ($this->print_result_raw == true) { ob_start(); echo "\nRAW, format = array_key_object\n"; print_r($sql_result); $out = ob_get_clean(); FOX_debug::addToFile($out); } if ($this->disable_typecast_read == true) { $data = $sql_result; } else { $data = $cast->queryResult($format = "array_object", $sql_result, $query["types"]); if ($this->print_result_cast == true) { ob_start(); echo "\nCAST, format = array_key_object\n"; print_r($data); $out = ob_get_clean(); FOX_debug::addToFile($out); } } if ($data) { $result = array(); // If a single column name is passed as a string, use the more efficient // direct assignment algorithm to build a 1 level tree if (!is_array($ctrl["key_col"])) { foreach ($data as $row) { $key = $row->{$ctrl["key_col"]}; $result[$key] = $row; } } else { foreach ($data as $row) { // Since there is no functionality in PHP for creating a new array key // based on a name stored in a variable ( $$ variable variable syntax does // not work for multidimensional arrays, we have to build a string of PHP // code and use eval() to run it $eval_str = "\$result"; foreach ($ctrl["key_col"] as $keyname) { $eval_str .= '["' . $row->{$keyname} . '"]'; } $eval_str .= " = \$row_copy;"; $row_copy = new stdClass(); // Copy the row object into a new stdClass, skipping keys that are used as the // branch variables foreach ($row as $key => $value) { if (array_search($key, $ctrl["key_col"]) === false) { $row_copy->{$key} = $value; } } // Run the PHP string we have built eval($eval_str); } } if ($this->print_result_formatted == true) { ob_start(); echo "\nFORMATTED, format = array_key_object\n"; print_r($result); $out = ob_get_clean(); FOX_debug::addToFile($out); } unset($data); // Reduce memory usage } break; // ARRAY_KEY_ARRAY // ============================================================================= // When used with a single column name passed as a string: // // Returns results as an array of arrays, where the primary array key names are // set based on the contents of a database column. // // EXAMPLE: "SELECT * FROM test_table" + $ctrl["key_col"]="col_3" // RESULT: array( // "dog" =>array( "col_1"=>1, "col_2"=>"red", "col_3"=>"dog", "col_4"=>"big"), // "cat" =>array( "col_1"=>2, "col_2"=>"green", "col_3"=>"cat", "col_4"=>"med"), // "bird"=>array( "col_1"=>3, "col_2"=>"blue", "col_3"=>"bird", "col_4"=>"small"), // "fish"=>array( "col_1"=>4, "col_2"=>"black", "col_3"=>"fish", "col_4"=>"tiny"), // ) // // When used with multiple column names passed as an array of strings: // // Returns results as an array of arrays^N, where the array key names and heirarchy // are set based on the contents of the $key_col array. This output format REQUIRES // that each taxonomy group (in the example below "col_3" + "col_4") is UNIQUE // // EXAMPLE TABLE "test_table_2" // ====================================== // col_1 | col_2 | col_3 | col_4 | col_5 // ====================================== // 1 | red | dog | big | heavy // 2 | green| dog | med | light // 3 | blue | bird | small | light // 4 | black| fish | tiny | average // 5 | black| fish | large | light // // UNIQUE KEY col_3_col4(col_3, col_4) // // EXAMPLE: "SELECT * FROM test_table" + $ctrl["key_col"] = array("col_3, "col_4") // RESULT: array( // "dog" =>array( // "big"=>array("col_1"=>1, "col_2"=>"red", "col_5"=>"heavy"), // "med"=>array("col_1"=>2, "col_2"=>"green", "col_5"=>"light") // ), // "bird"=>array( // "small"=>array("col_1"=>3, "col_2"=>"blue", "col_5"=>"light") // ), // "fish"=>array( // "tiny"=>array("col_1"=>4, "col_2"=>"black", "col_5"=>"average"), // "large"=>array("col_1"=>5, "col_2"=>"black", "col_5"=>"light") // ) // ) // ARRAY_KEY_ARRAY // ============================================================================= // When used with a single column name passed as a string: // // Returns results as an array of arrays, where the primary array key names are // set based on the contents of a database column. // // EXAMPLE: "SELECT * FROM test_table" + $ctrl["key_col"]="col_3" // RESULT: array( // "dog" =>array( "col_1"=>1, "col_2"=>"red", "col_3"=>"dog", "col_4"=>"big"), // "cat" =>array( "col_1"=>2, "col_2"=>"green", "col_3"=>"cat", "col_4"=>"med"), // "bird"=>array( "col_1"=>3, "col_2"=>"blue", "col_3"=>"bird", "col_4"=>"small"), // "fish"=>array( "col_1"=>4, "col_2"=>"black", "col_3"=>"fish", "col_4"=>"tiny"), // ) // // When used with multiple column names passed as an array of strings: // // Returns results as an array of arrays^N, where the array key names and heirarchy // are set based on the contents of the $key_col array. This output format REQUIRES // that each taxonomy group (in the example below "col_3" + "col_4") is UNIQUE // // EXAMPLE TABLE "test_table_2" // ====================================== // col_1 | col_2 | col_3 | col_4 | col_5 // ====================================== // 1 | red | dog | big | heavy // 2 | green| dog | med | light // 3 | blue | bird | small | light // 4 | black| fish | tiny | average // 5 | black| fish | large | light // // UNIQUE KEY col_3_col4(col_3, col_4) // // EXAMPLE: "SELECT * FROM test_table" + $ctrl["key_col"] = array("col_3, "col_4") // RESULT: array( // "dog" =>array( // "big"=>array("col_1"=>1, "col_2"=>"red", "col_5"=>"heavy"), // "med"=>array("col_1"=>2, "col_2"=>"green", "col_5"=>"light") // ), // "bird"=>array( // "small"=>array("col_1"=>3, "col_2"=>"blue", "col_5"=>"light") // ), // "fish"=>array( // "tiny"=>array("col_1"=>4, "col_2"=>"black", "col_5"=>"average"), // "large"=>array("col_1"=>5, "col_2"=>"black", "col_5"=>"light") // ) // ) case "array_key_array": try { $sql_result = $this->driver->get_results($sql); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 6, 'text' => "Error in database driver", 'data' => array('query' => $query, 'sql' => $sql), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } if ($this->print_result_raw == true) { ob_start(); echo "RAW, format = array_key_array\n"; print_r($sql_result); $out = ob_get_clean(); FOX_debug::addToFile($out); } if ($this->disable_typecast_read == true) { $data = $sql_result; } else { $data = $cast->queryResult($format = "array_object", $sql_result, $query["types"]); if ($this->print_result_cast == true) { ob_start(); echo "\nCAST, format = array_key_array\n"; print_r($data); $out = ob_get_clean(); FOX_debug::addToFile($out); } } if ($data) { $result = array(); // If a single column name is passed as a string, use the more efficient // direct assignment algorithm to build a 1 level tree if (!is_array($ctrl["key_col"])) { foreach ($data as $row) { $arr = array(); // Convert row object into array foreach ($row as $key => $value) { $arr[$key] = $value; } // Insert row array into primary array as named key $result[$row->{$ctrl["key_col"]}] = $arr; } } else { foreach ($data as $row) { // Since there is no functionality in PHP for creating a new array key // based on a name stored in a variable ( $$ variable variable syntax does // not work for multidimensional arrays), we have to build a string of PHP // code and use eval() to run it $eval_str = "\$result"; foreach ($ctrl["key_col"] as $keyname) { $eval_str .= '["' . $row->{$keyname} . '"]'; } $eval_str .= " = \$arr;"; $arr = array(); // Convert row object into array, skipping keys that are used as the // branch variables foreach ($row as $key => $value) { // Check if this is a first-order row. If it is, "lift" it up a // level in the results array to avoid adding an unnecessary "L0" // wrapper array around it $order = count(array_keys((array) $row)) - count($ctrl["key_col"]); if ($order > 1) { if (array_search($key, $ctrl["key_col"]) === false) { $arr[$key] = $value; } } else { $arr = $value; } } // Run the PHP string we have built eval($eval_str); } } if ($this->print_result_formatted == true) { ob_start(); echo "\nFORMATTED, format = array_key_array\n"; print_r($result); $out = ob_get_clean(); FOX_debug::addToFile($out); } unset($data); // Reduce memory usage } break; // ARRAY_KEY_ARRAY_GROUPED // ============================================================================= // // Requires at least TWO column names, and columns not specified in $key_col are not // included in the results set. Returns results as an array of arrays^N-1, where the // array key names and heirarchy are set based on the contents of the $key_col array. // Results in the last db column specified in $key_col are grouped together in an // int-keyed array. The key name corresponds to the order in which a rows is returned // from the database and the value of each key is the column's value in the database // row. For a working example of how to use this result formatter, see the function // database_resultFormatters::test_array_key_array_grouped() in the database unit tests. // // EXAMPLE TABLE "test_table_2" // =============================== // col_1 | col_2 | col_3 | col_4 // =============================== // 1 | red | dog | A // 2 | green| dog | B // 3 | green| dog | C // 4 | green| dog | D // 5 | blue | bird | A // 6 | black| bird | A // 7 | black| fish | A // 8 | black| fish | B // // UNIQUE KEY no_duplicates(col_2, col_3, col_4) // // EXAMPLE: "SELECT * FROM test_table" + $ctrl["key_col"] = array("col_2, "col_3", "col_4") // NOTE: "col_1" is excluded because it is not specified in $ctrl["key_col"] // RESULT: array( // "dog" =>array( // "red"=> array("A"), // "green"=> array("B","C","D") // ), // "bird" =>array( // "blue"=> array("A"), // "black"=> array("A") // ), // "fish" =>array( // "black"=> array("A","B") // ) // ) // ARRAY_KEY_ARRAY_GROUPED // ============================================================================= // // Requires at least TWO column names, and columns not specified in $key_col are not // included in the results set. Returns results as an array of arrays^N-1, where the // array key names and heirarchy are set based on the contents of the $key_col array. // Results in the last db column specified in $key_col are grouped together in an // int-keyed array. The key name corresponds to the order in which a rows is returned // from the database and the value of each key is the column's value in the database // row. For a working example of how to use this result formatter, see the function // database_resultFormatters::test_array_key_array_grouped() in the database unit tests. // // EXAMPLE TABLE "test_table_2" // =============================== // col_1 | col_2 | col_3 | col_4 // =============================== // 1 | red | dog | A // 2 | green| dog | B // 3 | green| dog | C // 4 | green| dog | D // 5 | blue | bird | A // 6 | black| bird | A // 7 | black| fish | A // 8 | black| fish | B // // UNIQUE KEY no_duplicates(col_2, col_3, col_4) // // EXAMPLE: "SELECT * FROM test_table" + $ctrl["key_col"] = array("col_2, "col_3", "col_4") // NOTE: "col_1" is excluded because it is not specified in $ctrl["key_col"] // RESULT: array( // "dog" =>array( // "red"=> array("A"), // "green"=> array("B","C","D") // ), // "bird" =>array( // "blue"=> array("A"), // "black"=> array("A") // ), // "fish" =>array( // "black"=> array("A","B") // ) // ) case "array_key_array_grouped": try { $sql_result = $this->driver->get_results($sql); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 7, 'text' => "Error in database driver", 'data' => array('query' => $query, 'sql' => $sql), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } if ($this->print_result_raw == true) { ob_start(); echo "RAW, format = array_key_array_grouped\n"; print_r($sql_result); $out = ob_get_clean(); FOX_debug::addToFile($out); } if ($this->disable_typecast_read == true) { $data = $sql_result; } else { $data = $cast->queryResult($format = "array_object", $sql_result, $query["types"]); if ($this->print_result_cast == true) { ob_start(); echo "\nCAST, format = array_key_array_grouped\n"; print_r($data); $out = ob_get_clean(); FOX_debug::addToFile($out); } } if ($data) { $result = array(); foreach ($data as $row) { // Since there is no functionality in PHP for creating a new array key // based on a name stored in a variable ( $$ variable variable syntax does // not work for multidimensional arrays), we have to build a string of PHP // code and use eval() to run it $eval_str = "\$result"; $idx = sizeof($ctrl["key_col"]) - 1; $grouped_col = $ctrl["key_col"][$idx]; foreach ($ctrl["key_col"] as $keyname) { if ($keyname != $grouped_col) { $eval_str .= '["' . $row->{$keyname} . '"]'; } else { $eval_str .= '[]'; } } $eval_str .= " = \$row->" . $grouped_col . ";"; // Run the PHP string we have built eval($eval_str); } if ($this->print_result_formatted == true) { ob_start(); echo "\nFORMATTED, format = array_key_array_grouped\n"; print_r($result); $out = ob_get_clean(); FOX_debug::addToFile($out); } unset($data); // Reduce memory usage } break; // ARRAY_KEY_ARRAY_TRUE // ============================================================================= // // Returns results as an array of arrays^N-1, where the array key names and heirarchy // are set based on the contents of the $key_col array. Results in the last db column // specified in $key_col are grouped together in an result-keyed array where the key // name is the column's value in the database row and the key's value is (bool)true. // For a working example of how to use this result formatter, see the function // database_resultFormatters::test_array_key_array_true() in the database unit tests. // // EXAMPLE TABLE "test_table_2" // =============================== // col_1 | col_2 | col_3 | col_4 // =============================== // 1 | red | dog | A // 2 | green| dog | B // 3 | green| dog | C // 4 | green| dog | D // 5 | blue | bird | A // 6 | black| bird | A // 7 | black| fish | A // 8 | black| fish | B // // UNIQUE KEY no_duplicates(col_2, col_3, col_4) // // EXAMPLE: "SELECT * FROM test_table" + $ctrl["key_col"] = array("col_2, "col_3", "col_4") // NOTE: "col_1" is excluded because it is not specified in $ctrl["key_col"] // RESULT: array( // "dog" =>array( // "red"=> array("A"=>"true"), // "green"=> array("B"=>"true","C"=>"true","D"=>"true") // ), // "bird" =>array( // "blue"=> array("A"=>"true"), // "black"=> array("A"=>"true") // ), // "fish" =>array( // "black"=> array("A"=>"true","B"=>"true") // ) // ) // ARRAY_KEY_ARRAY_TRUE // ============================================================================= // // Returns results as an array of arrays^N-1, where the array key names and heirarchy // are set based on the contents of the $key_col array. Results in the last db column // specified in $key_col are grouped together in an result-keyed array where the key // name is the column's value in the database row and the key's value is (bool)true. // For a working example of how to use this result formatter, see the function // database_resultFormatters::test_array_key_array_true() in the database unit tests. // // EXAMPLE TABLE "test_table_2" // =============================== // col_1 | col_2 | col_3 | col_4 // =============================== // 1 | red | dog | A // 2 | green| dog | B // 3 | green| dog | C // 4 | green| dog | D // 5 | blue | bird | A // 6 | black| bird | A // 7 | black| fish | A // 8 | black| fish | B // // UNIQUE KEY no_duplicates(col_2, col_3, col_4) // // EXAMPLE: "SELECT * FROM test_table" + $ctrl["key_col"] = array("col_2, "col_3", "col_4") // NOTE: "col_1" is excluded because it is not specified in $ctrl["key_col"] // RESULT: array( // "dog" =>array( // "red"=> array("A"=>"true"), // "green"=> array("B"=>"true","C"=>"true","D"=>"true") // ), // "bird" =>array( // "blue"=> array("A"=>"true"), // "black"=> array("A"=>"true") // ), // "fish" =>array( // "black"=> array("A"=>"true","B"=>"true") // ) // ) case "array_key_array_true": try { $sql_result = $this->driver->get_results($sql); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 8, 'text' => "Error in database driver", 'data' => array('query' => $query, 'sql' => $sql), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } if ($this->print_result_raw == true) { ob_start(); echo "RAW, format = array_key_array_true\n"; print_r($sql_result); $out = ob_get_clean(); FOX_debug::addToFile($out); } if ($this->disable_typecast_read == true) { $data = $sql_result; } else { $data = $cast->queryResult($format = "array_object", $sql_result, $query["types"]); if ($this->print_result_cast == true) { ob_start(); echo "\nCAST, format = array_key_array_true\n"; print_r($data); $out = ob_get_clean(); FOX_debug::addToFile($out); } } if ($data) { $result = array(); foreach ($data as $row) { // Since there is no functionality in PHP for creating a new array key // based on a name stored in a variable ( $$ variable variable syntax does // not work for multidimensional arrays), we have to build a string of PHP // code and use eval() to run it $eval_str = "\$result"; foreach ($ctrl["key_col"] as $keyname) { $eval_str .= '["' . $row->{$keyname} . '"]'; } $eval_str .= " = true;"; // Run the PHP string we have built eval($eval_str); } if ($this->print_result_formatted == true) { ob_start(); echo "\nFORMATTED, format = array_key_array_true\n"; print_r($result); $out = ob_get_clean(); FOX_debug::addToFile($out); } unset($data); // Reduce memory usage } break; // ARRAY_KEY_ARRAY_FALSE // ============================================================================= // // Returns results as an array of arrays^N-1, where the array key names and heirarchy // are set based on the contents of the $key_col array. Results in the last db column // specified in $key_col are grouped together in an result-keyed array where the key // name is the column's value in the database row and the key's value is (bool)false. // For a working example of how to use this result formatter, see the function // database_resultFormatters::test_array_key_array_false() in the database unit tests. // // EXAMPLE TABLE "test_table_2" // =============================== // col_1 | col_2 | col_3 | col_4 // =============================== // 1 | red | dog | A // 2 | green| dog | B // 3 | green| dog | C // 4 | green| dog | D // 5 | blue | bird | A // 6 | black| bird | A // 7 | black| fish | A // 8 | black| fish | B // // UNIQUE KEY no_duplicates(col_2, col_3, col_4) // // EXAMPLE: "SELECT * FROM test_table" + $ctrl["key_col"] = array("col_2, "col_3", "col_4") // NOTE: "col_1" is excluded because it is not specified in $ctrl["key_col"] // RESULT: array( // "dog" =>array( // "red"=> array("A"=>"false"), // "green"=> array("B"=>"false","C"=>"false","D"=>"false") // ), // "bird" =>array( // "blue"=> array("A"=>"false"), // "black"=> array("A"=>"false") // ), // "fish" =>array( // "black"=> array("A"=>"false","B"=>"false") // ) // ) // ARRAY_KEY_ARRAY_FALSE // ============================================================================= // // Returns results as an array of arrays^N-1, where the array key names and heirarchy // are set based on the contents of the $key_col array. Results in the last db column // specified in $key_col are grouped together in an result-keyed array where the key // name is the column's value in the database row and the key's value is (bool)false. // For a working example of how to use this result formatter, see the function // database_resultFormatters::test_array_key_array_false() in the database unit tests. // // EXAMPLE TABLE "test_table_2" // =============================== // col_1 | col_2 | col_3 | col_4 // =============================== // 1 | red | dog | A // 2 | green| dog | B // 3 | green| dog | C // 4 | green| dog | D // 5 | blue | bird | A // 6 | black| bird | A // 7 | black| fish | A // 8 | black| fish | B // // UNIQUE KEY no_duplicates(col_2, col_3, col_4) // // EXAMPLE: "SELECT * FROM test_table" + $ctrl["key_col"] = array("col_2, "col_3", "col_4") // NOTE: "col_1" is excluded because it is not specified in $ctrl["key_col"] // RESULT: array( // "dog" =>array( // "red"=> array("A"=>"false"), // "green"=> array("B"=>"false","C"=>"false","D"=>"false") // ), // "bird" =>array( // "blue"=> array("A"=>"false"), // "black"=> array("A"=>"false") // ), // "fish" =>array( // "black"=> array("A"=>"false","B"=>"false") // ) // ) case "array_key_array_false": try { $sql_result = $this->driver->get_results($sql); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 9, 'text' => "Error in database driver", 'data' => array('query' => $query, 'sql' => $sql), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } if ($this->print_result_raw == true) { ob_start(); echo "RAW, format = array_key_array_false"; print_r($sql_result); $out = ob_get_clean(); FOX_debug::addToFile($out); } if ($this->disable_typecast_read == true) { $data = $sql_result; } else { $data = $cast->queryResult($format = "array_object", $sql_result, $query["types"]); if ($this->print_result_cast == true) { ob_start(); echo "\nCAST, format = array_key_array_false"; print_r($data); $out = ob_get_clean(); FOX_debug::addToFile($out); } } if ($data) { $result = array(); foreach ($data as $row) { // Since there is no functionality in PHP for creating a new array key // based on a name stored in a variable ( $$ variable variable syntax does // not work for multidimensional arrays), we have to build a string of PHP // code and use eval() to run it $eval_str = "\$result"; foreach ($ctrl["key_col"] as $keyname) { $eval_str .= '["' . $row->{$keyname} . '"]'; } $eval_str .= " = false;"; // Run the PHP string we have built eval($eval_str); } if ($this->print_result_formatted == true) { ob_start(); echo "\nFORMATTED, format = array_key_array_false"; print_r($result); $out = ob_get_clean(); FOX_debug::addToFile($out); } unset($data); // Reduce memory usage } break; // ARRAY_KEY_SINGLE // ============================================================================= // Returns results as an array of ints or strings, where the array key names // are set based on the contents of a database column. // // EXAMPLE: "SELECT col_2, col_3 FROM test_table" + $ctrl["key_col"]="col_2", $ctrl["val_col"]="col_3" // RESULT: array( // "red"=>"dog", // "green"=>"cat", // "blue"=>"bird", // "black"=>"fish" // ) // ARRAY_KEY_SINGLE // ============================================================================= // Returns results as an array of ints or strings, where the array key names // are set based on the contents of a database column. // // EXAMPLE: "SELECT col_2, col_3 FROM test_table" + $ctrl["key_col"]="col_2", $ctrl["val_col"]="col_3" // RESULT: array( // "red"=>"dog", // "green"=>"cat", // "blue"=>"bird", // "black"=>"fish" // ) case "array_key_single": try { $sql_result = $this->driver->get_results($sql); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 10, 'text' => "Error in database driver", 'data' => array('query' => $query, 'sql' => $sql), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } if ($this->print_result_raw == true) { ob_start(); echo "RAW, format = array_key_single\n"; print_r($sql_result); $out = ob_get_clean(); FOX_debug::addToFile($out); } if ($this->disable_typecast_read == true) { $data = $sql_result; } else { $data = $cast->queryResult($format = "array_object", $sql_result, $query["types"]); if ($this->print_result_cast == true) { ob_start(); echo "\nCAST, format = array_key_single\n"; print_r($data); $out = ob_get_clean(); FOX_debug::addToFile($out); } } if ($data) { $result = array(); foreach ($data as $row) { $result[$row->{$ctrl["key_col"]}] = $row->{$ctrl["val_col"]}; } if ($this->print_result_formatted == true) { ob_start(); echo "\nCAST, format = array_key_single\n"; print_r($result); $out = ob_get_clean(); FOX_debug::addToFile($out); } unset($data); // Reduce memory usage } break; // ARRAY_OBJECT // ============================================================================= // Returns results as an array of objects, where the primary array keys are // zero-indexed ints // // EXAMPLE: "SELECT * FROM test_table" // RESULT: array( // stdClass( "col_1"->1, "col_2"->"red", "col_3"->"dog", "col_4"->"big"), // stdClass( "col_1"->2, "col_2"->"green", "col_3"->"cat", "col_4"->"med"), // stdClass( "col_1"->3, "col_2"->"blue", "col_3"->"bird", "col_4"->"small"), // stdClass( "col_1"->4, "col_2"->"black", "col_3"->"fish", "col_4"->"tiny"), // ) // ARRAY_OBJECT // ============================================================================= // Returns results as an array of objects, where the primary array keys are // zero-indexed ints // // EXAMPLE: "SELECT * FROM test_table" // RESULT: array( // stdClass( "col_1"->1, "col_2"->"red", "col_3"->"dog", "col_4"->"big"), // stdClass( "col_1"->2, "col_2"->"green", "col_3"->"cat", "col_4"->"med"), // stdClass( "col_1"->3, "col_2"->"blue", "col_3"->"bird", "col_4"->"small"), // stdClass( "col_1"->4, "col_2"->"black", "col_3"->"fish", "col_4"->"tiny"), // ) case "array_object": try { $sql_result = $this->driver->get_results($sql); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 11, 'text' => "Error in database driver", 'data' => array('query' => $query, 'sql' => $sql), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } if ($this->print_result_raw == true) { ob_start(); echo "RAW, format = array_object\n"; print_r($sql_result); $out = ob_get_clean(); FOX_debug::addToFile($out); } if ($this->disable_typecast_read == true) { $result = $sql_result; } else { $result = $cast->queryResult($format = "array_object", $sql_result, $query["types"]); if ($this->print_result_cast == true) { ob_start(); echo "\nCAST, format = array_object\n"; print_r($result); $out = ob_get_clean(); FOX_debug::addToFile($out); } } if ($this->print_result_formatted == true) { ob_start(); print_r($result); $out = ob_get_clean(); FOX_debug::addToFile($out); } break; // ARRAY_ARRAY // ============================================================================= // Returns results as an array of arrays, where the primary array keys are // zero-indexed ints // // EXAMPLE: "SELECT * FROM test_table" // RESULT: array( // array( "col_1"=>1, "col_2"=>"red", "col_3"=>"dog", "col_4"=>"big"), // array( "col_1"=>2, "col_2"=>"green", "col_3"=>"cat", "col_4"=>"med"), // array( "col_1"=>3, "col_2"=>"blue", "col_3"=>"bird", "col_4"=>"small"), // array( "col_1"=>4, "col_2"=>"black", "col_3"=>"fish", "col_4"=>"tiny"), // ) // ARRAY_ARRAY // ============================================================================= // Returns results as an array of arrays, where the primary array keys are // zero-indexed ints // // EXAMPLE: "SELECT * FROM test_table" // RESULT: array( // array( "col_1"=>1, "col_2"=>"red", "col_3"=>"dog", "col_4"=>"big"), // array( "col_1"=>2, "col_2"=>"green", "col_3"=>"cat", "col_4"=>"med"), // array( "col_1"=>3, "col_2"=>"blue", "col_3"=>"bird", "col_4"=>"small"), // array( "col_1"=>4, "col_2"=>"black", "col_3"=>"fish", "col_4"=>"tiny"), // ) case "array_array": try { $sql_result = $this->driver->get_results($sql); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 12, 'text' => "Error in database driver", 'data' => array('query' => $query, 'sql' => $sql), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } if ($this->print_result_raw == true) { ob_start(); echo "RAW, format = array_array\n"; print_r($sql_result); $out = ob_get_clean(); FOX_debug::addToFile($out); } if ($this->disable_typecast_read == true) { $data = $sql_result; } else { $data = $cast->queryResult($format = "array_object", $sql_result, $query["types"]); if ($this->print_result_cast == true) { ob_start(); echo "\nCAST, format = array_array\n"; print_r($data); $out = ob_get_clean(); FOX_debug::addToFile($out); } } if ($data) { $result = array(); foreach ($data as $row) { $arr = array(); // Convert row object into array foreach ($row as $key => $value) { $arr[$key] = $value; } // Insert row array into primary array as unnamed key $result[] = $arr; } if ($this->print_result_formatted == true) { ob_start(); echo "\nFORMATTED, format = array_array\n"; print_r($result); $out = ob_get_clean(); FOX_debug::addToFile($out); } unset($data); // Reduce memory usage } break; // ARRAY_ARRAY_OFFSET // ============================================================================= // Returns results as an array of arrays, where the primary array keys are // zero-indexed ints, and the secondary array keys are the offset of the // column in the table definition array // // EXAMPLE: "SELECT * FROM test_table" // RESULT: array( // array( 1, "red", "dog", "big"), // array( 2, "green", "cat", "med"), // array( 3, "blue", "bird", "small"), // array( 4, "black", "fish", "tiny"), // ) // ARRAY_ARRAY_OFFSET // ============================================================================= // Returns results as an array of arrays, where the primary array keys are // zero-indexed ints, and the secondary array keys are the offset of the // column in the table definition array // // EXAMPLE: "SELECT * FROM test_table" // RESULT: array( // array( 1, "red", "dog", "big"), // array( 2, "green", "cat", "med"), // array( 3, "blue", "bird", "small"), // array( 4, "black", "fish", "tiny"), // ) case "array_array_offset": try { $sql_result = $this->driver->get_results($sql); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 12, 'text' => "Error in database driver", 'data' => array('query' => $query, 'sql' => $sql), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } if ($this->print_result_raw == true) { ob_start(); echo "RAW, format = array_array_offset\n"; print_r($sql_result); $out = ob_get_clean(); FOX_debug::addToFile($out); } if ($this->disable_typecast_read == true) { $data = $sql_result; } else { $data = $cast->queryResult($format = "array_object", $sql_result, $query["types"]); if ($this->print_result_cast == true) { ob_start(); echo "\nCAST, format = array_array_offset\n"; print_r($data); $out = ob_get_clean(); FOX_debug::addToFile($out); } } if ($data) { $result = array(); foreach ($data as $row) { $arr = array(); // Convert row object into array foreach ($row as $key => $value) { $arr[] = $value; } // Insert row array into primary array as unnamed key $result[] = $arr; } if ($this->print_result_formatted == true) { ob_start(); echo "\nFORMATTED, format = array_array_offset\n"; print_r($result); $out = ob_get_clean(); FOX_debug::addToFile($out); } unset($data); // Reduce memory usage } break; // RAW // ============================================================================= // Runs a default SQL query. Returned result format depends on the query. // RAW // ============================================================================= // Runs a default SQL query. Returned result format depends on the query. case "raw": try { $result = $this->driver->query($sql); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 13, 'text' => "Error in database driver", 'data' => array('query' => $query, 'sql' => $sql), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } if ($this->print_result_raw == true) { ob_start(); echo "format = null\n"; print_r($result); $out = ob_get_clean(); FOX_debug::addToFile($out); } break; default: throw new FOX_exception(array('numeric' => 14, 'text' => "Invalid query runner format", 'data' => array('faulting_format' => $ctrl["format"], "query" => $query, "ctrl" => $ctrl), 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => null)); } // END switch($ctrl["format"]) return $result; }
/** * Lofts a flat matrix into a trie structure, while hashing its keys * * @version 1.0 * @since 1.0 * * @param array $rows | Flat matrix * @param array $columns | Array of column names * @param array $ctrl | Control args * * @return array | Exception on failure. Flattened trie structure on success. */ public static function loftMatrixHash($rows, $columns, &$hash_table, $ctrl = null) { $ctrl_default = array('null_token' => '*'); $ctrl = FOX_sUtil::parseArgs($ctrl, $ctrl_default); $result = array(); // If a single column name is passed as a string, use the more efficient // direct assignment algorithm to build a 1 level trie if (!is_array($columns)) { foreach ($rows as $row) { // Convert row object into array foreach ($row as $tokens) { $result[$hash_table->set($tokens[$columns])] = true; } unset($tokens); } unset($row); } else { foreach ($rows as $row) { // Since there is no functionality in PHP for creating a new array key // based on a name stored in a variable ( $$ variable variable syntax does // not work for multidimensional arrays), we have to build a string of PHP // code and use eval() to run it $eval_str = "\$result"; foreach ($columns as $keyname) { if (FOX_sUtil::keyExists($keyname, $row)) { $eval_str .= '["' . $hash_table->set($row[$keyname]) . '"]'; } else { $eval_str .= '["' . $ctrl['null_token'] . '"]'; } } unset($keyname); $eval_str .= " = true;"; // Run the PHP string we have built eval($eval_str); } unset($row); } return $result; }
public function __construct($args = null) { // Handle dependency-injection // =========================================================== // NOTE: Memcached's flush() has one-second granularity. It only affects items // set a minimum of 1 second before it, and it could affect items set for up to // one second after it. This it probably in Memcached's implementation to handle // network latency across multiple servers, and would never be a problem in production // because the only time a site would dump the *entire* cache is on a server reboot. // @see http://ca2.php.net/manual/en/memcache.flush.php // However, its a HUGE issue during unit testing when the cache has to be flushed // between every test fixture ...potentially hundreds of times a second, and the unit // tests are usually run against a SINGLE memcached instance. As such, the unit tests // usually set this value to almost zero. If you experience problems with the memcached // test fixture on your system, you may need to increase the 'flush_propagation_delay' // parameter $args_default = array('max_offset' => 2147483646, 'servers' => array(array('ip' => '127.0.0.1', 'port' => 11211, 'persist' => false, 'weight' => 100)), 'compress_threshold' => 0.2, 'flush_propagation_delay' => 1200000, 'set_propagation_delay' => 0); $args = FOX_sUtil::parseArgs($args, $args_default); foreach ($args as $key => $var) { $this->{$key} = $var; } unset($key, $var); // Handle process-id binding // =========================================================== if (FOX_sUtil::keyExists('process_id', $args)) { // Binding to a reference is important. It makes the cache engine $process_id // update if the FOX_mCache is changed, which we do during unit testing. $this->process_id =& $args['process_id']; } else { global $fox; $this->process_id = $fox->process_id; } // CASE 1: Try for the "Memcached" extension, which is the fastest and // has the most advanced features. // ======================================================================= $this->has_libs = false; if (class_exists("Memcached") && $this->use_full == true) { $this->has_libs = true; $this->engine = new Memcached(); $active_servers = $this->engine->getServerList(); if (count($active_servers) == 0) { $formatted_servers = array(); foreach ($this->servers as $server) { $temp = array($server['ip'], $server['port'], $server['weight']); $formatted_servers[] = $temp; } unset($server); $this->engine->addServers($formatted_servers); } $this->engine->setCompressThreshold($this->compress_threshold); $this->mode = 'full'; if ($this->enable == true) { $this->is_active = true; } } elseif (class_exists("Memcache") && $this->use_basic == true) { $this->has_libs = true; $this->engine = new Memcache(); foreach ($this->servers as $server) { $this->engine->addServer($server['ip'], $server['port'], $server['persist']); } unset($server); $this->engine->setCompressThreshold($this->compress_threshold); $this->mode = 'basic'; if ($this->enable == true) { $this->is_active = true; } } elseif ($this->use_portable == true) { require dirname(__FILE__) . '/class.portable.memcached.php'; $this->has_libs = true; $this->engine = new FOX_memcached_portable(); $this->mode = 'portable'; if ($this->enable == true) { $this->is_active = true; } } }