/** * 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; }