/** * 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); }
/** * 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); }
/** * 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); }
/** * 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 type_id of a given type_slug, for one or more slugs. * * @version 1.0 * @since 1.0 * @param int $module_id | Module id that owns this object type. * @param string $type_slug | Single slug as string. Multiple slugs as array of strings. * @return bool/array | Exception on failure. False on nonexistent. Array "type_slug"=>"type_id" on success. */ public function slugToTypeId($module_id, $type_slug) { $db = new FOX_db(); if (!is_array($type_slug)) { $type_slug = array($type_slug); } // Load as many id's as possible from the cache // ============================================ $result = array(); $missing_slugs = array(); $persistent_cache_loaded = false; foreach ($type_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_type_id"][$module_id])) { $result[$slug] = $this->cache["slug_to_type_id"][$module_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_type_id"][$module_id])) { $result[$slug] = $this->cache["slug_to_type_id"][$module_id][$slug]; } else { $missing_slugs[] = $slug; } } else { $missing_slugs[] = $slug; } } unset($slug); // Fetch any missing "type_slug"-"type_id" pairs from the db // =========================================================== if (count($missing_slugs) > 0) { $args = array(array("col" => "module_id", "op" => "=", "val" => $module_id), array("col" => "type_slug", "op" => "=", "val" => $missing_slugs)); $columns = array("mode" => "include", "col" => array("type_slug", "type_id")); $ctrl = array("format" => "array_key_single", "key_col" => "type_slug", "val_col" => "type_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)); } if ($db_result) { // The if($db_result) prevents array_merge() // foreach() from crashing on an empty db result $result = array_merge($result, $db_result); // Update the cache // ============================== 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 $slug => $type_id) { $cache_image["slug_to_type_id"][$slug] = $type_id; } unset($slug, $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; if (count($result) > 0) { return $result; } else { return false; } }
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 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_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); }
/** * Loads target data into the cache * * @version 1.0 * @since 1.0 * * @param array $data | Array of targets to cache, or null to cache all rows in the database * => VAL @param string/array $location | Single location as string. Multiple locations as array of strings. * => VAL @param string/array $target | Single target as string. Multiple targets as array of strings. * => VAL @param int/array $module_id | Single module_id as int. Multiple module_ids as array of int. * * @return bool | Exception on failure. False on nonexistent. True on success. */ public function load($data, $skip_load = false) { $db = new FOX_db(); $struct = self::_struct(); // Build and run query // =========================================================== $args = array(); if ($data["location"]) { $args[] = array("col" => "location", "op" => "=", "val" => $data["location"]); } elseif ($data["target"]) { $args[] = array("col" => "target", "op" => "=", "val" => $data["target"]); } elseif ($data["module_id"]) { $args[] = array("col" => "module_id", "op" => "=", "val" => $data["module_id"]); } $ctrl = array("format" => "array_key_array", "key_col" => array("location", "target")); $columns = null; try { $db_result = $db->runSelectQuery($struct, $args, $columns, $ctrl); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 1, 'text' => "Error reading from database", 'data' => array('args' => $args, 'columns' => $columns, 'ctrl' => $ctrl), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } if (!$db_result) { // No results were found return false; } // Fetch the persistent cache image // =================================================== if ($skip_load) { $cache_image = $this->cache; } else { try { $cache_image = self::readCache(); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 2, 'text' => "Cache read error", 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } } // Rebuild the cache image // =================================================== if (empty($data)) { $cache_image["all_cached"] = true; } elseif (!$data["target"] && !$data["module_id"]) { if (!is_array($data["location"])) { $cache_locations = array($data["location"]); } else { $cache_locations = $data["location"]; } foreach ($cache_locations as $location_name) { $cache_image["locations"][$location_name] = true; } unset($cache_locations, $location_name); } foreach ($db_result as $location => $targets) { foreach ($targets as $target => $target_data) { if ($location == "page") { // If the location is a page, only copy the fields used by pages $cache_image["data"][$location][$target]["module_id"] = $target_data["module_id"]; $cache_image["data"][$location][$target]["php_class"] = $target_data["php_class"]; } else { $cache_image["data"][$location][$target] = $target_data; } } unset($location, $targets); } unset($location, $targets); // Update the persistent cache // =================================================== try { self::writeCache($cache_image); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 3, 'text' => "Cache write error", 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } // Update the class cache $this->cache = $cache_image; return true; }
/** * Loads node, branch, tree, or the entire datastore into the cache * * @version 1.0 * @since 1.0 * * @param int/array $tree| Single tree id as int. * @param int/array $branch | Single branch id as int. * @param string/array $node | Single node name as string. Multiple node names as array of strings. * @param bool $skip_load | If set true, the function will not update the class cache array from * the persistent cache before adding data from a db call and saving it * back to the persistent cache. * * @return bool | Exception on failure. True on success. */ public function load($tree = null, $branch = null, $node = null, $skip_load = false) { $db = new FOX_db(); $struct = $this->_struct(); // Build and run query // =========================================================== $args = array(array("col" => "tree", "op" => "=", "val" => $tree)); if ($branch) { $args[] = array("col" => "branch", "op" => "=", "val" => $branch); if ($node) { $args[] = array("col" => "node", "op" => "=", "val" => $node); } } $ctrl = array("format" => "array_key_array", "key_col" => array("tree", "branch", "node")); $columns = null; try { $db_result = $db->runSelectQuery($struct, $args, $columns, $ctrl); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 1, 'text' => "Error reading from database", 'data' => array('args' => $args, 'ctrl' => $ctrl), 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => $child)); } if ($db_result) { // Fetch the persistent cache image // =================================================== if ($skip_load) { $cache_image = $this->cache; } else { try { $cache_image = self::readCache(); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 2, 'text' => "Cache read error", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => $child)); } } // Rebuild the cache image // =================================================== $ancestor_cached = false; if (!$tree) { // Indicate all data for the module_id is cached $cache_image["all_cached"] = true; // Clear descendent dictionaries, because they're redundant unset($cache_image["trees"]); unset($cache_image["branches"]); // Prevent descendents from loading their dictionaries $ancestor_cached = true; } foreach ($db_result as $_tree => $branches) { if (!$branch && !$ancestor_cached) { $cache_image["trees"][$_tree] = true; unset($cache_image["branches"][$_tree]); $ancestor_cached = true; } foreach ($branches as $_branch => $nodes) { if (!$node && !$ancestor_cached) { $cache_image["branches"][$_tree][$_branch] = true; } foreach ($nodes as $_node => $val) { $cache_image["keys"][$_tree][$_branch][$_node] = $val; } unset($_node, $val); } unset($_branch, $nodes); } unset($_tree, $branches); // Clear empty walks from dictionary arrays $cache_image["branches"] = FOX_sUtil::arrayPrune($cache_image["branches"], 1); // Update the persistent cache // =================================================== try { self::writeCache($cache_image); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 3, 'text' => "Cache write error", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => $child)); } // Update the class cache $this->cache = $cache_image; } return true; }
/** * Removes one or more users from one or more groups * * @version 1.0 * @since 1.0 * * @param int/array $user_id | Single user_id as int. Multiple user_id's as array of ints. * @param int/array $group_id | Single group_id as int. Multiple group_id's as array of ints. * @return int | False on failure. Int number of rows deleted on success. Int 0 if no rows deleted. */ public function removeFromGroup($user_id, $group_id) { global $fox; $db = new FOX_db(); try { $gk = new FOX_uGroupKeyRing(); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 1, 'text' => "FOX_uGroupKeyRing constructor exception", 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } // CASE 1: Single user_id, single group_id // ================================================================= if (!is_array($user_id) && !is_array($group_id)) { // Get the combined keyring of the user's current groups, // minus the one we're removing the user from $args = array(array("col" => "user_id", "op" => "=", "val" => $user_id), array("col" => "group_id", "op" => "!=", "val" => $group_id)); $columns = array("mode" => "include", "col" => "group_id"); $ctrl = array("format" => "col"); try { $in_groups = $db->runSelectQuery(self::$struct, $args, $columns, $ctrl); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 2, 'text' => "DB select exception", 'data' => array("args" => $args, "columns" => $columns, "ctrl" => $ctrl), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } try { $keep_keys = $gk->getKeys($in_groups); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 3, 'text' => "FOX_uGroupKeyRing getKeys exception", 'data' => array("in_groups" => $in_groups), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } // Get the keyring for 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' => 4, 'text' => "FOX_uGroupKeyRing getKeys exception", 'data' => array("group_id" => $group_id), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } // Intersect the remove group's keyring with the user's other groups' keyrings // to determine the keys that need to be revoked from the user's keyring if ($keep_keys && $drop_keys) { $revoke_keys = array_diff($drop_keys, $keep_keys); } else { $revoke_keys = $drop_keys; } // @@@@@@ BEGIN TRANSACTION @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ try { $transaction_started = $db->beginTransaction(); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 5, 'text' => "beginTransaction exception", 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } if ($transaction_started) { // Drop the user-group pair from the groupstore db table $args = array(array("col" => "user_id", "op" => "=", "val" => $user_id), array("col" => "group_id", "op" => "=", "val" => $group_id)); try { $rows_changed = $db->runDeleteQuery(self::$struct, $args); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 6, 'text' => "DB delete exception", 'data' => $args, 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } // If the user is not a member of the group we are attempting to delete // them from, return "0" to indicate that no rows were changed if (!$rows_changed) { try { $db->rollbackTransaction(); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 7, 'text' => "rollbackTransaction exception", 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } return 0; } // Revoke the keys on the group's keyring that the user is not // being granted by other groups if ($revoke_keys) { $ks = new FOX_uKeyRing(); try { $keys_ok = $ks->revokeKey($user_id, $revoke_keys); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 8, 'text' => "FOX_uKeyRing revokeKey exception", 'data' => array("user_id" => $user_id, "revoke_keys" => $revoke_keys), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } } else { // Handle no keys to revoke $keys_ok = true; } // If all operations were successful, commit the transaction if ($rows_changed && $keys_ok) { try { $commit_ok = $db->commitTransaction(); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 9, 'text' => "commitTransaction exception", 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } // Update the cache if ($commit_ok) { // Load, update, writeback $this->cache[$user_id] = $fox->cache->get("FOX_uGroupMember", $user_id); $this->cache[$user_id]["keys"][$group_id] = false; $cache_ok = $fox->cache->set("FOX_uGroupMember", $user_id, $this->cache[$user_id]); if ($cache_ok) { return $rows_changed; } else { return false; } } else { return false; } } else { try { $db->rollbackTransaction(); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 10, 'text' => "rollbackTransaction exception", 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } return false; } } else { // If we couldn't start a transaction, return false return false; } // @@@@@@ END TRANSACTION @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ } // CASE 2: Single user_id, multiple groups // ================================================================= if (!is_array($user_id) && is_array($group_id)) { // Get the combined keyring of all the user's current groups, // minus the groups we're removing them from $args = array(array("col" => "user_id", "op" => "=", "val" => $user_id), array("col" => "group_id", "op" => "!=", "val" => $group_id)); $columns = array("mode" => "include", "col" => "group_id"); $ctrl = array("format" => "col"); try { $in_groups = $db->runSelectQuery(self::$struct, $args, $columns, $ctrl); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 11, 'text' => "DB select exception", 'data' => array("args" => $args, "columns" => $columns, "ctrl" => $ctrl), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } try { $keep_keys = $gk->getKeys($in_groups); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 12, 'text' => "FOX_uGroupKeyRing getKeys exception", 'data' => array("in_groups" => $in_groups), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } // Get the combined keyring of all the groups that we're // removing the user from try { $drop_keys = $gk->getKeys($group_id); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 13, 'text' => "FOX_uGroupKeyRing getKeys exception", 'data' => array("groiup_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; } // @@@@@@ BEGIN TRANSACTION @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ try { $transaction_started = $db->beginTransaction(); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 14, 'text' => "beginTransaction exception", 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } if ($transaction_started) { // Drop the user-group pairs from the groupstore db table $args = array(array("col" => "user_id", "op" => "=", "val" => $user_id), array("col" => "group_id", "op" => "=", "val" => $group_id)); try { $rows_changed = $db->runDeleteQuery(self::$struct, $args); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 15, 'text' => "DB delete exception", 'data' => $args, 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } // If the user is not a member of any of the groups we're trying to delete // them from, return "0" to indicate that no db rows were changed if (!$rows_changed) { try { $db->rollbackTransaction(); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 16, 'text' => "rollbackTransaction exception", 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } return 0; } // Revoke all the keys we previously calculated if ($revoke_keys) { $ks = new FOX_uKeyRing(); try { $keys_ok = $ks->revokeKey($user_id, $revoke_keys); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 17, 'text' => "FOX_uKeyRing revokeKey exception", 'data' => array("user_id" => $user_id, "revoke_keys" => $revoke_keys), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } } else { // Handle no keys to revoke $keys_ok = true; } // If all operations were successful, commit the transaction if ($rows_changed && $keys_ok) { 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)); } // Update the cache if ($commit_ok) { // Load, update, writeback $this->cache[$user_id] = $fox->cache->get("FOX_uGroupMember", $user_id); foreach ($group_id as $group) { $this->cache[$user_id]["keys"][$group] = false; } unset($group); $cache_ok = $fox->cache->set("FOX_uGroupMember", $user_id, $this->cache[$user_id]); if ($cache_ok) { return $rows_changed; } else { return false; } } else { return false; } } else { try { $db->rollbackTransaction(); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 19, 'text' => "rollbackTransaction exception", 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } return false; } } else { // If we couldn't start a transaction, return false return false; } // @@@@@@ END TRANSACTION @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ } // CASE 3: Multiple user_id's, single group // ================================================================= if (is_array($user_id) && !is_array($group_id)) { // 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_id), 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(self::$struct, $args, $columns = null, $ctrl); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 20, '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' => 21, 'text' => "beginTransaction exception", 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } if ($started_transaction) { $all_ok = true; try { $gk = new FOX_uGroupKeyRing(); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 22, 'text' => "FOX_uGroupKeyRing constructor exception", 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } foreach ($user_id 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' => 23, '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' => 24, '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 { $keys_ok = $ks->revokeKey($user, $revoke_keys); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 25, 'text' => "FOX_uKeyRing revokeKey exception", 'data' => array("user" => $user, "revoke_keys" => $revoke_keys), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } if ($keys_ok === false) { // Handles (int)0 return value from revokeKey() $all_ok = false; // if we try to remove a key from a user that doesn't } // have the key, as part of removing a key from } // a large batch of users } unset($user); // Drop the user-group pairs from the groupstore db table $args = array(array("col" => "user_id", "op" => "=", "val" => $user_id), array("col" => "group_id", "op" => "=", "val" => $group_id)); try { $rows_changed = $db->runDeleteQuery(self::$struct, $args); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 26, 'text' => "DB delete exception", 'data' => $args, 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } // If none of the users are a member of the group we're trying to delete // them from, return "0" to indicate that no db rows were changed if (!$rows_changed) { try { $db->rollbackTransaction(); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 27, 'text' => "rollbackTransaction exception", 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } return 0; } // If all operations completed successfully, commit the transaction and // return the result of the commit. // ======================================================= if ($rows_changed && $all_ok) { try { $commit_ok = $db->commitTransaction(); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 28, 'text' => "commitTransaction exception", 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } // Update the cache if ($commit_ok) { $all_ok = true; foreach ($user_id as $user) { // Load, update, writeback $this->cache[$user] = $fox->cache->get("FOX_uGroupMember", $user); $this->cache[$user]["keys"][$group_id] = false; $cache_ok = $fox->cache->set("FOX_uGroupMember", $user, $this->cache[$user]); if (!$cache_ok) { $all_ok = false; } } unset($user); if ($all_ok) { return $rows_changed; } else { return false; } } else { return false; } } else { try { $db->rollbackTransaction(); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 29, 'text' => "rollbackTransaction exception", 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } return false; } } else { // If we couldn't start a transaction, return false return false; } // @@@@@@ END TRANSACTION @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ } // CASE 4: Multiple user_id's, multiple groups // ================================================================= if (is_array($user_id) && is_array($group_id)) { // Load all of the groups that each user is currently in, except // for the groups we're deleting users from $args = array(array("col" => "user_id", "op" => "=", "val" => $user_id), 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(self::$struct, $args, $columns = null, $ctrl); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 30, 'text' => "DB select exception", 'data' => array("args" => $args, "ctrl" => $ctrl), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } // @@@@@@ BEGIN TRANSACTION @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ if ($db->beginTransaction()) { $all_ok = true; try { $gk = new FOX_uGroupKeyRing(); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 31, 'text' => "FOX_uGroupKeyRing constructor exception", 'data' => array("in_groups" => $in_groups), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } foreach ($user_id 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' => 32, 'text' => "FOX_uGroupKeyRing getKeys exception", 'data' => array("user" => $in_groups[$user]), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } // Get the keyring of the groups we're removing the user from try { $drop_keys = $gk->getKeys($group_id); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 33, '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 { $keys_ok = $ks->revokeKey($user, $revoke_keys); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 34, 'text' => "FOX_uKeyRing revokeKey exception", 'data' => array("user" => $user, "revoke_keys" => $revoke_keys), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } if ($keys_ok === false) { // Handles (int)0 return value from revokeKey() $all_ok = false; // if we try to remove a key from a user that doesn't } // have the key, as part of removing a key from } // a large batch of users } unset($user); // Drop the user-group pairs from the groupstore db table $args = array(array("col" => "user_id", "op" => "=", "val" => $user_id), array("col" => "group_id", "op" => "=", "val" => $group_id)); try { $rows_changed = $db->runDeleteQuery(self::$struct, $args); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 35, 'text' => "DB delete exception", 'data' => $args, 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } // If none of the users are a members of any of the groups we're trying to delete // them from, return "0" to indicate that no db rows were changed if (!$rows_changed) { try { $db->rollbackTransaction(); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 36, 'text' => "rollbackTransaction exception", 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } return 0; } // If all operations completed successfully, commit the transaction and // return the result of the commit. // ======================================================= if ($rows_changed && $all_ok) { try { $commit_ok = $db->commitTransaction(); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 37, 'text' => "commitTransaction exception", 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } // Update the cache if ($commit_ok) { $all_ok = true; foreach ($user_id as $user) { // Load, update, writeback $this->cache[$user] = $fox->cache->get("FOX_uGroupMember", $user); foreach ($group_id as $group) { $this->cache[$user]["keys"][$group] = false; } $cache_ok = $fox->cache->set("FOX_uGroupMember", $user, $this->cache[$user]); if (!$cache_ok) { $all_ok = false; } } unset($user, $group); if ($all_ok) { return $rows_changed; } else { return false; } } else { return false; } } else { try { $db->rollbackTransaction(); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 38, 'text' => "rollbackTransaction exception", 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } return false; } } else { // If we couldn't start a transaction, return false return false; } // @@@@@@ END TRANSACTION @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ } }
/** * Loads key, type_id, REMOVE, or all data for one or more modules from the db * into the key cache * * @version 1.0 * @since 1.0 * * @param int/array $module_id | Single module id as int. Multiple module id as array of int. * @param string/array $type_id | Single type_id name as string. Multiple type_id id as array of string. * @param string/array $branch_id | Single type as string. Multiple types as array of strings. * @param int/array $key_id | Single key_id as int. Multiple key_id's as array of ints. * @param bool $skip_load | If set true, the function will not update the class cache array from * the persistent cache before adding data from a db call and saving it * back to the persistent cache. * * @return bool | Exception on failure. True on success. */ public function load($module_id, $type_id = null, $branch_id = null, $key_id = null, $skip_load = false) { $db = new FOX_db(); $struct = $this->_struct(); // Build and run query // =========================================================== $args = array(array("col" => "module_id", "op" => "=", "val" => $module_id)); if ($type_id) { $args[] = array("col" => "type_id", "op" => "=", "val" => $type_id); if ($branch_id) { $args[] = array("col" => "branch_id", "op" => "=", "val" => $branch_id); if ($key_id) { $args[] = array("col" => "key_id", "op" => "=", "val" => $key_id); } } } $ctrl = array("format" => "array_key_array", "key_col" => array("module_id", "type_id", "branch_id", "key_id")); $columns = null; try { $db_result = $db->runSelectQuery($struct, $args, $columns, $ctrl); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 1, 'text' => "Error loading requested keys from database", 'data' => array("module_id" => $module_id, "type_id" => $type_id, "branch_id" => $branch_id, "key_id" => $key_id, "skip_load" => $skip_load), 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => $child)); } if (!$db_result) { // If the query returned zero results, no further work needs to be done return true; } // Load the persistent cache records for all returned module_id's into // the temp class cache // ===================================================================== $module_ids = array_keys($db_result); if ($skip_load) { foreach ($module_ids as $_module_id) { $update_cache[$_module_id] = $this->cache[$_module_id]; } unset($_module_id); } else { try { $update_cache = self::readCachePage($module_ids); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 2, 'text' => "Cache get error", 'data' => array("module_ids" => array_keys($db_result)), 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => $child)); } } unset($module_ids); // Overwrite the temp cache records with the data fetched in the db query, // while setting the correct heirarchical cache flags // ===================================================================== $ancestor_cached = false; foreach ($db_result as $_module_id => $type_ids) { if (!$type_id) { // Indicate all data for the module_id is cached $update_cache[$_module_id]["all_cached"] = true; // Clear descendent dictionaries, because they're redundant unset($update_cache[$_module_id]["type_id"]); unset($update_cache[$_module_id]["branch_id"]); // Prevent descendents from loading their dictionaries $ancestor_cached = true; } foreach ($type_ids as $_type_id => $branch_ids) { if (!$branch_id && !$ancestor_cached) { $update_cache[$_module_id]["type_id"][$_type_id] = true; unset($update_cache[$_module_id]["branch_id"]); $ancestor_cached = true; } foreach ($branch_ids as $_branch_id => $key_ids) { if (!$key_id && !$ancestor_cached) { $update_cache[$_module_id]["branch_id"][$_type_id][$_branch_id] = true; } foreach ($key_ids as $_key_id => $val) { $update_cache[$_module_id]["keys"][$_type_id][$_branch_id][$_key_id] = $val["key_id"]; } unset($_key_id, $val); } unset($_branch_id, $key_ids); } unset($_type_id, $branch_ids); } unset($_module_id, $type_ids); // Clear empty walks from dictionary arrays $update_cache["branch_id"] = FOX_sUtil::arrayPrune($update_cache["branch_id"], 1); // Overwrite the persistent cache records with the temp class cache array // ===================================================================== try { self::writeCachePage($update_cache); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 3, 'text' => "Cache set error", 'data' => $update_cache, 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => $child)); } // Write the temp class cache array items to the class cache array foreach ($update_cache as $update_module_id => $module_data) { $this->cache[$update_module_id] = $module_data; } unset($update_module_id, $module_data); return true; }
/** * Loads user keys into the cache. * * @version 1.0 * @since 1.0 * * @param int/array $user_id | Single user id as int. Multiple user id's as array of int. * @param int/array $key_id | Single key id as int. Multiple key ids as array of int. * @return bool | False on failure. True on success. */ public function load($user_id, $key_id = null, $skip_load = false) { global $fox; $db = new FOX_db(); $args = array(); if ($user_id) { $args[] = array("col" => "user_id", "op" => "=", "val" => $user_id); } if ($key_id) { $args[] = array("col" => "key_id", "op" => "=", "val" => $key_id); } $columns = array("mode" => "include", "col" => array("user_id", "key_id")); $ctrl = array("format" => "array_key_array_grouped", "key_col" => array("user_id", "key_id")); try { $db_result = $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)); } // When the function is called with specific keys to look for, if a user doesn't // have that key, we can add that information to the cache. This saves a query // the next time the key is requested. if ($db_result) { if ($key_id) { if (!is_array($user_id)) { $user_id = array($user_id); } if (!is_array($key_id)) { $key_id = array($key_id); } $all_ok = true; foreach ($user_id as $user) { // Load the persistent cache record for the user_id into the class's cache array if (!$skip_load) { $this->cache[$user] = $fox->cache->get("FOX_uKeyRing", $user); } foreach ($key_id as $key) { if (FOX_sUtil::valExists($key, $db_result[$user])) { $this->cache[$user]["keys"][$key] = true; } else { $this->cache[$user]["keys"][$key] = false; } } // Save the updated persistent cache record for the user_id $cache_ok = $fox->cache->set("FOX_uData", $user, $this->cache[$user]); if (!$cache_ok) { $all_ok = false; } } return $all_ok; } else { // If the function is called without $key_id set, all of the keys for each user will be added // to the cache. At this point we can unset all of the user's "false" keys because we know the // list of keys is authoratative (if it's not in the array, they don't have the key). $all_ok = true; foreach ($db_result as $user => $keys) { unset($this->cache[$user]); $this->cache[$user]["all_cached"] = true; foreach ($keys as $key) { $this->cache[$user]["keys"][$key] = true; } // Save the updated persistent cache record for the user_id $cache_ok = $fox->cache->set("FOX_uData", $user, $this->cache[$user]); if (!$cache_ok) { $all_ok = false; } } return $all_ok; } } 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 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); }
/** * 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" }
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); }
/** * Loads group keys into the cache. * * @version 1.0 * @since 1.0 * * @param int/array $group_id | Single group id as int. Multiple group id's as array of int. * @param int/array $key_id | Single key id as int. Multiple key ids as array of int. * @param bool $skip_load | If set true, the function will not update the class cache array from * the persistent cache before adding data from a db call and saving it * back to the persistent cache. * @return bool | False on failure. True on success. */ public function load($group_id, $key_id = null, $skip_load = false) { global $fox; $db = new FOX_db(); $args = array(); $args = array(array("col" => "group_id", "op" => "=", "val" => $group_id)); if ($key_id) { $args[] = array("col" => "key_id", "op" => "=", "val" => $key_id); } $columns = array("mode" => "include", "col" => array("group_id", "key_id")); $ctrl = array("format" => "array_key_array_true", "key_col" => array("group_id", "key_id")); try { $db_result = $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)); } // Load the class cache array from the persistent cache if (!$skip_load) { try { self::loadCache(); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 2, 'text' => "loadCache exception", 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } } if ($db_result) { // When the function is called with specific keys to look for, if a group doesn't // have that key, we can add that information to the cache. This saves a query // the next time the key is requested. if ($key_id) { if (!is_array($group_id)) { $group_id = array($group_id); } if (!is_array($key_id)) { $key_id = array($key_id); } foreach ($group_id as $group) { foreach ($key_id as $key) { if (FOX_sUtil::keyExists($key, $db_result[$group])) { $this->cache["keys"][$group][$key] = true; } else { $this->cache["keys"][$group][$key] = false; } } unset($key); } unset($group); } else { // If the function is called with only a group_id, all of the keys that // group has will be added to the cache. But we cannot add information // about what keys a group *doesn't* have to the list, because we don't // have a list of keys to check against. foreach ($db_result as $group => $keys) { // Flag the entire group as cached $this->cache["groups"][$group] = true; foreach ($keys as $key => $fake_var) { // $fake_var is needed because we're operating on // key names, not key values $this->cache["keys"][$group][$key] = true; } unset($key); } unset($group, $keys); } // Write the updated local cache array to the persistent cache try { $cache_ok = self::saveCache(); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 3, 'text' => "saveCache exception", 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } return $cache_ok; } else { return false; } }
/** * Loads key, branch, tree, or all data for one or more users from the db * into the key cache * * @version 1.0 * @since 1.0 * * @param int/array $user_id | Single user id as int. Multiple user id as array of int. * @param int/array $tree | Single tree id as int. Multiple tree id as array of int. * @param int/array $branch | Single branch id as int. Multiple branch id as array of int. * @param string/array $key | Single key as string. Multiple keys as array of strings. * @param bool $skip_load | If set true, the function will not update the class cache array from * the persistent cache before adding data from a db call and saving it * back to the persistent cache. * @return bool | False on failure. True on success. */ public function load($user_id, $tree = null, $branch = null, $key = null, $skip_load = false) { global $rad; $db = new FOX_db(); // Run query // =========================================================== $args = array(array("col" => "user_id", "op" => "=", "val" => $user_id)); if ($tree) { $args[] = array("col" => "tree", "op" => "=", "val" => $tree); if ($branch) { $args[] = array("col" => "branch", "op" => "=", "val" => $branch); if ($key) { $args[] = array("col" => "node", "op" => "=", "val" => $key); } } } $ctrl = array("format" => "array_key_array", "key_col" => array("user_id", "tree", "branch", "node")); try { $db_result = $db->runSelectQuery(self::$struct, $args, $columns = null, $ctrl); } catch (FOX_exception $child) { $debug_args = array("user_id" => $user_id, "tree" => $tree, "branch" => $branch, "key" => $key, "skip_load" => $skip_load); throw new FOX_exception(array('numeric' => 1, 'text' => "Db select exception ", 'data' => $debug_args, 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } // Update cache // =========================================================== if (!$db_result) { // If the query returned zero results, no further work needs to be done return true; } else { // Key or array of keys from the *same branch* and *same tree* // -------------------------------------------------------------- if ($user_id && $tree && $branch && $key) { // Load the persistent cache record for the user_id into the class's cache array if (!$skip_load) { try { $this->cache[$user_id] = $rad->cache->get("FOX_uData", $user_id, $valid); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 2, 'text' => "Cache get exception", 'data' => array("user_id" => $user_id, "tree" => $tree, "branch" => $branch, "key" => $key), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } } // Overwrite the class cache array with the data fetched in the db query foreach ($db_result[$user_id][$tree][$branch] as $key_name => $val) { $this->cache[$user_id]["keys"][$tree][$branch][$key_name] = $val["val"]; } // Overwrite the persistent cache record with the updated class cache array try { $cache_ok = $rad->cache->set("FOX_uData", $user_id, $this->cache[$user_id]); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 3, 'text' => "Cache set exception", 'data' => array("user_id" => $user_id, "tree" => $tree, "branch" => $branch, "key" => $key), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } } elseif ($user_id && $tree && $branch && !$key) { // Load the persistent cache record for the user_id into the class's cache array if (!$skip_load) { try { $this->cache[$user_id] = $rad->cache->get("FOX_uData", $user_id, $valid); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 4, 'text' => "Cache get exception", 'data' => array("user_id" => $user_id, "tree" => $tree, "branch" => $branch), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } } // Overwrite the class cache array with the data fetched in the db query foreach ($db_result[$user_id][$tree] as $branch_name => $keys) { foreach ($keys as $key_name => $val) { $this->cache[$user_id]["keys"][$tree][$branch_name][$key_name] = $val["val"]; } // Set the branch cache $this->cache[$user_id]["branch"][$tree][$branch_name] = true; } // Overwrite the persistent cache record with the updated class cache array try { $cache_ok = $rad->cache->set("FOX_uData", $user_id, $this->cache[$user_id]); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 5, 'text' => "Cache set exception", 'data' => array("user_id" => $user_id, "tree" => $tree, "branch" => $branch), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } } elseif ($user_id && $tree && !$branch && !$key) { // Load the persistent cache record for the user_id into the class's cache array if (!$skip_load) { try { $this->cache[$user_id] = $rad->cache->get("FOX_uData", $user_id, $valid); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 6, 'text' => "Cache get exception", 'data' => array("user_id" => $user_id, "tree" => $tree), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } } // Overwrite the class cache array with the data fetched in the db query foreach ($db_result[$user_id] as $tree_name => $branches) { foreach ($branches as $branch_name => $keys) { foreach ($keys as $key_name => $val) { $this->cache[$user_id]["keys"][$tree_name][$branch_name][$key_name] = $val["val"]; } } // Set the tree cache $this->cache[$user_id]["tree"][$tree_name] = true; } // Overwrite the persistent cache record with the updated class cache array try { $cache_ok = $rad->cache->set("FOX_uData", $user_id, $this->cache[$user_id]); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 7, 'text' => "Cache set exception", 'data' => array("user_id" => $user_id, "tree" => $tree), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } } elseif ($user_id && !$tree && !$branch && !$key) { $cache_ok = true; foreach ($db_result as $single_user => $trees) { // Load the persistent cache record for the user_id into the class's cache array if (!$skip_load) { try { $this->cache[$single_user] = $rad->cache->get("FOX_uData", $single_user, $valid); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 8, 'text' => "Cache get exception", 'data' => array("user_id" => $user_id), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } } // Overwrite the class cache array with the data fetched in the db query foreach ($trees as $tree_name => $branches) { foreach ($branches as $branch_name => $keys) { foreach ($keys as $key_name => $val) { $this->cache[$single_user]["keys"][$tree_name][$branch_name][$key_name] = $val["val"]; } } } // Set the all_cached flag $this->cache[$single_user]["all_cached"] = true; // Overwrite the persistent cache record with the updated class cache array try { $cache_ok = $rad->cache->set("FOX_uData", $single_user, $this->cache[$single_user]); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 9, 'text' => "Cache set exception", 'data' => array("user_id" => $user_id), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } } } 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 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; } }
/** * Loads module_slug data into the cache * * @version 1.0 * @since 1.0 * * @param array $data | Array of identifiers to cache, or null to cache all rows in the database * => VAL @param string/array $module_type | Single module_type as string. Multiple module_types as array of strings. * => VAL @param string/array $module_slug | Single module_slug as string. Multiple module_slugs as array of strings. * => VAL @param int/array $module_id | Single module_id as int. Multiple module_ids as array of int. * * @return array | Exception on failure. False on nonexistent. Results array on success. */ public function load($data = null, $skip_load = false) { $db = new FOX_db(); $struct = self::_struct(); $args = array(); // Build query args // ==================================================================== if ($data["module_type"]) { $args[] = array("col" => "module_type", "op" => "=", "val" => $data["module_type"]); } elseif ($data["module_slug"]) { $args[] = array("col" => "module_slug", "op" => "=", "val" => $data["module_slug"]); } elseif ($data["module_id"]) { $args[] = array("col" => "module_id", "op" => "=", "val" => $data["module_id"]); } $ctrl = array("format" => "array_key_array", "key_col" => array("module_type", "module_slug")); $columns = null; try { $db_result = $db->runSelectQuery($struct, $args, $columns, $ctrl); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 1, 'text' => "Error reading from database", 'data' => array('args' => $args, 'ctrl' => $ctrl), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } if (!$db_result) { // No results were found return false; } else { // Fetch the persistent cache image // =================================================== if ($skip_load) { $cache_image = $this->cache; } else { try { $cache_image = self::readCache(); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 2, 'text' => "Cache read error", 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } } // Rebuild the cache image // =================================================== if (!$data["module_type"] && !$data["module_slug"] && !$data["module_id"]) { $cache_image["all_cached"] = true; } elseif (!$data["module_slug"] && !$data["module_id"]) { if (!is_array($data["module_type"])) { $cache_module_types = array($data["module_type"]); } else { $cache_module_types = $data["module_type"]; } foreach ($cache_module_types as $module_type_name) { $cache_image["module_types"][$module_type_name] = true; } unset($cache_module_types, $module_type_name); } foreach ($db_result as $module_type => $module_slugs) { foreach ($module_slugs as $module_slug => $module_slug_data) { $cache_image["data"][$module_type][$module_slug] = $module_slug_data; } unset($module_type, $module_slugs); } unset($module_type, $module_slugs); // Update the persistent cache // =================================================== try { self::writeCache($cache_image); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 3, 'text' => "Cache write error", 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } // Update the class cache $this->cache = $cache_image; return true; } }