/**
  * 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;
 }
 /**
  * Test fixture for validateMatrixRow() method, 'trie' mode, 'data' trie
  *
  * @version 1.0
  * @since 1.0
  * 
  * =======================================================================================
  */
 public function test_validateMatrixRow_trie_data()
 {
     $struct = array("table" => "FOX_dataStore_validators", "engine" => "InnoDB", "cache_namespace" => "FOX_dataStore_validators", "cache_strategy" => "paged", "cache_engine" => array("memcached", "redis", "apc", "thread"), "columns" => array("X5" => array("php" => "int", "sql" => "int", "format" => "%d", "width" => null, "flags" => "NOT NULL", "auto_inc" => false, "default" => null, "index" => true), "X4" => array("php" => "string", "sql" => "varchar", "format" => "%s", "width" => 32, "flags" => "NOT NULL", "auto_inc" => false, "default" => null, "index" => true), "X3" => array("php" => "int", "sql" => "int", "format" => "%d", "width" => null, "flags" => "NOT NULL", "auto_inc" => false, "default" => null, "index" => true), "X2" => array("php" => "string", "sql" => "varchar", "format" => "%s", "width" => 32, "flags" => "NOT NULL", "auto_inc" => false, "default" => null, "index" => true), "X1" => array("php" => "int", "sql" => "int", "format" => "%d", "width" => null, "flags" => "NOT NULL", "auto_inc" => false, "default" => null, "index" => true), "X0" => array("php" => "serialize", "sql" => "longtext", "format" => "%s", "width" => null, "flags" => "", "auto_inc" => false, "default" => null, "index" => false)));
     $cls = new FOX_dataStore_validator($struct);
     // PASS - Valid data trie, branch terminating at clip order, TRUE node
     // ####################################################################
     $ctrl = array('end_node_format' => 'trie', 'trie_ctrl' => array('order' => 3, 'mode' => 'data', 'allow_wildcard' => false, 'clip_order' => 2));
     $row = array('X5' => 1, 'X4' => 'Y', 'X3' => array(1 => array('X' => array(1 => true, 5 => true), 'Y' => true)));
     try {
         $result = $cls->validateMatrixRow($row, $ctrl);
     } catch (FOX_exception $child) {
         $this->fail($child->dumpString(1));
     }
     $this->assertEquals(true, $result);
     // PASS - Valid data trie, branch terminating at clip order, ARRAY node
     // ####################################################################
     $ctrl = array('end_node_format' => 'trie', 'trie_ctrl' => array('order' => 3, 'mode' => 'data', 'allow_wildcard' => false, 'clip_order' => 2));
     $row = array('X5' => 1, 'X4' => 'Y', 'X3' => array(1 => array('X' => array(1 => true, 5 => true), 'Y' => array())));
     try {
         $result = $cls->validateMatrixRow($row, $ctrl);
     } catch (FOX_exception $child) {
         $this->fail($child->dumpString(1));
     }
     $this->assertEquals(true, $result);
     // PASS - Valid data trie, L1 node values ignored
     // ####################################################################
     $ctrl = array('end_node_format' => 'trie', 'trie_ctrl' => array('order' => 3, 'mode' => 'data', 'allow_wildcard' => false, 'clip_order' => 2));
     $row = array('X5' => 1, 'X4' => 'Y', 'X3' => array(1 => array('X' => array(1 => true, 5 => "foo"))));
     try {
         $result = $cls->validateMatrixRow($row, $ctrl);
     } catch (FOX_exception $child) {
         $this->fail($child->dumpString(1));
     }
     $this->assertEquals(true, $result);
     // PASS - Valid data trie, implied trie order
     // ####################################################################
     $ctrl = array('end_node_format' => 'trie', 'trie_ctrl' => array('order' => null, 'mode' => 'data', 'allow_wildcard' => false, 'clip_order' => 2));
     $row = array('X5' => 1, 'X4' => 'Y', 'X3' => array(1 => array('X' => array(1 => true, 5 => "foo"))));
     try {
         $result = $cls->validateMatrixRow($row, $ctrl);
     } catch (FOX_exception $child) {
         $this->fail($child->dumpString(1));
     }
     $this->assertEquals(true, $result);
     // FAIL - Invalid L1 node data type
     // ####################################################################
     $ctrl = array('end_node_format' => 'trie', 'trie_ctrl' => array('order' => 3, 'mode' => 'data', 'allow_wildcard' => false, 'clip_order' => 2));
     $row = array('X5' => 1, 'X4' => 'Y', 'X3' => array(1 => array('X' => array(1 => true, "F" => true), 'Y' => array())));
     try {
         $result = $cls->validateMatrixRow($row, $ctrl);
     } catch (FOX_exception $child) {
         $this->fail($child->dumpString(1));
     }
     $this->assertNotEquals(true, $result);
     // FAIL - Invalid L2 node value
     // ####################################################################
     $ctrl = array('end_node_format' => 'trie', 'trie_ctrl' => array('order' => 3, 'mode' => 'data', 'allow_wildcard' => false, 'clip_order' => 2));
     $row = array('X5' => 1, 'X4' => 'Y', 'X3' => array(1 => array('X' => array(1 => true, 2 => true), 'Y' => "Fail")));
     try {
         $result = $cls->validateMatrixRow($row, $ctrl);
     } catch (FOX_exception $child) {
         $this->fail($child->dumpString(1));
     }
     $this->assertNotEquals(true, $result);
     // FAIL - Invalid L3 data type
     // ####################################################################
     $ctrl = array('end_node_format' => 'trie', 'trie_ctrl' => array('order' => 3, 'mode' => 'data', 'allow_wildcard' => false, 'clip_order' => 2));
     $row = array('X5' => 1, 'X4' => 'Y', 'X3' => array(1 => array('X' => array(1 => true, 2 => true), 'Y' => true), "F" => array('X' => array(1 => true, 2 => true), 'Y' => true)));
     try {
         $result = $cls->validateMatrixRow($row, $ctrl);
     } catch (FOX_exception $child) {
         $this->fail($child->dumpString(1));
     }
     $this->assertNotEquals(true, $result);
     // FAIL - Invalid L3 value
     // ####################################################################
     $ctrl = array('end_node_format' => 'trie', 'trie_ctrl' => array('order' => 3, 'mode' => 'data', 'allow_wildcard' => false, 'clip_order' => 2));
     $row = array('X5' => 1, 'X4' => 'Y', 'X3' => array(1 => array('X' => array(1 => true, 2 => true), 'Y' => true), 2 => "FAIL"));
     try {
         $result = $cls->validateMatrixRow($row, $ctrl);
     } catch (FOX_exception $child) {
         $this->fail($child->dumpString(1));
     }
     $this->assertNotEquals(true, $result);
     // FAIL - Branch terminates above clip plane
     // ####################################################################
     $ctrl = array('end_node_format' => 'trie', 'trie_ctrl' => array('order' => 3, 'mode' => 'data', 'allow_wildcard' => false, 'clip_order' => 2));
     $row = array('X5' => 1, 'X4' => 'Y', 'X3' => array(1 => array('X' => array(1 => true, 2 => true), 'Y' => true), 2 => true));
     try {
         $result = $cls->validateMatrixRow($row, $ctrl);
     } catch (FOX_exception $child) {
         $this->fail($child->dumpString(1));
     }
     $this->assertNotEquals(true, $result);
     // FAIL - Branch terminates below clip plane, but not at L1
     // ####################################################################
     $ctrl = array('end_node_format' => 'trie', 'trie_ctrl' => array('order' => 3, 'mode' => 'data', 'allow_wildcard' => false, 'clip_order' => 3));
     $row = array('X5' => 1, 'X4' => 'Y', 'X3' => array(1 => array('X' => array(1 => true, 2 => true), 'Y' => true)));
     try {
         $result = $cls->validateMatrixRow($row, $ctrl);
     } catch (FOX_exception $child) {
         $this->fail($child->dumpString(1));
     }
     $this->assertNotEquals(true, $result);
     // FAIL - L3 isn't a trie
     // ####################################################################
     $ctrl = array('end_node_format' => 'trie', 'trie_ctrl' => array('order' => 3, 'mode' => 'data', 'allow_wildcard' => false, 'clip_order' => 2));
     $row = array('X5' => 1, 'X4' => 'Y', 'X3' => "FAIL");
     try {
         $result = $cls->validateMatrixRow($row, $ctrl);
     } catch (FOX_exception $child) {
         $this->fail($child->dumpString(1));
     }
     $this->assertNotEquals(true, $result);
     // FAIL - Invalid L4 value
     // ####################################################################
     $ctrl = array('end_node_format' => 'trie', 'trie_ctrl' => array('order' => 3, 'mode' => 'data', 'allow_wildcard' => false, 'clip_order' => 2));
     $row = array('X5' => 1, 'X4' => '2', 'X3' => array(1 => array('X' => array(1 => true, 2 => true), 'Y' => true)));
     try {
         $result = $cls->validateMatrixRow($row, $ctrl);
     } catch (FOX_exception $child) {
         $this->fail($child->dumpString(1));
     }
     $this->assertNotEquals(true, $result);
     // FAIL - Invalid L5 value
     // ####################################################################
     $ctrl = array('end_node_format' => 'trie', 'trie_ctrl' => array('order' => 3, 'mode' => 'data', 'allow_wildcard' => false, 'clip_order' => 2));
     $row = array('X5' => 2.4, 'X4' => 'Y', 'X3' => array(1 => array('X' => array(1 => true, 2 => true), 'Y' => true), 2 => "FAIL"));
     try {
         $result = $cls->validateMatrixRow($row, $ctrl);
     } catch (FOX_exception $child) {
         $this->fail($child->dumpString(1));
     }
     $this->assertNotEquals(true, $result);
     // EXCEPTION - Invalid ['trie_ctrl']['order']
     // ####################################################################
     $ctrl = array('end_node_format' => 'trie', 'trie_ctrl' => array('order' => 99, 'mode' => 'data', 'allow_wildcard' => false, 'clip_order' => 2));
     $row = array('X5' => '1', 'X4' => 'Y', 'X3' => array(1 => array('X' => array(1 => true, 2 => true), 'Y' => true), 'F' => true));
     try {
         $result = $cls->validateMatrixRow($row, $ctrl);
         // Execution will halt on the previous line if validateMatrixRow() throws an exception
         $this->fail("Method validateMatrixRow() failed to throw an exception on invalid trie ['trie_ctrl']['order']");
     } catch (FOX_exception $child) {
     }
     // EXCEPTION - Missing ['trie_ctrl']['clip_order']
     // ####################################################################
     $ctrl = array('end_node_format' => 'trie', 'trie_ctrl' => array('order' => 2, 'mode' => 'data', 'allow_wildcard' => false, 'clip_order' => null));
     $row = array('X5' => '1', 'X4' => 'Y', 'X3' => array(1 => array('X' => array(1 => true, 2 => true), 'Y' => true), 'F' => true));
     try {
         $result = $cls->validateMatrixRow($row, $ctrl);
         // Execution will halt on the previous line if validateMatrixRow() throws an exception
         $this->fail("Method validateMatrixRow() failed to throw an exception on missing trie ['trie_ctrl']['clip_order']");
     } catch (FOX_exception $child) {
     }
     // EXCEPTION - Wildcards on data trie
     // ####################################################################
     $ctrl = array('end_node_format' => 'trie', 'trie_ctrl' => array('order' => 3, 'mode' => 'data', 'allow_wildcard' => true, 'clip_order' => 2));
     $row = array('X5' => '1', 'X4' => 'Y', 'X3' => array(1 => array('X' => array(1 => true, 2 => true), 'Y' => true), 'F' => true));
     try {
         $result = $cls->validateMatrixRow($row, $ctrl);
         // Execution will halt on the previous line if validateMatrixRow() throws an exception
         $this->fail("Method validateMatrixRow() failed to throw an exception on wildcards on data trie");
     } catch (FOX_exception $child) {
     }
 }
 /**
  * Deletes one or more plugins from the datastore
  *
  * @version 1.0
  * @since 1.0
  *
  * @param string/array $plugin | Single plugin as string. Multiple plugins as array of string.
  * @return int | Exception on failure. Number of db rows changed on success.
  */
 public function dropPlugin($plugin)
 {
     $struct = $this->_struct();
     $validator_result = array();
     try {
         // All of the validator calls are wrapped in a single try{} block to reduce code size. If
         // a validator throws an exception, it will contain all info needed for debugging
         $validator = new FOX_dataStore_validator($struct);
         // If a single tree name is sent in, we validate it individually instead of automatically
         // spinning it into an array and validating the array. This lets us trap strings that PHP
         // automatically converts to ints ("17")
         if (!is_array($plugin)) {
             $validator_result['plugin'] = $validator->validateKey(array('type' => $struct['columns'][$this->L4_col]['php'], 'format' => 'scalar', 'var' => $plugin));
         } else {
             foreach ($plugin as $key => $val) {
                 $validator_result['plugin'] = $validator->validateKey(array('type' => $struct['columns'][$this->L4_col]['php'], 'format' => 'scalar', 'var' => $val));
                 if ($validator_result['plugin'] !== true) {
                     break;
                 }
             }
             unset($key, $val);
         }
     } catch (FOX_exception $child) {
         throw new FOX_exception(array('numeric' => 1, 'text' => "Error in validator class", '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)
     foreach ($validator_result as $key => $val) {
         if ($val !== true) {
             throw new FOX_exception(array('numeric' => 2, 'text' => "Invalid " . $key . " name", 'data' => array('plugin' => $plugin, 'msg' => $val), 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => null));
         }
     }
     unset($key, $val);
     $drop_ctrl = array('validate' => false);
     try {
         $rows_changed = parent::dropL4($plugin, $drop_ctrl);
     } catch (FOX_exception $child) {
         throw new FOX_exception(array('numeric' => 3, 'text' => "Error calling parent::dropL4()", 'data' => array('plugin' => $plugin), 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => $child));
     }
     return (int) $rows_changed;
 }