/** * Fetches multiple L5->L1 walks from the datastore * * @version 1.0 * @since 1.0 * * [MATRIX MODE] * @param array $data | Array of row arrays * => ARR @param int '' | Individual row array * => VAL @param int/string $L5 | Single L5 id as int/string * => VAL @param int/string $L4 | Single L4 id as int/string * => VAL @param int/string $L3 | Single L3 id as int/string * => VAL @param int/string $L2 | Single L2 id as int/string * => VAL @param int/string $L1 | Single L1 id as int/string * * [TRIE MODE] * @param array $data | array of L5's in the form "L5_id"=>"L4s" * => ARR @param array $L4s | array of L4's in the form "L4_id"=>"L3s" * => ARR @param array $L3s | array of L3's in the form "L3_id"=>"L2s" * => ARR @param array $L2s | array of L2's in the form "L2_id"=>"L1s" * => ARR @param array $L1s | array of L1's in the form "L1_id"=>"L1_value" * => KEY @param int/string | L1 id * => VAL @param NULL * * @param array $ctrl | Control parameters * => VAL @param bool $validate | Validate keys * => VAL @param string $q_mode | Query format - 'matrix' | 'trie' * => VAL @param string $r_mode | Response format - 'matrix' | 'trie' * * @param bool &$valid | True if all requested objects exist, false if not. * @return array | Exception on failure. Data array on success. */ public function getMulti($data, $ctrl = null, &$valid = 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()))))); } // Add default control params // ========================== $ctrl_default = array('validate' => true, 'q_mode' => 'trie', 'r_mode' => 'trie', 'trap_*' => true); $ctrl = FOX_sUtil::parseArgs($ctrl, $ctrl_default); if (!is_array($data) || count($data) < 1) { throw new FOX_exception(array('numeric' => 1, 'text' => "Invalid data array", 'data' => $data, 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => null)); } // Validate data array // =========================================================== $struct = $this->_struct(); $get_data = array(); if ($ctrl['q_mode'] == 'matrix') { if ($ctrl['validate'] != false) { // Performance optimization (saves 1 op per key) if ($this->debug_on) { extract($this->debug_handler->event(array('pid' => $this->process_id, 'text' => "matrix_validate_start", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'parent' => $this, 'vars' => compact(array_keys(get_defined_vars()))))); } $row_valid = false; try { $validator = new FOX_dataStore_validator($struct); $row_ctrl = array('end_node_format' => 'scalar'); foreach ($data as $row) { $row_valid = $validator->validateMatrixRow($row, $row_ctrl); if ($row_valid !== true) { break; } } unset($row); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 2, 'text' => "Error in validator", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => $child)); } if ($row_valid !== true) { throw new FOX_exception(array('numeric' => 3, 'text' => "Invalid row in data array", 'data' => $row_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' => "matrix_validate_end", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'parent' => $this, 'vars' => compact(array_keys(get_defined_vars()))))); } } // Loft the individual rows into a trie (to merge overlapping objects) then clip // the tree to get the highest order objects we need to fetch // ============================================================================= if ($this->debug_on) { extract($this->debug_handler->event(array('pid' => $this->process_id, 'text' => "matrix_transform_start", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'parent' => $this, 'vars' => compact(array_keys(get_defined_vars()))))); } $columns = array($this->L5_col, $this->L4_col, $this->L3_col, $this->L2_col, $this->L1_col); $trie = FOX_trie::loftMatrix($data, $columns, $loft_ctrl = null); $clip_ctrl = null; try { $get_data = FOX_trie::clipAssocTrie($trie, $columns, $clip_ctrl); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 3, 'text' => "Error in FOX_trie::clipAssocTrie()", 'data' => array('trie' => $trie, 'columns' => $columns, 'clip_ctrl' => $clip_ctrl), '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' => "matrix_transform_end", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'parent' => $this, 'vars' => compact(array_keys(get_defined_vars()))))); } } elseif ($ctrl['q_mode'] == 'trie') { if ($ctrl['validate'] != false) { // Validate the $data array if ($this->debug_on) { extract($this->debug_handler->event(array('pid' => $this->process_id, 'text' => "trie_validate_start", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'parent' => $this, 'vars' => compact(array_keys(get_defined_vars()))))); } $struct = $this->_struct(); try { $validator = new FOX_dataStore_validator($struct); $val_ctrl = array('order' => $this->order, 'mode' => 'control'); $tree_valid = $validator->validateTrie($data, $val_ctrl); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 4, 'text' => "Error in validator", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => $child)); } if ($tree_valid !== true) { throw new FOX_exception(array('numeric' => 5, 'text' => "Invalid key in data array", 'data' => $tree_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' => "trie_validate_end", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'parent' => $this, 'vars' => compact(array_keys(get_defined_vars()))))); } } $get_data = $data; } else { throw new FOX_exception(array('numeric' => 6, 'text' => "Invalid ctrl['q_mode'] parameter", 'data' => $ctrl, 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => null)); } // Trap "SELECT * WHERE TRUE" // =========================================================== if ($ctrl['trap_*'] == true) { if (!array_keys($get_data)) { // @see http://en.wikipedia.org/wiki/Universal_set $error_msg = "INTERLOCK TRIP: One or more of the conditions set in the \$data array reduces to the universal set, "; $error_msg .= "which is equivalent to 'WHERE 1 = 1'. Running this command would have selected the entire datastore. "; $error_msg .= "If this is actually your design intent, set \$ctrl['trap_*'] = false to disable this interlock."; throw new FOX_exception(array('numeric' => 7, 'text' => "{$error_msg}", 'data' => $data, 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => null)); } } // Find all requested objects that don't have authority in the class cache (L5 to L2), // or which don't exist in the class cache (L1) and try to load them from the persistent cache // ============================================================================================== if ($this->debug_on) { extract($this->debug_handler->event(array('pid' => $this->process_id, 'text' => "class_cache_prescan_start", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'parent' => $this, 'vars' => compact(array_keys(get_defined_vars()))))); } try { $cache_fetch = self::notInClassCache($get_data, $this->cache); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 8, 'text' => "Error in self::notInClassCache()", 'data' => array('get_data' => $get_data), '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' => "class_cache_prescan_end", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'parent' => $this, 'vars' => compact(array_keys(get_defined_vars()))))); } if ($cache_fetch) { if ($this->debug_on) { extract($this->debug_handler->event(array('pid' => $this->process_id, 'text' => "persistent_cache_fetch_start", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'parent' => $this, 'vars' => compact(array_keys(get_defined_vars()))))); } try { $cache_pages = self::readCachePage(array_keys($cache_fetch)); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 9, 'text' => "Error reading from persistent cache", 'data' => array('cache_fetch' => array_keys($cache_fetch)), '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_fetch_end", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'parent' => $this, 'vars' => compact(array_keys(get_defined_vars()))))); } foreach ($cache_pages as $page_id => $page_image) { // NOTE: because of the way cache operations are implemented throughout // this class, the persistent cache *always* has authority over the class // cache, which makes it impossible for a situation to occur where there // are entries in the class cache that are not in the persistent cache. As // a result, we can safely overwrite pages in the class cache with pages // from the persistent cache. $this->cache[$page_id] = $page_image; } unset($page_id, $page_image); // Find all requested objects that didn't have authority in the class cache (L5 to L2), // or which didn't exist in the class cache (L1) and try to load them from the database // ===================================================================================== if ($this->debug_on) { extract($this->debug_handler->event(array('pid' => $this->process_id, 'text' => "class_cache_postscan_start", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'parent' => $this, 'vars' => compact(array_keys(get_defined_vars()))))); } $db_fetch = self::notInClassCache($cache_fetch, $this->cache); if ($this->debug_on) { extract($this->debug_handler->event(array('pid' => $this->process_id, 'text' => "class_cache_postscan_end", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'parent' => $this, 'vars' => compact(array_keys(get_defined_vars()))))); } if ($db_fetch) { // Lock affected cache pages for all requested items, to prevent // corrupted keys in case another thread attempts to do a write // operation while we're reading from the database // =========================================================== 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::lockCachePage(array_keys($db_fetch)); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 10, 'text' => "Error locking cache", 'data' => $db_fetch, '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()))))); } $columns = null; $args = array('key_col' => array($this->L5_col, $this->L4_col, $this->L3_col, $this->L2_col, $this->L1_col), 'args' => $db_fetch); $db_ctrl = array('args_format' => 'trie', 'format' => 'array_key_array', 'key_col' => array($this->L5_col, $this->L4_col, $this->L3_col, $this->L2_col, $this->L1_col), 'hash_key_vals' => $this->hashing_on); if ($this->debug_on) { extract($this->debug_handler->event(array('pid' => $this->process_id, 'text' => "db_fetch_start", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'parent' => $this, 'vars' => compact(array_keys(get_defined_vars()))))); } try { $db_result = $this->db->runSelectQuery($struct, $args, $columns, $db_ctrl); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 11, 'text' => "Error while reading from database", 'data' => array('args' => $args, 'columns' => $columns, 'db_ctrl' => $db_ctrl), '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_fetch_end", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'parent' => $this, 'vars' => compact(array_keys(get_defined_vars()))))); } if ($db_result) { if ($this->debug_on) { extract($this->debug_handler->event(array('pid' => $this->process_id, 'text' => "db_result_transform_start", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'parent' => $this, 'vars' => compact(array_keys(get_defined_vars()))))); } // Copy L5 pages in $this->cache to $update_cache as needed, then merge the db // results into the L5 $update_cache pages. This saves memory over duplicating // the entire $this->cache variable. // ============================================================================ $update_cache = array(); foreach ($db_fetch as $L5 => $L4s) { // If we're loading an entire L5 page from the db, we don't need to // merge into the class cache page (if it exists) because the result // from the database has authority if (count($L4s) == 0) { // Overwrite keys if (FOX_sUtil::keyExists($L5, $db_result)) { // The L5 object now has authority $update_cache[$L5]['all_cached'] = true; // Update descendent LUT's unset($update_cache[$L5][$this->L4_col][$L4]); unset($update_cache[$L5][$this->L3_col][$L4]); unset($update_cache[$L5][$this->L2_col][$L4]); $update_cache[$L5]["keys"] = $db_result[$L5]; } } else { // However, for L4 or lower order objects, we have to merge into // the L5 class cache page (if it exists) because the database // result doesn't have L5 authority if (FOX_sUtil::keyExists($L5, $this->cache)) { $update_cache[$L5] = $this->cache[$L5]; } } foreach ($L4s as $L4 => $L3s) { if (count($L3s) == 0) { if (FOX_sUtil::keyExists($L4, $db_result[$L5])) { // The L4 object now has authority $update_cache[$L5][$this->L4_col][$L4] = true; // Update descendent LUT's unset($update_cache[$L5][$this->L3_col][$L4]); unset($update_cache[$L5][$this->L2_col][$L4]); $update_cache[$L5]["keys"][$L4] = $db_result[$L5][$L4]; } } foreach ($L3s as $L3 => $L2s) { if (count($L2s) == 0) { if (FOX_sUtil::keyExists($L3, $db_result[$L5][$L4])) { // The L3 object now has authority $update_cache[$L5][$this->L3_col][$L4][$L3] = true; // Update descendent LUT's unset($update_cache[$L5][$this->L2_col][$L4][$L3]); $update_cache[$L5]["keys"][$L4][$L3] = $db_result[$L5][$L4][$L3]; } } foreach ($L2s as $L2 => $L1s) { if (count($L1s) == 0) { if (FOX_sUtil::keyExists($L2, $db_result[$L5][$L4][$L3])) { // The L2 object now has authority $update_cache[$L5][$this->L2_col][$L4][$L3][$L2] = true; $update_cache[$L5]["keys"][$L4][$L3][$L2] = $db_result[$L5][$L4][$L3][$L2]; } } foreach ($L1s as $L1 => $fake_var) { if (FOX_sUtil::keyExists($L1, $db_result[$L5][$L4][$L3][$L2])) { $update_cache[$L5]["keys"][$L4][$L3][$L2][$L1] = $db_result[$L5][$L4][$L3][$L2][$L1]; } } unset($L1, $fake_var); } unset($L2, $L1s); } unset($L3, $L2s); } unset($L4, $L3s); // Clear empty walks from the LUT's // ========================================================================== if (FOX_sUtil::keyExists($L5, $db_result)) { $update_cache[$L5][$this->L2_col] = FOX_sUtil::arrayPrune($update_cache[$L5][$this->L2_col], 3); $update_cache[$L5][$this->L3_col] = FOX_sUtil::arrayPrune($update_cache[$L5][$this->L3_col], 2); $update_cache[$L5][$this->L4_col] = FOX_sUtil::arrayPrune($update_cache[$L5][$this->L4_col], 1); } } unset($L5, $L4s); if ($this->debug_on) { extract($this->debug_handler->event(array('pid' => $this->process_id, 'text' => "db_result_transform_end", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'parent' => $this, 'vars' => compact(array_keys(get_defined_vars()))))); } } // ENDOF: if($db_result) } // ENDOF: if($db_fetch) } // ENDOF: if($cache_fetch) // Build the updated cache image, and generate the result from the image (this // lets us still return a result in the event of a cache write failure) // ========================================================================== if ($update_cache) { $cache_image = $this->cache; foreach ($update_cache as $page_id => $page_image) { $cache_image[$page_id] = $page_image; } unset($page_id, $page_image); } else { // Just bind by reference to save memory $cache_image =& $this->cache; } $result = array(); $valid = true; if ($this->debug_on) { extract($this->debug_handler->event(array('pid' => $this->process_id, 'text' => "result_build_start", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'parent' => $this, 'vars' => compact(array_keys(get_defined_vars()))))); } foreach ($get_data as $L5 => $L4s) { // Handle "true", "null" etc end nodes. The algorithm is implemented this // way to avoid excessive if-else nesting indentation. We know that any // non-array keys are valid end nodes because the trie passed validation // at the beginning of the class method if (!is_array($L4s)) { $L4s = array(); } if (count($L4s) == 0) { if (FOX_sUtil::keyExists($L5, $cache_image)) { $result[$L5] = $cache_image[$L5]['keys']; } else { $valid = false; } } foreach ($L4s as $L4 => $L3s) { if (!is_array($L3s)) { $L3s = array(); } if (count($L3s) == 0) { if (FOX_sUtil::keyExists($L4, $cache_image[$L5]['keys'])) { $result[$L5][$L4] = $cache_image[$L5]['keys'][$L4]; } else { $valid = false; } } foreach ($L3s as $L3 => $L2s) { if (!is_array($L2s)) { $L2s = array(); } if (count($L2s) == 0) { if (FOX_sUtil::keyExists($L3, $cache_image[$L5]['keys'][$L4])) { $result[$L5][$L4][$L3] = $cache_image[$L5]['keys'][$L4][$L3]; } else { $valid = false; } } foreach ($L2s as $L2 => $L1s) { if (!is_array($L1s)) { $L1s = array(); } if (count($L1s) == 0) { if (FOX_sUtil::keyExists($L2, $cache_image[$L5]['keys'][$L4][$L3])) { $result[$L5][$L4][$L3][$L2] = $cache_image[$L5]['keys'][$L4][$L3][$L2]; } else { $valid = false; } } foreach ($L1s as $L1 => $fake_var) { if (FOX_sUtil::keyExists($L1, $cache_image[$L5]['keys'][$L4][$L3][$L2])) { $result[$L5][$L4][$L3][$L2][$L1] = $cache_image[$L5]['keys'][$L4][$L3][$L2][$L1]; } else { $valid = false; } } unset($L1, $fake_var); } unset($L2, $L1s); } unset($L3, $L2s); } unset($L4, $L3s); } unset($L5, $L4s); if ($this->debug_on) { extract($this->debug_handler->event(array('pid' => $this->process_id, 'text' => "result_build_end", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'parent' => $this, 'vars' => compact(array_keys(get_defined_vars()))))); } if ($ctrl['r_mode'] == 'matrix') { if ($this->debug_on) { extract($this->debug_handler->event(array('pid' => $this->process_id, 'text' => "result_matrix_transform_start", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'parent' => $this, 'vars' => compact(array_keys(get_defined_vars()))))); } $flatten_ctrl = array('mode' => 'data'); // Set to 'data' mode so flattenAssocTrie() // returns the values inside the trie's end nodes $flatten_cols = array($this->L5_col, $this->L4_col, $this->L3_col, $this->L2_col, $this->L1_col, $this->L0_col); // has a key name to put the end node value in try { $result = FOX_trie::flattenAssocTrie($result, $flatten_cols, $flatten_ctrl); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 12, 'text' => "Error converting result to 'matrix' format", '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' => "result_matrix_transform_end", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'parent' => $this, 'vars' => compact(array_keys(get_defined_vars()))))); } } elseif ($ctrl['r_mode'] != 'trie') { throw new FOX_exception(array('numeric' => 13, 'text' => "Invalid ctrl['r_mode'] parameter", 'data' => $ctrl, 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => null)); } // Write updated page images to persistent cache // =========================================================== if ($update_cache) { // Trap no changed pages if ($this->debug_on) { extract($this->debug_handler->event(array('pid' => $this->process_id, 'text' => "persistent_cache_write_start", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'parent' => $this, 'vars' => compact(array_keys(get_defined_vars()))))); } try { self::writeCachePage($update_cache); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 14, 'text' => "Error writing to persistent cache", 'data' => array('update_cache' => $update_cache, 'result' => $result), '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_write_end", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'parent' => $this, 'vars' => compact(array_keys(get_defined_vars()))))); } } // Flush any locked persistent cache pages that were created // for keys which didn't exist in the database // =========================================================== if ($db_fetch) { $updated_pages = array(); if ($update_cache) { $updated_pages = array_keys($update_cache); } $flush_pages = array_diff(array_keys($db_fetch), $updated_pages); } if ($flush_pages) { if ($this->debug_on) { extract($this->debug_handler->event(array('pid' => $this->process_id, 'text' => "persistent_cache_flush_pages_start", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'parent' => $this, 'vars' => compact(array_keys(get_defined_vars()))))); } try { self::flushCachePage($flush_pages); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 15, 'text' => "Error flushing pages from persistent cache", 'data' => array('flush_pages' => $flush_pages), '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_flush_pages_end", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'parent' => $this, 'vars' => compact(array_keys(get_defined_vars()))))); } } // Overwrite the class cache with the new cache image // =========================================================== $this->cache = $cache_image; 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; }
/** * Optimizes the $args matrix passed during instantiations, and assembles it into an object trie * * @version 1.0 * @since 1.0 * * @return bool | Exception on failure. True on success. */ public function build() { if ($this->ctrl['mode'] == 'matrix') { if ($this->ctrl['optimize'] == true) { $this->columns = FOX_trie::optimizeMatrix($this->args, $this->columns); } if ($this->ctrl['hash_token_vals'] == true) { $args_array = FOX_trie::loftMatrixHash($this->args, $this->columns, $this->hash_table, $ctrl = null); } else { $args_array = FOX_trie::loftMatrix($this->args, $this->columns, $ctrl = null); } } else { if ($this->ctrl['optimize'] == true) { $flatten_ctrl = array('null_token' => $this->null_token); $flattened = FOX_trie::flattenAssocTrie($this->args, $this->columns, $flatten_ctrl); $this->columns = FOX_trie::optimizeMatrix($flattened, $this->columns); $loft_ctrl = array('null_token' => $this->null_token); $args_array = FOX_trie::loftMatrix($flattened, $this->columns, $loft_ctrl); } else { $args_array = $this->args; } } // Convert the array into a SQL statement and params array // ===================================================================== try { $this->iterator = new FOX_queryBuilder_whereMatrix_iterator(array('base' => $this, 'parent' => null, 'value' => $this->null_token, 'args' => $args_array, 'depth' => -1)); } catch (FOX_Exception $child) { throw new FOX_exception(array('numeric' => 1, 'text' => "Error creating root node", 'data' => array("args" => $this->args, "columns" => $this->columns, "max_depth" => $this->max_depth, "ctrl" => $this->ctrl), 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => $child)); } return true; }