/**
  * Deletes all data from a database table
  *
  * @version 1.0
  * @since 1.0
  * @return bool | Exception on failure. True on success.
  */
 public function truncate()
 {
     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())))));
     }
     $db = new FOX_db(array('pid' => $this->process_id));
     try {
         $db->runTruncateTable($this->_struct());
     } catch (FOX_exception $child) {
         throw new FOX_exception(array('numeric' => 1, 'text' => "Failed to truncate table", 'data' => array('struct' => $this->_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 true;
 }
 /**
  * Returns an array of logged events based on supplied parameters. This function integrates with a jQuery
  * datagrid control in the admin screens, allowing arbitrary sorting and filtering of events.
  *
  * @param array $args | Args in the form: array("col"=>column_name, "op" => "<, >, =, !=", "val" => "int | string | array()")
  *	    => ARR @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 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 object/array $columns | Either array with specific columns to include/exclue or anything else to return all columns.
  *	=> ARR @param int '' | Array index
  *	    => VAL @param string $table_class | Class of table that the column is from.
  *	    => VAL @param string $table_alias | Alias table that the column is from. Used instead of table_class not required
  *	    => VAL @param string $col_name | Name of the column
  *	    => VAL @param string $col_alias | Alias of the column
  *	    => VAL @param bool $count | True to count this column
  *	    => VAL @param bool/array $sum | True sum this column, array sums multiple columns
  *	        => ARR @param int '' | Array index
  *			=> VAL @param string $table_alias | Table alias of table that the column is from. if table alias is not set the default is t(number)
  *			=> VAL @param string $col_name | Name of the column
  *			=> VAL @param string $col_alias | Column alias used instead of table alias and col_name
  *			=> VAL @param bool $count | True to count this column
  *			=> VAL @param string $op | Operation to perform on column value +,- or *(muliple) default +
  *
  * @param array $ctrl | Control parameters for the query
  *	=> VAL @param int $page | Set current page (used when traversing multi-page data sets)
  *	=> VAL @param int $per_page | Max number of rows to return in a query / number of rows to return per page when transversing a multi-page data set
  *	=> VAL @param int $offset | Shift results page forward or backward "n" items within the returned data set
  *	=> ARR @param array $sort | Sort results by supplied parameters. Multi-dimensional sorts possible by passing multiple arrays.
  *	    => ARR @param int '' | Array index
  *		=> VAL @param string $class | Class name that owns the table
  *		=> VAL @param string $col | Name of column to sort by
  *		=> VAL @param string $col_alias | Column alias used instead of class and col. not required
  *		=> VAL @param string/array $sort | Direction to sort in. "ASC", "DESC", array(val, val, val) where position in array
  *						   is the desired position in the results set for the row or rows with columm matching val
  *	=> ARR @param array $group | Apply SQL GROUP to columns. Multi-dimensional group possible by passing multiple arrays.
  *	    => ARR @param int '' | Array index
  *		=> VAL @param string $class | Class name that owns the table
  *		=> VAL @param string $col | Name of column to apply GROUP to
  *		=> VAL @param string $col_alias | Column alias used instead of class and col. not required
  *		=> VAL @param string $sort | Direction to sort in. "ASC" | "DESC"
  *	=> VAL @param string $format | @see FOX_db::runQuery() for detailed info on format string
  *	=> VAL @param string $key_col | Column name to get key names from when using $format="key" or $format="asc"
  *	=> VAL @param string $asc_col | Column name to use as value when using $format="asc"
  *
  * @param bool $return_tokens | True to use dictionary and return words for tree, branch and node
  *
  * @return bool/int/array | False on failure. Int on count. Array of rows on success.
  */
 public function query($args = null, $columns = null, $ctrl = null, $return_tokens = true)
 {
     if (!isset($ctrl)) {
         $ctrl = array();
     }
     if (!isset($ctrl['format'])) {
         $ctrl['format'] = "array_array";
     }
     $join_args = array("tree" => array(), "branch" => array(), "node" => array());
     if (is_array($args)) {
         // Process args in case dic entries are used instead of numbers
         foreach ($args as $arg) {
             // check dic columns
             if (in_array($arg["col"], array('tree', 'branch', 'node'))) {
                 // if val is string or array of strings
                 if (!is_numeric($arg["val"]) || is_array($arg["val"]) && !is_numeric($arg["val"][0])) {
                     // if val is string or array of strings then add to join_args and don't add to processed_args
                     $join_args[$arg['col']][] = $args;
                     continue;
                 }
             }
             $processed_args[] = $arg;
         }
     }
     $db = new FOX_db();
     // Check if need to use runSelectLeftJoin
     $num_join_args = count($join_args['tree']) + count($join_args['branch']) + count($join_args['node']);
     if ($return_tokens || $num_join_args > 0) {
         if (!isset($ctrl['group'])) {
             $ctrl["group"] = array(array("class" => self::$struct, "col" => "id", "sort" => "ASC"));
         }
         $primary = array("class" => self::$struct, "args" => $processed_args);
         $join = array(array("class" => "FOX_log_dictionary_tree", "on" => array("pri" => "tree", "op" => "=", "sec" => "id"), "args" => $join_args['tree']), array("class" => "FOX_log_dictionary_branch", "on" => array("pri" => "branch", "op" => "=", "sec" => "id"), "args" => $join_args['branch']), array("class" => "FOX_log_dictionary_node", "on" => array("pri" => "node", "op" => "=", "sec" => "id"), "args" => $join_args['node']));
         if (is_null($columns)) {
             if ($return_tokens) {
                 $columns = array(array("table_alias" => "t1", "col_name" => "id", "col_alias" => "id"), array("table_alias" => "t2", "col_name" => "token", "col_alias" => "tree"), array("table_alias" => "t3", "col_name" => "token", "col_alias" => "branch"), array("table_alias" => "t4", "col_name" => "token", "col_alias" => "node"), array("table_alias" => "t1", "col_name" => "user_id", "col_alias" => "user_id"), array("table_alias" => "t1", "col_name" => "level", "col_alias" => "level"), array("table_alias" => "t1", "col_name" => "date", "col_alias" => "date"), array("table_alias" => "t1", "col_name" => "summary", "col_alias" => "summary"), array("table_alias" => "t1", "col_name" => "data", "col_alias" => "data"));
             } else {
                 $columns = array(array("table_alias" => "t1", "col_name" => "id", "col_alias" => "id"), array("table_alias" => "t1", "col_name" => "tree", "col_alias" => "tree"), array("table_alias" => "t1", "col_name" => "branch", "col_alias" => "branch"), array("table_alias" => "t1", "col_name" => "node", "col_alias" => "node"), array("table_alias" => "t1", "col_name" => "user_id", "col_alias" => "user_id"), array("table_alias" => "t1", "col_name" => "level", "col_alias" => "level"), array("table_alias" => "t1", "col_name" => "date", "col_alias" => "date"), array("table_alias" => "t1", "col_name" => "summary", "col_alias" => "summary"), array("table_alias" => "t1", "col_name" => "data", "col_alias" => "data"));
             }
         }
         try {
             $result = $db->runSelectQueryLeftJoin($primary, $join, $columns, $ctrl);
         } catch (FOX_exception $child) {
             throw new FOX_exception(array('numeric' => 3, 'text' => "Error reading from DB \n", 'data' => array('primary' => $primary, 'join' => $join, 'columns' => $columns, 'ctrl' => $ctrl), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child));
             return false;
         }
     } else {
         if (!is_null($columns) && count($columns) > 0) {
             $select_columns["mode"] = "include";
             if (count($columns) == 1) {
                 $select_columns["col"] = $columns[0]["col_name"];
             } else {
                 foreach ($columns as $col) {
                     $select_columns["col"][] = $col["col_name"];
                 }
             }
         }
         try {
             $result = $db->runSelectQuery(self::$struct, $processed_args, $select_columns, $ctrl);
         } catch (FOX_exception $child) {
             throw new FOX_exception(array('numeric' => 4, 'text' => "Error reading from DB \n", 'data' => array('primary' => $primary, 'join' => $join, 'columns' => $columns, 'ctrl' => $ctrl), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child));
             return false;
         }
     }
     if ($result == 0) {
         return false;
     } else {
         return $result;
     }
 }
 /**
  * Deletes the entire keyring for one or more groups
  *
  * @version 1.0
  * @since 1.0
  *
  * @param int $group_id | id of the group as int. Multiple groups as array of int.
  * @return int | Number of keys affected.
  */
 public function dropGroup($group_id)
 {
     global $fox;
     $db = new FOX_db();
     // Drop the keys from the db
     $args = array(array("col" => "group_id", "op" => "=", "val" => $group_id));
     try {
         $result = $db->runDeleteQuery(self::$struct, $args);
     } catch (FOX_exception $child) {
         throw new FOX_exception(array('numeric' => 1, 'text' => "DB delete exception", 'data' => $args, 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child));
     }
     // Update the cache
     if ($result) {
         if (!is_array($group_id)) {
             $group_id = array($group_id);
         }
         foreach ($group_id as $group) {
             unset($this->cache["keys"][$group]);
             unset($this->cache["groups"][$group]);
         }
         unset($group);
         try {
             $cache_ok = self::saveCache();
         } catch (FOX_exception $child) {
             throw new FOX_exception(array('numeric' => 2, 'text' => "saveCache exception", 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child));
         }
         if ($cache_ok) {
             return $result;
         } else {
             return false;
         }
     } else {
         return $result;
     }
 }
 /**
  * Removes one or more modules from the database and cache.
  *
  * @version 1.0
  * @since 1.0
  * 
  * @param string $module_type | Single module_type as string.
  * @param int/array $module_ids | Single module_id as int. Multiple module_id's as array of int.
  * 
  * @return int | Exception on failure. Int number of db rows changed on success.
  */
 public function deleteModule($module_type, $module_ids)
 {
     $db = new FOX_db();
     $struct = self::_struct();
     if (empty($module_type) || !is_string($module_type)) {
         throw new FOX_exception(array('numeric' => 1, 'text' => "Invalid module_types parameter", 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => null));
     }
     if (empty($module_ids)) {
         throw new FOX_exception(array('numeric' => 2, 'text' => "Invalid module_ids parameter", 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => null));
     }
     if (!is_array($module_ids)) {
         // Handle single int as input
         $module_ids = array($module_ids);
     }
     // Lock the cache
     // ===========================================================
     try {
         self::lockCache();
     } catch (FOX_exception $child) {
         throw new FOX_exception(array('numeric' => 2, 'text' => "Error locking cache", 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child));
     }
     // Update the database
     // ===========================================================
     $args = array(array("col" => "module_type", "op" => "=", "val" => $module_type), array("col" => "module_id", "op" => "=", "val" => $module_ids));
     try {
         $rows_changed = $db->runDeleteQuery($struct, $args);
     } catch (FOX_exception $child) {
         throw new FOX_exception(array('numeric' => 3, 'text' => "Error deleting from database", 'data' => array('args' => $args), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child));
     }
     // Flush the cache
     // =============================================================
     // NOTE: this is a case where it's not practical to rebuild the cache. We'd have to run an
     // additional query to fetch the old module_slug and php_class values to clear them from the cache
     try {
         self::flushCache();
     } catch (FOX_exception $child) {
         throw new FOX_exception(array('numeric' => 4, 'text' => "Error flushing cache", 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child));
     }
     return (int) $rows_changed;
 }
 /**
  * Test fixture for addMulti() method (matrix mode)
  *
  * @version 1.0
  * @since 1.0
  * 
  * =======================================================================================
  */
 function test_addMulti_matrix()
 {
     $test_obj = new stdClass();
     $test_obj->foo = "11";
     $test_obj->bar = "test_Bar";
     $test_data = array(array('L4' => 'A', 'L3' => 'X', 'L2' => 'K', 'L1' => 1, 'L0' => null), array('L4' => 'A', 'L3' => 'X', 'L2' => 'K', 'L1' => 2, 'L0' => false), array('L4' => 'A', 'L3' => 'X', 'L2' => 'K', 'L1' => 5, 'L0' => true), array('L4' => 'A', 'L3' => 'X', 'L2' => 'Z', 'L1' => 3, 'L0' => (int) 0), array('L4' => 'A', 'L3' => 'Y', 'L2' => 'K', 'L1' => 1, 'L0' => (int) 1), array('L4' => 'A', 'L3' => 'Y', 'L2' => 'K', 'L1' => 2, 'L0' => (int) -1), array('L4' => 'A', 'L3' => 'Y', 'L2' => 'K', 'L1' => 3, 'L0' => (double) 1.7), array('L4' => 'A', 'L3' => 'Y', 'L2' => 'Z', 'L1' => 4, 'L0' => (double) -1.6), array('L4' => 'B', 'L3' => 'X', 'L2' => 'K', 'L1' => 1, 'L0' => (string) "foo"), array('L4' => 'B', 'L3' => 'X', 'L2' => 'K', 'L1' => 2, 'L0' => array(null, true, false, 1, 1.0, "foo")), array('L4' => 'B', 'L3' => 'X', 'L2' => 'Z', 'L1' => 3, 'L0' => $test_obj));
     // Load class with data
     // ===============================================================
     try {
         $ctrl = array('mode' => 'matrix');
         $set_ok = $this->cls->addMulti($test_data, $ctrl);
     } catch (FOX_exception $child) {
         $this->fail($child->dumpString(array('depth' => 50, 'data' => true)));
     }
     // Should return number of L1's added
     $this->assertEquals(11, $set_ok);
     // Test adding some  duplicate itemes
     // ===============================================================
     try {
         $dupe_data = array(array('L4' => 'A', 'L3' => 'X', 'L2' => 'K', 'L1' => 1, 'L0' => null), array('L4' => 'A', 'L3' => 'X', 'L2' => 'K', 'L1' => 2, 'L0' => false), array('L4' => 'A', 'L3' => 'X', 'L2' => 'K', 'L1' => 1, 'L0' => true), array('L4' => 'A', 'L3' => 'X', 'L2' => 'Z', 'L1' => 3, 'L0' => (int) 0), array('L4' => 'A', 'L3' => 'Y', 'L2' => 'K', 'L1' => 1, 'L0' => (int) 1), array('L4' => 'A', 'L3' => 'Y', 'L2' => 'K', 'L1' => 2, 'L0' => (int) -1), array('L4' => 'A', 'L3' => 'Y', 'L2' => 'K', 'L1' => 3, 'L0' => (double) 1.7), array('L4' => 'A', 'L3' => 'Y', 'L2' => 'Z', 'L1' => 4, 'L0' => (double) -1.6));
         $ctrl = array('mode' => 'matrix');
         $this->cls->addMulti($dupe_data, $ctrl);
         // Execution will halt on the previous line if addMulti() throws an exception
         $this->fail("Method addMulti() failed to throw an exception on duplicate entry");
     } catch (FOX_exception $child) {
     }
     // Check cache state
     // ===============================================================
     // NOTE: the LUT's won't be set at this point, because we haven't done any
     // database reads that give objects authority
     $check = array('A' => array('keys' => array('X' => array('K' => array(1 => null, 2 => false, 5 => true), 'Z' => array(3 => (int) 0)), 'Y' => array('K' => array(1 => (int) 1, 2 => (int) -1, 3 => (double) 1.7), 'Z' => array(4 => (double) -1.6)))), 'B' => array('keys' => array('X' => array('K' => array(1 => (string) "foo", 2 => array(null, true, false, 1, 1.0, "foo")), 'Z' => array(3 => $test_obj)))));
     $this->assertEquals($check, $this->cls->cache);
     // Check db state
     // ===============================================================
     $check = array('A' => array('X' => array('K' => array(1 => null, 2 => false, 5 => true), 'Z' => array(3 => (int) 0)), 'Y' => array('K' => array(1 => (int) 1, 2 => (int) -1, 3 => (double) 1.7), 'Z' => array(4 => (double) -1.6))), 'B' => array('X' => array('K' => array(1 => (string) "foo", 2 => array(null, true, false, 1, 1.0, "foo")), 'Z' => array(3 => $test_obj))));
     $db = new FOX_db();
     $columns = null;
     $ctrl = array('format' => 'array_key_array', 'key_col' => array('L4', 'L3', 'L2', 'L1'));
     try {
         $struct = $this->cls->_struct();
         $result = $db->runSelectQuery($struct, $args = null, $columns, $ctrl);
     } catch (FOX_exception $child) {
         $this->fail($child->dumpString(1));
     }
     $this->assertEquals($check, $result);
 }
 function test_dropId_Multi()
 {
     // load db
     // ======================================================
     $add_tokens = array("one", "two", "three", "four", "five");
     try {
         $add_result = $this->cls->addToken($add_tokens);
     } catch (FOX_exception $child) {
         $this->fail($child->dumpString(array('depth' => 50, 'data' => true)));
     }
     // Test  single dropId
     // ======================================================
     try {
         $drop_ids = array(1, 2, 3, 4, 5);
         $this->assertEquals(5, $this->cls->dropId($drop_ids));
     } catch (FOX_exception $child) {
         $this->fail($child->dumpString(array('depth' => 50, 'data' => true)));
     }
     // Check Db has no rows
     // ======================================================
     try {
         $db = new FOX_db();
         $this->assertEquals(false, $db->runSelectQuery(FOX_test_dictionary::$struct));
     } catch (FOX_exception $child) {
         $this->fail($child->dumpString(array('depth' => 50, 'data' => true)));
     }
     // Check Class cache is empty
     $this->assertEquals(array('ids' => array(), 'tokens' => array()), $this->cls->cache);
 }
 /**
  * Test fixture for setMulti() method (matrix mode)
  *
  * @version 1.0
  * @since 1.0
  * 
  * =======================================================================================
  */
 function test_setMulti_matrix()
 {
     $test_obj = new stdClass();
     $test_obj->foo = "11";
     $test_obj->bar = "test_Bar";
     $test_data = array(array('L5' => 1, 'L4' => 'X', 'L3' => 'K', 'L2' => 'K', 'L1' => 1, 'L0' => null), array('L5' => 1, 'L4' => 'X', 'L3' => 'K', 'L2' => 'K', 'L1' => 2, 'L0' => false), array('L5' => 1, 'L4' => 'X', 'L3' => 'K', 'L2' => 'T', 'L1' => 1, 'L0' => true), array('L5' => 1, 'L4' => 'X', 'L3' => 'Z', 'L2' => 'Z', 'L1' => 3, 'L0' => (int) 0), array('L5' => 1, 'L4' => 'Y', 'L3' => 'K', 'L2' => 'K', 'L1' => 1, 'L0' => (int) 1), array('L5' => 1, 'L4' => 'Y', 'L3' => 'K', 'L2' => 'K', 'L1' => 2, 'L0' => (int) -1), array('L5' => 1, 'L4' => 'Y', 'L3' => 'K', 'L2' => 'T', 'L1' => 3, 'L0' => (double) 1.7), array('L5' => 1, 'L4' => 'Y', 'L3' => 'Z', 'L2' => 'Z', 'L1' => 4, 'L0' => (double) -1.6), array('L5' => 2, 'L4' => 'X', 'L3' => 'K', 'L2' => 'K', 'L1' => 1, 'L0' => (string) "foo"), array('L5' => 2, 'L4' => 'X', 'L3' => 'K', 'L2' => 'K', 'L1' => 2, 'L0' => array(null, true, false, 1, 1.0, "foo")), array('L5' => 2, 'L4' => 'X', 'L3' => 'Z', 'L2' => 'Z', 'L1' => 3, 'L0' => $test_obj));
     // Load class with data
     // ===============================================================
     try {
         $ctrl = array('mode' => 'matrix');
         $set_ok = $this->cls->setMulti($test_data, $ctrl);
     } catch (FOX_exception $child) {
         $this->fail($child->dumpString(array('depth' => 50, 'data' => true)));
     }
     // Should return number of L1's added
     $this->assertEquals(11, $set_ok);
     // Test adding some  duplicate itemes
     // ===============================================================
     try {
         $dupe_data = array(array('L5' => 1, 'L4' => 'X', 'L3' => 'K', 'L2' => 'K', 'L1' => 1, 'L0' => null), array('L5' => 1, 'L4' => 'X', 'L3' => 'K', 'L2' => 'K', 'L1' => 2, 'L0' => false), array('L5' => 1, 'L4' => 'X', 'L3' => 'K', 'L2' => 'T', 'L1' => 1, 'L0' => true), array('L5' => 1, 'L4' => 'X', 'L3' => 'Z', 'L2' => 'Z', 'L1' => 3, 'L0' => (int) 0), array('L5' => 1, 'L4' => 'Y', 'L3' => 'K', 'L2' => 'K', 'L1' => 1, 'L0' => (int) 1), array('L5' => 1, 'L4' => 'Y', 'L3' => 'K', 'L2' => 'K', 'L1' => 2, 'L0' => (int) -1), array('L5' => 1, 'L4' => 'Y', 'L3' => 'K', 'L2' => 'T', 'L1' => 3, 'L0' => (double) 1.7), array('L5' => 1, 'L4' => 'Y', 'L3' => 'Z', 'L2' => 'Z', 'L1' => 4, 'L0' => (double) -1.6));
         $ctrl = array('mode' => 'matrix');
         $rows_changed = $this->cls->setMulti($dupe_data, $ctrl);
         // Should return (int)0 to indicate no rows were changed
         $this->assertEquals(0, $rows_changed);
     } catch (FOX_exception $child) {
         // Shouldn't throw an exception because the set() method allows
         // existing rows to be overwritten
         $this->fail($child->dumpString(array('depth' => 50, 'data' => true)));
     }
     // Check cache state
     // ===============================================================
     // NOTE: the LUT's won't be set at this point, because we haven't done any
     // database reads that give objects authority
     $check = array(1 => array('keys' => array('X' => array('K' => array('K' => array(1 => null, 2 => false), 'T' => array(1 => true)), 'Z' => array('Z' => array(3 => (int) 0))), 'Y' => array('K' => array('K' => array(1 => (int) 1, 2 => (int) -1), 'T' => array(3 => (double) 1.7)), 'Z' => array('Z' => array(4 => (double) -1.6))))), 2 => array('keys' => array('X' => array('K' => array('K' => array(1 => (string) "foo", 2 => array(null, true, false, 1, 1.0, "foo"))), 'Z' => array('Z' => array(3 => $test_obj))))));
     $this->assertEquals($check, $this->cls->cache);
     // Check db state
     // ===============================================================
     $check = array(1 => array('X' => array('K' => array('K' => array(1 => null, 2 => false), 'T' => array(1 => true)), 'Z' => array('Z' => array(3 => (int) 0))), 'Y' => array('K' => array('K' => array(1 => (int) 1, 2 => (int) -1), 'T' => array(3 => (double) 1.7)), 'Z' => array('Z' => array(4 => (double) -1.6)))), 2 => array('X' => array('K' => array('K' => array(1 => (string) "foo", 2 => array(null, true, false, 1, 1.0, "foo"))), 'Z' => array('Z' => array(3 => $test_obj)))));
     $db = new FOX_db();
     $columns = null;
     $ctrl = array('format' => 'array_key_array', 'key_col' => array('L5', 'L4', 'L3', 'L2', 'L1'));
     try {
         $struct = $this->cls->_struct();
         $result = $db->runSelectQuery($struct, $args = null, $columns, $ctrl);
     } catch (FOX_exception $child) {
         $this->fail($child->dumpString(1));
     }
     $this->assertEquals($check, $result);
 }
 /**
  * Test fixture for dropGlobal() method, L4, multi item
  *
  * @version 1.0
  * @since 1.0
  * 
  * =======================================================================================
  */
 public function test_dropGlobal_L4_multi()
 {
     self::loadData();
     // Drop objects
     // ####################################################################
     $drop_ctrl = array("validate" => true);
     try {
         $rows_changed = $this->cls->dropGlobal(4, array('X', 'Y'), $drop_ctrl);
     } catch (FOX_exception $child) {
         $this->fail($child->dumpString(1));
     }
     // Should report 19 rows were dropped
     $this->assertEquals(19, $rows_changed);
     // Verify db state
     // ####################################################################
     $db = new FOX_db();
     $columns = null;
     $args = null;
     $ctrl = array('format' => 'array_key_array', 'key_col' => array('L5', 'L4', 'L3', 'L2', 'L1'));
     try {
         $result = $db->runSelectQuery($this->cls->_struct(), $args, $columns, $ctrl);
     } catch (FOX_exception $child) {
         $this->fail($child->dumpString(1));
     }
     $this->assertEquals(null, $result);
     // Check class cache state
     // ####################################################################
     $check_cache = array();
     $this->assertEquals($check_cache, $this->cls->cache);
     // Verify persistent cache state by reading-back all items
     // ####################################################################
     $request = array(1 => array(), 2 => array(), 3 => array());
     $valid = false;
     try {
         $result = $this->cls->getMulti($request, $ctrl, $valid);
     } catch (FOX_exception $child) {
         $this->fail($child->dumpString(1));
     }
     $this->assertEquals(false, $valid);
     // Should report invalid because
     // a requested L5 doesn't exist
     $this->assertEquals(array(), $result);
 }
 /**
  * Drops one or more branches for ALL TREES in the datastore
  *
  * @version 1.0
  * @since 1.0
  *
  * @param string/array $branches | single branch as string. Multiple branches as array of string.
  * @return int | Exception on failure. Number of db rows changed on success.
  */
 public function dropSiteBranch($branches)
 {
     $db = new FOX_db();
     $struct = $this->_struct();
     // Lock the cache
     // ===========================================================
     try {
         self::lockCache();
     } catch (FOX_exception $child) {
         throw new FOX_exception(array('numeric' => 1, 'text' => "Error locking cache", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => $child));
     }
     // Update the database
     // ===========================================================
     $args = array(array("col" => "branch", "op" => "=", "val" => $branches));
     try {
         $rows_changed = $db->runDeleteQuery($struct, $args);
     } catch (FOX_exception $child) {
         throw new FOX_exception(array('numeric' => 2, 'text' => "Error deleting from database", 'data' => array('args' => $args), 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => $child));
     }
     // Flush the cache
     // ===========================================================
     try {
         self::flushCache();
     } catch (FOX_exception $child) {
         throw new FOX_exception(array('numeric' => 3, 'text' => "Error flushing cache", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => $child));
     }
     return (int) $rows_changed;
 }
 /**
  * Deletes the entire module data store, and flushes the cache. Generally
  * used for testing and debug.
  *
  * @version 1.0
  * @since 1.0
  * @return bool | Exception on failure. True on success.
  */
 public function dropAll()
 {
     $db = new FOX_db();
     $struct = $this->_struct();
     try {
         $db->runTruncateTable($struct);
     } catch (FOX_exception $child) {
         throw new FOX_exception(array('numeric' => 1, 'text' => "Error while clearing the database", 'data' => null, 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => $child));
     }
     // Since this operation affects *all* module_id's, we have to flush
     // the entire cache namespace
     try {
         self::flushCache();
     } catch (FOX_exception $child) {
         throw new FOX_exception(array('numeric' => 2, 'text' => "Cache flush error", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => $child));
     }
 }
 /**
  * Drops one or more keys from the database and cache for ALL USERS ON THE SITE. Generally used when
  * uninstalling or upgfoxing apps, or for managing admin-assigned arbitrary keys.
  *
  * @version 1.0
  * @since 1.0
  *
  * @param int/array $key_id | Single key_id as int. Multiple key_id's as array of ints.
  * @return bool | False on failure. True on success.
  */
 public function revokeKeySitewide($key_id)
 {
     global $fox;
     $db = new FOX_db();
     $args = array(array("col" => "key_id", "op" => "=", "val" => $key_id));
     try {
         $rows_changed = $db->runDeleteQuery(self::$struct, $args);
     } catch (FOX_exception $child) {
         throw new FOX_exception(array('numeric' => 1, 'text' => "DB delete exception", 'data' => array("args" => $args), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child));
     }
     // Because multiple user_id's are affected by this operation, we have
     // to flush the entire cache
     try {
         $cache_ok = self::flushCache();
     } catch (FOX_exception $child) {
         throw new FOX_exception(array('numeric' => 2, 'text' => "flushCache exception", 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child));
     }
     if ($cache_ok) {
         return $rows_changed;
     } else {
         return false;
     }
 }
 /**
  * Test fixture for dropGlobal() method, L1, multiple items
  *
  * @version 1.0
  * @since 1.0
  * 
  * =======================================================================================
  */
 public function test_dropGlobal_L1_multi()
 {
     self::loadData();
     // Drop objects
     // ####################################################################
     $drop_ctrl = array("validate" => true);
     try {
         $rows_changed = $this->cls->dropGlobal(1, array(1, 2), $drop_ctrl);
     } catch (FOX_exception $child) {
         $this->fail($child->dumpString(1));
     }
     // Should report 12 rows were dropped
     $this->assertEquals(10, $rows_changed);
     // Verify db state
     // ####################################################################
     $db = new FOX_db();
     $columns = null;
     $args = null;
     $ctrl = array('format' => 'array_key_array', 'key_col' => array('L2', 'L1'));
     try {
         $result = $db->runSelectQuery($this->cls->_struct(), $args, $columns, $ctrl);
     } catch (FOX_exception $child) {
         $this->fail($child->dumpString(1));
     }
     // NOTE: the datastore will automatically clip empty branches
     $test_obj = new stdClass();
     $test_obj->foo = "11";
     $test_obj->bar = "test_Bar";
     $check = array('X' => array(5 => true, 3 => (int) 0), 'Y' => array(3 => (double) 1.7, 4 => (double) -1.6), 'Z' => array(3 => $test_obj), 'A' => array(5 => true, 3 => (int) 0), 'B' => array(3 => (double) 1.7, 4 => (double) -1.6));
     $this->assertEquals($check, $result);
     // Check class cache state
     // ####################################################################
     $check_cache = array();
     $this->assertEquals($check_cache, $this->cls->cache);
     // Verify persistent cache state by reading-back all items
     // ####################################################################
     $request = array('X' => array(), 'Y' => array(), 'Z' => array(), 'A' => array(), 'B' => array());
     $valid = false;
     try {
         $result = $this->cls->getMulti($request, $ctrl, $valid);
     } catch (FOX_exception $child) {
         $this->fail($child->dumpString(1));
     }
     $this->assertEquals(true, $valid);
     // Should report valid because all
     // requested L2's exist
     $this->assertEquals($check, $result);
 }
 /**
  * Test fixture for processHTMLForm() method, data integrity
  *
  * @version 1.0
  * @since 1.0
  * 
  * =======================================================================================
  */
 public function test_processHTMLForm_dataIntegrity()
 {
     self::loadData();
     // Missing key names string
     // ===============================================================
     $check = array('plugin_1^X^K^N' => true, 'plugin_1^X^K^N2' => false, 'plugin_1^X^Z^N3' => 2, 'plugin_1^Y^Z^N4' => -1.6);
     try {
         $result = $this->cls->processHTMLForm($check);
         // Execution will halt on the previous line if processHTMLForm() throws an exception
         $this->fail("Method processHTMLForm() failed to throw an exception on missing key names parameter");
     } catch (FOX_exception $child) {
     }
     // Invalid plugin name
     // ===============================================================
     $check = array('key_names' => '1^X^K^N1,plugin_1^X^K^N2,plugin_1^X^Z^N3,plugin_1^Y^Z^N4', 'plugin_1^X^K^N' => true, 'plugin_1^X^K^N2' => false, 'plugin_1^X^Z^N3' => 2, 'plugin_1^Y^Z^N4' => -1.6);
     try {
         $result = $this->cls->processHTMLForm($check);
         // Execution will halt on the previous line if processHTMLForm() throws an exception
         $this->fail("Method processHTMLForm() failed to throw an exception on invalid plugin name");
     } catch (FOX_exception $child) {
     }
     // Invalid tree name
     // ===============================================================
     $check = array('key_names' => 'plugin_1^1^K^N1,plugin_1^X^K^N2,plugin_1^X^Z^N3,plugin_1^Y^Z^N4', 'plugin_1^X^K^N' => true, 'plugin_1^X^K^N2' => false, 'plugin_1^X^Z^N3' => 2, 'plugin_1^Y^Z^N4' => -1.6);
     try {
         $result = $this->cls->processHTMLForm($check);
         // Execution will halt on the previous line if processHTMLForm() throws an exception
         $this->fail("Method processHTMLForm() failed to throw an exception on invalid tree name");
     } catch (FOX_exception $child) {
     }
     // Invalid branch name
     // ===============================================================
     $check = array('key_names' => 'plugin_1^X^1^N1,plugin_1^X^K^N2,plugin_1^X^Z^N3,plugin_1^Y^Z^N4', 'plugin_1^X^K^N' => true, 'plugin_1^X^K^N2' => false, 'plugin_1^X^Z^N3' => 2, 'plugin_1^Y^Z^N4' => -1.6);
     try {
         $result = $this->cls->processHTMLForm($check);
         // Execution will halt on the previous line if processHTMLForm() throws an exception
         $this->fail("Method processHTMLForm() failed to throw an exception on invalid branch name");
     } catch (FOX_exception $child) {
     }
     // Invalid node name
     // ===============================================================
     $check = array('key_names' => 'plugin_1^X^K^1,plugin_1^X^K^N2,plugin_1^X^Z^N3,plugin_1^Y^Z^N4', 'plugin_1^X^K^N' => true, 'plugin_1^X^K^N2' => false, 'plugin_1^X^Z^N3' => 2, 'plugin_1^Y^Z^N4' => -1.6);
     try {
         $result = $this->cls->processHTMLForm($check);
         // Execution will halt on the previous line if processHTMLForm() throws an exception
         $this->fail("Method processHTMLForm() failed to throw an exception on invalid node name");
     } catch (FOX_exception $child) {
     }
     // Nonexistent node
     // ===============================================================
     $check = array('key_names' => 'plugin_1^X^K^N6,plugin_1^X^K^N2,plugin_1^X^Z^N3,plugin_1^Y^Z^N4', 'plugin_1^X^K^N' => true, 'plugin_1^X^K^N2' => false, 'plugin_1^X^Z^N3' => 2, 'plugin_1^Y^Z^N4' => -1.6);
     try {
         $result = $this->cls->processHTMLForm($check);
         // Execution will halt on the previous line if processHTMLForm() throws an exception
         $this->fail("Method processHTMLForm() failed to throw an exception on nonexistent node");
     } catch (FOX_exception $child) {
     }
     // Check db state
     // ===============================================================
     $test_obj = new stdClass();
     $test_obj->foo = "11";
     $test_obj->bar = "test_Bar";
     $check = array("plugin_1" => array('X' => array('K' => array('N1' => array('filter' => 'debug', 'filter_ctrl' => false, 'val' => null), 'N2' => array('filter' => 'debug', 'filter_ctrl' => false, 'val' => false), 'N5' => array('filter' => 'debug', 'filter_ctrl' => false, 'val' => true)), 'Z' => array('N3' => array('filter' => 'debug', 'filter_ctrl' => false, 'val' => (int) 0))), 'Y' => array('K' => array('N1' => array('filter' => 'debug', 'filter_ctrl' => false, 'val' => (int) 1), 'N2' => array('filter' => 'debug', 'filter_ctrl' => false, 'val' => (int) -1), 'N3' => array('filter' => 'debug', 'filter_ctrl' => false, 'val' => (double) 1.7)), 'Z' => array('N4' => array('filter' => 'debug', 'filter_ctrl' => false, 'val' => (double) -1.6)))), "plugin_2" => array('X' => array('K' => array('N1' => array('filter' => 'debug', 'filter_ctrl' => false, 'val' => (string) "foo"), 'N2' => array('filter' => 'debug', 'filter_ctrl' => false, 'val' => array(null, true, false, 1, 1.0, "foo"))), 'Z' => array('N3' => array('filter' => 'debug', 'filter_ctrl' => false, 'val' => $test_obj)))));
     $db = new FOX_db();
     $columns = null;
     $ctrl = array('format' => 'array_key_array', 'key_col' => array('plugin', 'tree', 'branch', 'node'));
     try {
         $struct = $this->cls->_struct();
         $result = $db->runSelectQuery($struct, $args = null, $columns, $ctrl);
     } catch (FOX_exception $child) {
         $this->fail($child->dumpString(1));
     }
     $this->assertEquals($check, $result);
 }
 /**
  * Fetches the level_id of one or more slugs
  *
  * @version 1.0
  * @since 1.0
  *
  * @param int $module_id | module_id that owns the object type_id
  * @param int $type_id | Object type_id that owns the level_id
  * @param string $level_slug | Single level_slug as string. Multiple slugs as array of strings.
  * 
  * @return array | Exception on failure. False on nonexistent. Array "level_slug"=>"level_id" on success
  */
 public function slugToTypeId($module_id, $type_id, $level_slug)
 {
     $db = new FOX_db();
     if (!is_array($level_slug)) {
         $level_slug = array($level_slug);
     }
     // Load as many id's as possible from the cache
     // ============================================
     $result = array();
     $missing_slugs = array();
     $persistent_cache_loaded = false;
     foreach ($level_slug as $slug) {
         // If a requested slug is in the class cache, add its level_id to the the results array
         if (FOX_sUtil::keyExists($slug, $this->cache["slug_to_level_id"][$module_id][$type_id])) {
             $result[$slug] = $this->cache["slug_to_level_id"][$module_id][$type_id][$slug];
         } elseif (!$persistent_cache_loaded) {
             try {
                 self::loadCache();
                 $persistent_cache_loaded = true;
             } catch (FOX_exception $child) {
                 throw new FOX_exception(array('numeric' => 1, 'text' => "Cache read error", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => $child));
             }
             if (FOX_sUtil::keyExists($slug, $this->cache["slug_to_level_id"][$module_id][$type_id])) {
                 $result[$slug] = $this->cache["slug_to_level_id"][$module_id][$type_id][$slug];
             } else {
                 $missing_slugs[] = $slug;
             }
         } else {
             $missing_slugs[] = $slug;
         }
     }
     unset($slug);
     // Fetch any missing "level_slug"-"level_id" pairs from the db
     // ===========================================================
     if (count($missing_slugs) > 0) {
         $args = array(array("col" => "module_id", "op" => "=", "val" => $module_id), array("col" => "type_id", "op" => "=", "val" => $type_id), array("col" => "level_slug", "op" => "=", "val" => $missing_slugs));
         $columns = array("mode" => "include", "col" => array("level_slug", "level_id"));
         $ctrl = array("format" => "array_key_single", "key_col" => "level_slug", "val_col" => "level_id");
         try {
             $db_result = $db->runSelectQuery($this->_struct(), $args, $columns, $ctrl);
         } catch (FOX_exception $child) {
             throw new FOX_exception(array('numeric' => 2, 'text' => "Error reading from database", 'data' => array('args' => $args, 'columns' => $columns, 'ctrl' => $ctrl), 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => $child));
         }
         // Update the cache
         // ==============================
         if ($db_result) {
             $result = array_merge($result, $db_result);
             try {
                 $cache_image = self::readCache();
             } catch (FOX_exception $child) {
                 throw new FOX_exception(array('numeric' => 3, 'text' => "Cache read error", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => $child));
             }
             // Rebuild cache image
             foreach ($db_result as $slug => $level_id) {
                 $cache_image["slug_to_level_id"][$module_id][$type_id][$slug] = $level_id;
             }
             unset($slug, $level_id);
             try {
                 self::writeCache($cache_image);
             } catch (FOX_exception $child) {
                 throw new FOX_exception(array('numeric' => 4, 'text' => "Cache write error", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => $child));
             }
             // Overwrite the class cache
             $this->cache = $cache_image;
         }
     }
     if (count($result) >= 1) {
         return $result;
     } else {
         return false;
     }
 }
 /**
  * Returns all type_ids owned by a module
  *
  * @version 1.0
  * @since 1.0
  * @param int $module_id| Single module_id as int.
  * @return array | Exception on failure. False on nonexistent. Array of type_ids on success.
  */
 public function getTypes($module_id)
 {
     $db = new FOX_db();
     $result = array();
     // If the module_id doesn't exist in the class cache array, fetch it from the persistent cache
     if (!FOX_sUtil::keyExists($module_id, $this->cache["module_id_types"])) {
         try {
             self::loadCache();
         } catch (FOX_exception $child) {
             throw new FOX_exception(array('numeric' => 1, 'text' => "Cache read error", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => $child));
         }
         // If the module_id doesn't exist in the persistent cache, load it from the db
         if (!FOX_sUtil::keyExists($module_id, $this->cache["module_id_types"])) {
             $columns = array("mode" => "include", "col" => array("type_id"));
             $ctrl = array("format" => "col");
             try {
                 $db_result = $db->runSelectQueryCol($this->_struct(), "module_id", "=", $module_id, $columns, $ctrl);
             } catch (FOX_exception $child) {
                 throw new FOX_exception(array('numeric' => 2, 'text' => "Error reading from database", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => $child));
             }
             // Update the cache
             // ==============================
             if ($db_result) {
                 try {
                     $cache_image = self::readCache();
                 } catch (FOX_exception $child) {
                     throw new FOX_exception(array('numeric' => 3, 'text' => "Cache read error", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => $child));
                 }
                 // Rebuild the cache image
                 foreach ($db_result as $type_id) {
                     $result[] = $type_id;
                     $cache_image["module_id_types"][$module_id][$type_id] = true;
                 }
                 unset($type_id);
                 try {
                     self::writeCache($cache_image);
                 } catch (FOX_exception $child) {
                     throw new FOX_exception(array('numeric' => 4, 'text' => "Cache write error", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => $child));
                 }
                 // Overwrite the class cache
                 $this->cache = $cache_image;
             } else {
                 // The module_id doesn't exist
                 return false;
             }
         }
     }
     // Build the result array
     $type_ids = $this->cache["module_id_types"][$module_id];
     $result = array_keys($type_ids);
     return $result;
 }
Example #16
0
 function tearDown()
 {
     $tdb = new FOX_db();
     $tdb->runDropTable(self::$struct);
     parent::tearDown();
 }
 /**
  * Loads the class instance with the test data set, and verifies it was correctly written
  * to the database and cache
  *
  * @version 1.0
  * @since 1.0
  * 
  * =======================================================================================
  */
 public function loadData()
 {
     $test_obj = new stdClass();
     $test_obj->foo = "11";
     $test_obj->bar = "test_Bar";
     $test_data = array(array("L4" => 'A', "L3" => "X", "L2" => "K", "L1" => 1, "L0" => null), array("L4" => 'A', "L3" => "X", "L2" => "K", "L1" => 2, "L0" => false), array("L4" => 'A', "L3" => "X", "L2" => "K", "L1" => 5, "L0" => true), array("L4" => 'A', "L3" => "X", "L2" => "Z", "L1" => 3, "L0" => (int) 0), array("L4" => 'A', "L3" => "Y", "L2" => "K", "L1" => 1, "L0" => (int) 1), array("L4" => 'A', "L3" => "Y", "L2" => "K", "L1" => 2, "L0" => (int) -1), array("L4" => 'A', "L3" => "Y", "L2" => "K", "L1" => 3, "L0" => (double) 1.7), array("L4" => 'A', "L3" => "Y", "L2" => "Z", "L1" => 4, "L0" => (double) -1.6), array("L4" => 'B', "L3" => "X", "L2" => "K", "L1" => 1, "L0" => (string) "foo"), array("L4" => 'B', "L3" => "X", "L2" => "K", "L1" => 2, "L0" => array(null, true, false, 1, 1.0, "foo")), array("L4" => 'B', "L3" => "X", "L2" => "Z", "L1" => 3, "L0" => $test_obj));
     // Load class with data
     // ===============================================================
     try {
         $rows_changed = $this->cls->setL1_multi($test_data, $ctrl = null);
     } catch (FOX_exception $child) {
         $this->fail($child->dumpString(array('depth' => 1, 'data' => true)));
     }
     // Should return (int)11 to indicate  11 keys were added
     $this->assertEquals(11, $rows_changed);
     // Check cache state
     // ===============================================================
     // NOTE: the LUT's won't be set at this point, because we haven't done any
     // database reads that give objects authority
     $check = array('A' => array('keys' => array('X' => array('K' => array(1 => null, 2 => false, 5 => true), 'Z' => array(3 => (int) 0)), 'Y' => array('K' => array(1 => (int) 1, 2 => (int) -1, 3 => (double) 1.7), 'Z' => array(4 => (double) -1.6)))), 'B' => array('keys' => array('X' => array('K' => array(1 => (string) "foo", 2 => array(null, true, false, 1, 1.0, "foo")), 'Z' => array(3 => $test_obj)))));
     $this->assertEquals($check, $this->cls->cache);
     // Check db state
     // ===============================================================
     $check = array('A' => array('X' => array('K' => array(1 => null, 2 => false, 5 => true), 'Z' => array(3 => (int) 0)), 'Y' => array('K' => array(1 => (int) 1, 2 => (int) -1, 3 => (double) 1.7), 'Z' => array(4 => (double) -1.6))), 'B' => array('X' => array('K' => array(1 => (string) "foo", 2 => array(null, true, false, 1, 1.0, "foo")), 'Z' => array(3 => $test_obj))));
     $db = new FOX_db();
     $columns = null;
     $args = null;
     $ctrl = array('format' => 'array_key_array', 'key_col' => array('L4', 'L3', 'L2', 'L1'));
     try {
         $result = $db->runSelectQuery($this->cls->_struct(), $args, $columns, $ctrl);
     } catch (FOX_exception $child) {
         $this->fail($child->dumpString(1));
     }
     $this->assertEquals($check, $result);
 }
 /**
  * Drops all groups for a single user_id from the database and cache. Generally
  * used when deleting user profiles.
  *
  * @version 1.0
  * @since 1.0
  *
  * @param int $user_id | ID of the user
  * @return bool | False on failure. Number of rows affected on success.
  */
 public function dropUser($user_id)
 {
     global $fox;
     $db = new FOX_db();
     $args = array(array("col" => "user_id", "op" => "=", "val" => $user_id));
     try {
         $rows_changed = $db->runDeleteQuery(self::$struct, $args);
     } catch (FOX_exception $child) {
         throw new FOX_exception(array('numeric' => 1, 'text' => "DB delete exception", 'data' => $args, 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child));
     }
     unset($this->cache[$user_id]);
     $cache_ok = $fox->cache->del("FOX_uGroupMember", $user_id);
     if ($cache_ok) {
         return $rows_changed;
     } else {
         return false;
     }
 }
 /**
  * Test fixture for dropMulti() method, matrix mode, hot cache
  *
  * @version 1.0
  * @since 1.0
  * 
  * =======================================================================================
  */
 public function test_dropMulti_matrix_HOT()
 {
     self::loadData();
     // Load the cache
     // ####################################################################
     $request = array('A' => array(), 'B' => array(), 'C' => array());
     $valid = false;
     try {
         $result = $this->cls->getMulti($request, $ctrl, $valid);
     } catch (FOX_exception $child) {
         $this->fail($child->dumpString(1));
     }
     // HOT CACHE - All items in cache have authority from previous GET operation
     // ===================================================================
     // Drop objects
     // ####################################################################
     $data = array(array("L3" => 'A', "L2" => "X", "L1" => 1), array("L3" => 'A', "L2" => "Y"), array("L3" => 'B'), array("L3" => 'C'));
     $ctrl = array('validate' => true, 'mode' => 'matrix', 'trap_*' => true);
     try {
         $rows_changed = $this->cls->dropMulti($data, $ctrl);
     } catch (FOX_exception $child) {
         $this->fail($child->dumpString(1));
     }
     // Should return (int)1 to indicate 18 rows were dropped
     $this->assertEquals(16, $rows_changed);
     // Verify db state
     // ####################################################################
     $db = new FOX_db();
     $columns = null;
     $args = null;
     $ctrl = array('format' => 'array_key_array', 'key_col' => array('L3', 'L2', 'L1'));
     try {
         $result = $db->runSelectQuery($this->cls->_struct(), $args, $columns, $ctrl);
     } catch (FOX_exception $child) {
         $this->fail($child->dumpString(1));
     }
     // NOTE: the datastore will automatically clip empty branches
     $check = array('A' => array('X' => array(2 => false, 3 => (int) 0, 5 => true)));
     $this->assertEquals($check, $result);
     // Check cache state
     // ####################################################################
     // Since we're working with a hot cache, the all_cached flag will be set for all
     // nodes that already exist in the database. The L2 and L3 LUT's for these
     // nodes will be missing, because the all_cached flag takes priority.
     // PASS 1: Check the L4 nodes individually to simplify debugging
     // ====================================================================
     $check_cache_A = array('all_cached' => true, 'L2' => null, 'keys' => array('X' => array(2 => false, 3 => (int) 0, 5 => true)));
     $this->assertEquals($check_cache_A, $this->cls->cache['A']);
     // PASS 2: Combine the L4 nodes into a single array and check it
     // again. This finds L4 keys that aren't supposed to be there.
     // ====================================================================
     $check_cache = array('A' => $check_cache_A);
     $this->assertEquals($check_cache, $this->cls->cache);
     // Verify persistent cache state by reading-back all items
     // ####################################################################
     $request = array('A' => array(), 'B' => array(), 'C' => array());
     $valid = false;
     try {
         $result = $this->cls->getMulti($request, $ctrl, $valid);
     } catch (FOX_exception $child) {
         $this->fail($child->dumpString(1));
     }
     $this->assertEquals(false, $valid);
     // Should report invalid because
     // the '2' and '3' L4's don't exist
     $this->assertEquals($check, $result);
 }
 function test_deleteItem_multi_withMedias()
 {
     // Clear the albums table, medias table, and caches
     // ===================================================
     $this->alb->truncate();
     $this->alb->flushCache();
     $this->med->truncate();
     $this->med->flushCache();
     // Load albums class with test data
     // ===================================================
     $test_data = array(array('date_created' => "2011-01-01 15:14:13", 'title' => "Test Title", 'caption' => "Test Caption", 'privacy' => 3, 'module_id' => 1), array('date_created' => "2011-01-01 15:14:14", 'title' => "Test Title", 'caption' => "Test Caption", 'privacy' => 2, 'module_id' => 1), array('date_created' => "2011-01-01 15:14:15", 'title' => "Test Title", 'caption' => "Test Caption", 'privacy' => 1, 'module_id' => 2));
     $result = $this->alb->addItemMulti($user_id = 1, $test_data, $error);
     $this->assertEquals(true, $result, FOX_debug::formatError_print($error));
     // Add media items to test albums
     // ===================================================
     $test_data = array('owner_id' => 1, 'album_id' => 1, 'title' => "Test Media Title 01", 'caption' => "Test Media Caption 01", 'date_created' => "2011-02-02 17:18:19", 'module_slug' => "slug_01");
     $result = $this->med->addItem($test_data, $media_object, $error);
     $this->assertEquals(1, $result, FOX_debug::formatError_print($error));
     $test_data = array('owner_id' => 1, 'album_id' => 1, 'title' => "Test Media Title 02", 'caption' => "Test Media Caption 02", 'date_created' => "2011-02-02 17:18:19", 'module_slug' => "slug_01");
     $result = $this->med->addItem($test_data, $media_object, $error);
     $this->assertEquals(2, $result, FOX_debug::formatError_print($error));
     $test_data = array('owner_id' => 1, 'album_id' => 1, 'title' => "Test Media Title 03", 'caption' => "Test Media Caption 03", 'date_created' => "2011-02-02 17:18:19", 'module_slug' => "slug_01");
     $result = $this->med->addItem($test_data, $media_object, $error);
     $this->assertEquals(3, $result, FOX_debug::formatError_print($error));
     $test_data = array('owner_id' => 1, 'album_id' => 2, 'title' => "Test Media Title 04", 'caption' => "Test Media Caption 04", 'date_created' => "2011-02-02 17:18:19", 'module_slug' => "slug_01");
     $result = $this->med->addItem($test_data, $media_object, $error);
     $this->assertEquals(4, $result, FOX_debug::formatError_print($error));
     $test_data = array('owner_id' => 1, 'album_id' => 2, 'title' => "Test Media Title 05", 'caption' => "Test Media Caption 05", 'date_created' => "2011-02-02 17:18:19", 'module_slug' => "slug_01");
     $result = $this->med->addItem($test_data, $media_object, $error);
     $this->assertEquals(5, $result, FOX_debug::formatError_print($error));
     $test_data = array('owner_id' => 1, 'album_id' => 2, 'title' => "Test Media Title 06", 'caption' => "Test Media Caption 06", 'date_created' => "2011-02-02 17:18:19", 'module_slug' => "slug_01");
     $result = $this->med->addItem($test_data, $media_object, $error);
     $this->assertEquals(6, $result, FOX_debug::formatError_print($error));
     $test_data = array('owner_id' => 1, 'album_id' => 3, 'title' => "Test Media Title 07", 'caption' => "Test Media Caption 07", 'date_created' => "2011-02-02 17:18:19", 'module_slug' => "slug_01");
     $result = $this->med->addItem($test_data, $media_object, $error);
     $this->assertEquals(7, $result, FOX_debug::formatError_print($error));
     $test_data = array('owner_id' => 1, 'album_id' => 3, 'title' => "Test Media Title 08", 'caption' => "Test Media Caption 08", 'date_created' => "2011-02-02 17:18:19", 'module_slug' => "slug_01");
     $result = $this->med->addItem($test_data, $media_object, $error);
     $this->assertEquals(8, $result, FOX_debug::formatError_print($error));
     $test_data = array('owner_id' => 1, 'album_id' => 3, 'title' => "Test Media Title 09", 'caption' => "Test Media Caption 09", 'date_created' => "2011-02-02 17:18:19", 'module_slug' => "slug_01");
     $result = $this->med->addItem($test_data, $media_object, $error);
     $this->assertEquals(9, $result, FOX_debug::formatError_print($error));
     // Delete albums
     // ===================================================
     $result = $this->alb->deleteItem($user_id = 1, $album_id = array(1, 3), $error);
     $this->assertEquals(2, $result, FOX_debug::formatError_print($error));
     // Verify albums were deleted
     // ===================================================
     $result = $this->alb->get(array(1, 2, 3));
     $check_array = array(new FOX_album(array("id" => 2, 'owner_id' => 1, 'cover_image' => 4, 'display_order' => array(4, 5, 6), 'date_created' => "2011-01-01 15:14:14", 'title' => "Test Title", 'caption' => "Test Caption", 'privacy' => 2, 'module_id' => 1)));
     $this->assertEquals($check_array, $result);
     // Verify medias were deleted
     // ===================================================
     $db = new FOX_db();
     $args = array(array("col" => "owner_id", "op" => "=", "val" => 1));
     $ctrl = array("format" => "array_array");
     $db_result = $db->runSelectQuery(FOX_media::_struct(), $args, $columns = null, $ctrl);
     $check_data = array(array("id" => 4, 'owner_id' => 1, 'album_id' => 2, 'date_created' => "2011-02-02 17:18:19", 'title' => "Test Media Title 04", 'caption' => "Test Media Caption 04", 'privacy' => 2, 'module_id' => 1, 'pixels_x' => 1000, 'pixels_y' => 2000, 'bytes_master' => 1111, 'module_id' => 1, 'master_id' => "ABC1111"), array("id" => 5, 'owner_id' => 1, 'album_id' => 2, 'date_created' => "2011-02-02 17:18:19", 'title' => "Test Media Title 05", 'caption' => "Test Media Caption 05", 'privacy' => 2, 'module_id' => 1, 'pixels_x' => 1000, 'pixels_y' => 2000, 'bytes_master' => 1111, 'module_id' => 1, 'master_id' => "ABC1111"), array("id" => 6, 'owner_id' => 1, 'album_id' => 2, 'date_created' => "2011-02-02 17:18:19", 'title' => "Test Media Title 06", 'caption' => "Test Media Caption 06", 'privacy' => 2, 'module_id' => 1, 'pixels_x' => 1000, 'pixels_y' => 2000, 'bytes_master' => 1111, 'module_id' => 1, 'master_id' => "ABC1111"));
     $this->assertEquals($check_data, $db_result);
 }
 function test_dropId_Multi()
 {
     // load db
     // ======================================================
     $add_tokens = array("one", "two", "three", "four", "five");
     try {
         $add_result = $this->cls->addToken($add_tokens);
     } catch (FOX_exception $child) {
         throw new FOX_exception(array('numeric' => 3, 'text' => "addToken exception", 'data' => array("tokens" => $add_tokens), 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => $child));
         return false;
     }
     // Test  single dropId
     // ======================================================
     try {
         $drop_ids = array(1, 2, 3, 4, 5);
         $this->assertEquals(5, $this->cls->dropId($drop_ids));
     } catch (FOX_exception $child) {
         throw new FOX_exception(array('numeric' => 4, 'text' => "dropId exception", 'data' => array("drop ids" => $drop_ids), 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => $child));
         return false;
     }
     // Check Db has no rows
     // ======================================================
     try {
         $db = new FOX_db();
         $this->assertEquals(false, $db->runSelectQuery(FOX_test_dictionary::$struct));
     } catch (FOX_exception $child) {
         throw new FOX_exception(array('numeric' => 5, 'text' => "DB select exception", 'data' => array("ctrl" => array("count" => true, "format" => "var")), 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => $child));
         return false;
     }
     // Check Class cache is empty
     $this->assertEquals(array('ids' => array(), 'tokens' => array()), $this->cls->cache);
 }
 /**
  * Removes one or more modules from the database and cache.
  *
  * @version 1.0
  * @since 1.0
  * @param int/array $module_ids | Single module_id as int. Multiple module_id's as array of int.
  * @return int | Exception on failure. Int number of db rows changed on success.
  */
 public function dropModule($module_ids)
 {
     $db = new FOX_db();
     $struct = self::_struct();
     if (empty($module_ids)) {
         throw new FOX_exception(array('numeric' => 1, 'text' => "Invalid module_ids parameter", 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => null));
     }
     if (!is_array($module_ids)) {
         // Handle single int as input
         $module_ids = array($module_ids);
     }
     // Lock the cache
     // ===========================================================
     try {
         $cache_image = self::lockCache();
     } catch (FOX_exception $child) {
         throw new FOX_exception(array('numeric' => 2, 'text' => "Error locking cache", 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child));
     }
     // Update the database
     // ===========================================================
     $args = array(array("col" => "module_id", "op" => "=", "val" => $module_ids));
     try {
         $rows_changed = $db->runDeleteQuery($struct, $args, $ctrl = null);
     } catch (FOX_exception $child) {
         throw new FOX_exception(array('numeric' => 3, 'text' => "Error deleting from database", 'data' => array('args' => $args), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child));
     }
     // Update the persistent cache
     // ===========================================================
     if (!$rows_changed) {
         // If no rows were changed, we can just write-back the
         // cache image to release our lock
         try {
             self::writeCache($cache_image);
         } catch (FOX_exception $child) {
             throw new FOX_exception(array('numeric' => 4, 'text' => "Error writing to cache", 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child));
         }
     } else {
         // If rows were changed, we have to flush the entire cache
         try {
             self::flushCache();
         } catch (FOX_exception $child) {
             throw new FOX_exception(array('numeric' => 5, 'text' => "Error flushing cache", 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child));
         }
     }
     return (int) $rows_changed;
 }
Example #23
0
 /**
  * Deletes the entire user data store, and flushes the cache. Generally
  * used for testing and debug.
  *
  * @version 1.0
  * @since 1.0
  *
  * @return bool | False on failure. True on success.
  */
 public function dropAll(&$error = null)
 {
     global $rad;
     $db = new FOX_db();
     try {
         $query_ok = $db->runTruncateTable(self::$struct);
     } catch (FOX_exception $child) {
         throw new FOX_exception(array('numeric' => 1, 'text' => "Error while clearing the database", 'data' => null, 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child));
     }
     // Since this operation affects *all* user_id's, we have to flush the cache
     try {
         $cache_ok = self::flushCache();
     } catch (FOX_exception $child) {
         throw new FOX_exception(array('numeric' => 2, 'text' => "Cache flush exception", 'data' => null, 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child));
     }
     if ($cache_ok) {
         return true;
     } else {
         return false;
     }
 }
Example #24
0
 /**
  * Deletes a single group, given its group_id
  *
  * @version 1.0
  * @since 1.0
  *
  * @param int $group_id | id of the group
  * @return bool | False on failure. True on success.
  */
 public function deleteGroup($group_id)
 {
     global $fox;
     $db = new FOX_db();
     $columns = array("mode" => "include", "col" => array("is_default", "name"));
     $ctrl = array("format" => "row_array");
     try {
         $group = $db->runSelectQueryCol(self::$struct, "group_id", "=", $group_id, $columns, $ctrl);
     } catch (FOX_exception $child) {
         throw new FOX_exception(array('numeric' => 1, 'text' => "DB select exception", 'data' => array("data" => $data, "col" => "group_id", "op" => "=", "val" => $group_id, "columns" => $columns, "ctrl" => $ctrl), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child));
     }
     // If the group we're trying to delete is the default group, reject the action. There must *always* be a
     // default group on the system. If the admin wants to delete the default group, they have to make
     // another group the default group first.
     if ($group["is_default"] == true) {
         //echo "\nclass.user.group.types::deleteGroup() - attempted delete on default group\n";
         return false;
     }
     // Trap trying to delete a nonexistent group
     if (!$group) {
         //echo "\nclass.user.group.types::deleteGroup() - attempted delete on nonexistent group: $group_id \n";
         return false;
     }
     // Get the user_id of every user in the group we're deleting
     $columns = array("mode" => "include", "col" => "user_id");
     $ctrl = array("format" => "col");
     try {
         $user_ids = $db->runSelectQueryCol(FOX_uGroupMember::_struct(), "group_id", "=", $group_id, $columns, $ctrl);
     } catch (FOX_exception $child) {
         throw new FOX_exception(array('numeric' => 2, 'text' => "DB select exception", 'data' => array("data" => $data, "col" => "group_id", "op" => "=", "val" => $group_id, "columns" => $columns, "ctrl" => $ctrl), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child));
     }
     // CASE 1: There are users that are members of the group
     // ===============================================================================
     if ($user_ids) {
         // Load all of the groups that each user is currently in, except
         // the group we're removing them from
         $args = array(array("col" => "user_id", "op" => "=", "val" => $user_ids), array("col" => "group_id", "op" => "!=", "val" => $group_id));
         $ctrl = array("format" => "array_key_array_grouped", "key_col" => array("user_id", "group_id"));
         try {
             $in_groups = $db->runSelectQuery(FOX_uGroupMember::_struct(), $args, $columns = null, $ctrl);
         } catch (FOX_exception $child) {
             throw new FOX_exception(array('numeric' => 3, 'text' => "DB select exception", 'data' => array("args" => $args, "ctrl" => $ctrl), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child));
         }
         // @@@@@@ BEGIN TRANSACTION @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
         try {
             $started_transaction = $db->beginTransaction();
         } catch (FOX_exception $child) {
             throw new FOX_exception(array('numeric' => 4, 'text' => "beginTransaction exception", 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child));
         }
         if ($started_transaction) {
             $keys_ok = true;
             try {
                 $gk = new FOX_uGroupKeyRing();
             } catch (FOX_exception $child) {
                 throw new FOX_exception(array('numeric' => 2, 'text' => "FOX_uGroupKeyRing constructor exception", 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child));
             }
             foreach ($user_ids as $user) {
                 // Get the combined keyring of all the user's other groups
                 try {
                     $keep_keys = $gk->getKeys($in_groups[$user]);
                 } catch (FOX_exception $child) {
                     throw new FOX_exception(array('numeric' => 5, 'text' => "FOX_uGroupKeyRing getKeys exception", 'data' => array("user" => $in_groups[$user]), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child));
                 }
                 // Get the keyring of the group we're removing the user from
                 try {
                     $drop_keys = $gk->getKeys($group_id);
                 } catch (FOX_exception $child) {
                     throw new FOX_exception(array('numeric' => 6, 'text' => "FOX_uGroupKeyRing getKeys exception", 'data' => array("group_id" => $group_id), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child));
                 }
                 // Intersect the $keep_keys and $drop_keys arrays to get
                 // a list of keys we need to revoke from the user
                 if ($keep_keys && $drop_keys) {
                     $revoke_keys = array_diff($drop_keys, $keep_keys);
                 } else {
                     $revoke_keys = $drop_keys;
                 }
                 // Revoke all the keys we previously calculated
                 if ($revoke_keys) {
                     $ks = new FOX_uKeyRing();
                     try {
                         $revoke_ok = $ks->revokeKey($user, $revoke_keys);
                     } catch (FOX_exception $child) {
                         throw new FOX_exception(array('numeric' => 7, 'text' => "FOX_uKeyRing revokeKeys exception", 'data' => array("user" => $user, "revoke_keys" => $revoke_keys), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child));
                     }
                     if (!$revoke_ok) {
                         $keys_ok = false;
                     }
                 } else {
                     // Handle no keys to revoke
                     $keys_ok = true;
                 }
             }
             unset($user);
             // Because we are inside a transaction, we have to directly delete items from
             // the other class's db tables. If we deleted items using the other class's
             // functions, the other classes would remove them from their caches before we
             // could confirm all steps in the transaction were successful.
             // ============================================================================
             // Drop the group-user pairs from the group members table
             $args = array(array("col" => "group_id", "op" => "=", "val" => $group_id));
             try {
                 $gm_ok = $db->runDeleteQuery(FOX_uGroupMember::_struct(), $args);
             } catch (FOX_exception $child) {
                 throw new FOX_exception(array('numeric' => 8, 'text' => "DB delete exception", 'data' => $args, 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child));
             }
             // Drop the group-key pairs from the group keyring table
             $args = array(array("col" => "group_id", "op" => "=", "val" => $group_id));
             try {
                 $gk_ok = $db->runDeleteQuery(FOX_uGroupKeyRing::_struct(), $args);
             } catch (FOX_exception $child) {
                 throw new FOX_exception(array('numeric' => 9, 'text' => "DB delete exception", 'data' => $args, 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child));
             }
             // Drop the group from the group types table
             $args = array(array("col" => "group_id", "op" => "=", "val" => $group_id));
             try {
                 $gt_ok = $db->runDeleteQuery(self::$struct, $args);
             } catch (FOX_exception $child) {
                 throw new FOX_exception(array('numeric' => 10, 'text' => "DB delete exception", 'data' => $args, 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child));
             }
             // Update the cache
             if ($keys_ok && $gm_ok !== false && $gk_ok !== false && $gt_ok) {
                 // Handle groups with no members and
                 // groups with no keys returning (int)0
                 try {
                     $commit_ok = $db->commitTransaction();
                 } catch (FOX_exception $child) {
                     throw new FOX_exception(array('numeric' => 11, 'text' => "commitTransaction exception", 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child));
                 }
                 if ($commit_ok) {
                     // Because we directly modified other class's db tables, we have to
                     // flush the cache for the affected classes
                     try {
                         $fox->cache->flushNamespace("FOX_uGroupMember");
                     } catch (FOX_exception $child) {
                         throw new FOX_exception(array('numeric' => 12, 'text' => "FOX_uGroupMember flushNamespace exception", 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child));
                     }
                     try {
                         $fox->cache->flushNamespace("FOX_uGroupKeyRing");
                     } catch (FOX_exception $child) {
                         throw new FOX_exception(array('numeric' => 13, 'text' => "FOX_uGroupKeyRing flushNamespace exception", 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child));
                     }
                     // Load, update, writeback
                     try {
                         self::loadCache();
                     } catch (FOX_exception $child) {
                         throw new FOX_exception(array('numeric' => 14, 'text' => "FOX_uGroupKeyRing getKeys exception", 'data' => array("user" => $group_id), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child));
                     }
                     unset($this->cache["ids"][$group["name"]]);
                     $cache_ok = self::saveCache();
                     return $cache_ok;
                 } else {
                     return false;
                 }
             }
         } else {
             // If we couldn't start a transaction, return false
             return false;
         }
         // @@@@@@ END TRANSACTION @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     } else {
         // @@@@@@ BEGIN TRANSACTION @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
         try {
             $started_transaction = $db->beginTransaction();
         } catch (FOX_exception $child) {
             throw new FOX_exception(array('numeric' => 15, 'text' => "beginTransaction exception", 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child));
         }
         if ($started_transaction) {
             // Because we are inside a transaction, we have to directly delete items from
             // the other class's db tables. If we deleted items using the other class's
             // functions, the other classes would remove them from their caches before we
             // could confirm all steps in the transaction were successful.
             // ============================================================================
             // Drop the group-key pairs from the group keyring table
             $args = array(array("col" => "group_id", "op" => "=", "val" => $group_id));
             try {
                 $gk_ok = $db->runDeleteQuery(FOX_uGroupKeyRing::_struct(), $args);
             } catch (FOX_exception $child) {
                 throw new FOX_exception(array('numeric' => 16, 'text' => "DB delete exception", 'data' => $args, 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child));
             }
             // Drop the group from the group types table
             $args = array(array("col" => "group_id", "op" => "=", "val" => $group_id));
             try {
                 $gt_ok = $db->runDeleteQuery(self::$struct, $args);
             } catch (FOX_exception $child) {
                 throw new FOX_exception(array('numeric' => 17, 'text' => "DB delete exception", 'data' => $args, 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child));
             }
             // Update the cache
             if ($gk_ok !== false && $gt_ok) {
                 // Handle groups with no keys
                 // returning (int)0
                 try {
                     $commit_ok = $db->commitTransaction();
                 } catch (FOX_exception $child) {
                     throw new FOX_exception(array('numeric' => 18, 'text' => "commitTransaction exception", 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child));
                 }
                 if ($commit_ok) {
                     // Because we directly modified another class's db table, we
                     // have to flush the cache for the affected class
                     try {
                         $fox->cache->flushNamespace("FOX_uGroupKeyRing");
                     } catch (FOX_exception $child) {
                         throw new FOX_exception(array('numeric' => 2, 'text' => "FOX_uGroupKeyRing flushNamespace exception", 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child));
                     }
                     // Load, update, writeback
                     try {
                         self::loadCache();
                     } catch (FOX_exception $child) {
                         throw new FOX_exception(array('numeric' => 19, 'text' => "loadCache exception", 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child));
                     }
                     unset($this->cache["ids"][$group["name"]]);
                     try {
                         $cache_ok = self::saveCache();
                     } catch (FOX_exception $child) {
                         throw new FOX_exception(array('numeric' => 20, 'text' => "saveCache exception", 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child));
                     }
                     return $cache_ok;
                 } else {
                     return false;
                 }
             }
         } else {
             // If we couldn't start a transaction, return false
             return false;
         }
         // @@@@@@ END TRANSACTION @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     }
     // It might be possible to do this using a sophisticated query
     // Remove all keys granted by the group, from every user on the site, unless another group grants
     // the key, and the user is a member of that other group
     // ========================================================
     // DELETE kst
     // FROM user_keystore_table AS kst
     // INNER JOIN group_members_table AS gmt ON kst.user_id = gmt.user_id	    // user has to be a member of the deleted group
     // INNER JOIN group_keyring_table AS gkt ON gmt.group_id = gkt.group_id	    // key has to be granted by the deleted group
     // WHERE kst.key_id NOT IN (SELECT key_id
     //			    FROM group_keyring_table AS gkt2
     //			    INNER JOIN group_members_table AS gmt2 ON gkt2.group_id = gmt2.group_id
     //			    WHERE gmt2.group_id != gmt.group_id	    // where the key does not belong to another group
     //			    AND gmt2.user_id = gmt.user_id )	    // and the user is a member of that group
     // AND gkt.group_id = [this group]
     // AND gmt.group_id = [this group]
     // ...It also might be possible to do this using MySQL "foreign keys"
 }
 /**
  * Deletes an entire tree of keys
  *
  * @version 1.0
  * @since 1.0
  *
  * @param string $tree | The tree name
  * @return bool | False on failure. True on success.
  */
 public function dropTree($tree)
 {
     global $fox;
     $db = new FOX_db();
     // Fetch the key_id's for all matching keys from the db
     $args = array(array("col" => "tree", "op" => "=", "val" => $tree));
     $columns = array("mode" => "include", "col" => array("key_id"));
     $ctrl = array("format" => "col");
     try {
         $drop_ids = $db->runSelectQuery(self::$struct, $args, $columns, $ctrl);
     } catch (FOX_exception $child) {
         throw new FOX_exception(array('numeric' => 1, 'text' => "DB select exception", 'data' => array("args" => $args, "columns" => $columns, "ctrl" => $ctrl), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child));
     }
     // @@@@@@ BEGIN TRANSACTION @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     try {
         $started_transaction = $db->beginTransaction();
     } catch (FOX_exception $child) {
         throw new FOX_exception(array('numeric' => 2, 'text' => "beginTransaction exception", 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child));
     }
     if ($started_transaction) {
         $args = array(array("col" => "key_id", "op" => "=", "val" => $drop_ids));
         try {
             $db->runDeleteQuery(self::$struct, $args);
         } catch (FOX_exception $child) {
             throw new FOX_exception(array('numeric' => 3, 'text' => "DB delete exception", 'data' => $args, 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child));
         }
         // TODO:
         // 1) drop the keys from the user keystore
         // 2) purge the dropped keys from the user keystore cache
         // 3) drop the keys from all groups that grant them
         try {
             $query_ok = $db->commitTransaction();
         } catch (FOX_exception $child) {
             throw new FOX_exception(array('numeric' => 4, 'text' => "commitTransaction exception", 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child));
         }
     } else {
         $query_ok = false;
     }
     // @@@@@@ END TRANSACTION @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     // Update the cache
     if ($query_ok) {
         // Update the class cache from the persistent cache
         try {
             self::loadCache();
         } catch (FOX_exception $child) {
             throw new FOX_exception(array('numeric' => 5, 'text' => "loadCache exception", 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child));
         }
         // Flush the deleted branch from the class cache
         unset($this->cache["keys"][$tree_name]);
         unset($this->cache["branches"][$tree_name]);
         unset($this->cache["trees"][$tree_name]);
         // Write the updated class cache array to the persistent cache
         try {
             $cache_ok = self::saveCache();
         } catch (FOX_exception $child) {
             throw new FOX_exception(array('numeric' => 6, 'text' => "saveCache exception", 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child));
         }
         return $cache_ok;
     } else {
         return false;
     }
 }
Example #26
0
 /**
  * Deletes an existing user class. Users in this class will be moved to the class's "transfer_to"
  * class. If the "transfer_to" class was not set, users will be moved to the site's "default" class.
  *
  * @version 1.0
  * @since 1.0
  *
  * @param int $id | id of this class to delete
  * @return bool/int | False on failure. Numer of affected users on success.
  */
 public function deleteClass($id)
 {
     // Fetch the db entry for this user class
     // ============================================================================================
     $db = new FOX_db();
     $columns = array("format" => "include", "col" => array("id", "is_default", "transfer_to"));
     $ctrl = array("format" => "row_array");
     try {
         $result = $db->runSelectQueryCol(self::$struct, "id", "=", $id, $columns, $ctrl);
     } catch (FOX_exception $child) {
         throw new FOX_exception(array('numeric' => 1, 'text' => "DB select exception", 'data' => array("col" => "id", "op" => "=", "val" => $id, "columns" => $columns, "ctrl" => $ctrl), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child));
     }
     // Trap user trying to delete the default class
     // ============================================================================================
     if ($result["is_default"] == true) {
         echo "\nERROR: You cannot delete a class that is set as the default user class. To delete this ";
         echo "class, set another class as the default class, then come back and delete this one.\n";
         die;
     }
     // If the old class has a "transfer_to" class, use it. If the old class doesn't list a
     // "transfer_to" class, find the class that has the "default" flag, and use that class instead.
     // ============================================================================================
     if (!empty($result["transfer_to"])) {
         $dest_class = $result["transfer_to"];
     } else {
         $columns = array("format" => "include", "col" => "id");
         $ctrl = array("format" => "var");
         try {
             $dest_class = $db->runSelectQueryCol(self::$struct, "is_default", "=", true, $columns, $ctrl);
         } catch (FOX_exception $child) {
             throw new FOX_exception(array('numeric' => 2, 'text' => "DB select exception", 'data' => array("col" => "is_default", "op" => "=", "val" => true, "columns" => $columns, "ctrl" => $ctrl), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child));
         }
     }
     // Run the update query
     // ============================================================================================
     $update = array("user_class_id" => $dest_class, "when_class_set" => gmdate("Y-m-d H:i:s"), "when_class_expires" => null);
     try {
         $result = $db->runUpdateQueryCol(FOX_user::_struct(), $update, "user_class_id", "=", $id);
     } catch (FOX_exception $child) {
         throw new FOX_exception(array('numeric' => 3, 'text' => "DB update exception", 'data' => array("data" => $update, "col" => "usewr_class_id", "op" => "=", "val" => $id), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child));
     }
     // TODO: Although this code will move the users to the new class and delete the old class, it will cause
     // huge problems if the classes have different limitations. For example, if the old class allowed video
     // uploads in albums, and the new class does not. Or if the old class allowed 10 instances of an album
     // type and the new one does not, etc. We need to come up with ways to resolve these problems.
 }