/** * Get an array of courses (with magic extra bits) * where the accessdata and in DB enrolments show * that the cap requested is available. * * The main use is for get_my_courses(). * * Notes * * - $fields is an array of fieldnames to ADD * so name the fields you really need, which will * be added and uniq'd * * - the course records have $c->context which is a fully * valid context object. Saves you a query per course! * * - the course records have $c->categorypath to make * category lookups cheap * * - current implementation is split in - * * - if the user has the cap systemwide, stupidly * grab *every* course for a capcheck. This eats * a TON of bandwidth, specially on large sites * with separate DBs... * * - otherwise, fetch "likely" courses with a wide net * that should get us _cheaply_ at least the courses we need, and some * we won't - we get courses that... * - are in a category where user has the cap * - or where use has a role-assignment (any kind) * - or where the course has an override on for this cap * * - walk the courses recordset checking the caps oneach one * the checks are all in memory and quite fast * (though we could implement a specialised variant of the * has_capability_in_accessdata() code to speed it up) * * @param string $capability - name of the capability * @param array $accessdata - accessdata session array * @param bool $doanything - if false, ignore do anything * @param string $sort - sorting fields - prefix each fieldname with "c." * @param array $fields - additional fields you are interested in... * @param int $limit - set if you want to limit the number of courses * @return array $courses - ordered array of course objects - see notes above * */ function get_user_courses_bycap($userid, $cap, $accessdata, $doanything, $sort = 'c.sortorder ASC', $fields = NULL, $limit = 0) { global $CFG, $DB; // Slim base fields, let callers ask for what they need... $basefields = array('id', 'sortorder', 'shortname', 'idnumber'); if (!is_null($fields)) { $fields = array_merge($basefields, $fields); $fields = array_unique($fields); } else { $fields = $basefields; } // If any of the fields is '*', leave it alone, discarding the rest // to avoid ambiguous columns under some silly DBs. See MDL-18746 :-D if (in_array('*', $fields)) { $fields = array('*'); } $coursefields = 'c.' . implode(',c.', $fields); $sort = trim($sort); if ($sort !== '') { $sort = "ORDER BY {$sort}"; } $sysctx = get_context_instance(CONTEXT_SYSTEM); if (has_capability_in_accessdata($cap, $sysctx, $accessdata, $doanything)) { // // Apparently the user has the cap sitewide, so walk *every* course // (the cap checks are moderately fast, but this moves massive bandwidth w the db) // Yuck. // $sql = "SELECT {$coursefields},\n ctx.id AS ctxid, ctx.path AS ctxpath,\n ctx.depth AS ctxdepth, ctx.contextlevel AS ctxlevel,\n cc.path AS categorypath\n FROM {course} c\n JOIN {course_categories} cc\n ON c.category=cc.id\n JOIN {context} ctx\n ON (c.id=ctx.instanceid AND ctx.contextlevel=" . CONTEXT_COURSE . ")\n {$sort} "; $rs = $DB->get_recordset_sql($sql); } else { // // narrow down where we have the caps to a few contexts // this will be a combination of // - courses where user has an explicit enrolment // - courses that have an override (any status) on that capability // - categories where user has the rights (granted status) on that capability // $sql = "SELECT ctx.*\n FROM {context} ctx\n WHERE ctx.contextlevel=" . CONTEXT_COURSECAT . "\n ORDER BY ctx.depth"; $rs = $DB->get_recordset_sql($sql); $catpaths = array(); foreach ($rs as $catctx) { if ($catctx->path != '' && has_capability_in_accessdata($cap, $catctx, $accessdata, $doanything)) { $catpaths[] = $catctx->path; } } $rs->close(); $catclause = ''; $params = array(); if (count($catpaths)) { $cc = count($catpaths); for ($n = 0; $n < $cc; $n++) { $catpaths[$n] = "ctx.path LIKE '{$catpaths[$n]}/%'"; } $catclause = 'WHERE (' . implode(' OR ', $catpaths) . ')'; } unset($catpaths); $capany = ''; if ($doanything) { $capany = " OR rc.capability=:doany"; $params['doany'] = 'moodle/site:doanything'; } /// UNION 3 queries: /// - user role assignments in courses /// - user capability (override - any status) in courses /// - user right (granted status) in categories (optionally executed) /// Enclosing the 3-UNION into an inline_view to avoid column names conflict and making the ORDER BY cross-db /// and to allow selection of TEXT columns in the query (MSSQL and Oracle limitation). MDL-16209 $sql = "\n SELECT {$coursefields}, ctxid, ctxpath, ctxdepth, ctxlevel, categorypath\n FROM (\n SELECT c.id,\n ctx.id AS ctxid, ctx.path AS ctxpath,\n ctx.depth AS ctxdepth, ctx.contextlevel AS ctxlevel,\n cc.path AS categorypath\n FROM {course} c\n JOIN {course_categories} cc\n ON c.category=cc.id\n JOIN {context} ctx\n ON (c.id=ctx.instanceid AND ctx.contextlevel=" . CONTEXT_COURSE . ")\n JOIN {role_assignments} ra\n ON (ra.contextid=ctx.id AND ra.userid=:userid)\n UNION\n SELECT c.id,\n ctx.id AS ctxid, ctx.path AS ctxpath,\n ctx.depth AS ctxdepth, ctx.contextlevel AS ctxlevel,\n cc.path AS categorypath\n FROM {course} c\n JOIN {course_categories} cc\n ON c.category=cc.id\n JOIN {context} ctx\n ON (c.id=ctx.instanceid AND ctx.contextlevel=" . CONTEXT_COURSE . ")\n JOIN {role_capabilities} rc\n ON (rc.contextid=ctx.id AND (rc.capability=:cap {$capany})) "; if (!empty($catclause)) { /// If we have found the right in categories, add child courses here too $sql .= "\n UNION\n SELECT c.id,\n ctx.id AS ctxid, ctx.path AS ctxpath,\n ctx.depth AS ctxdepth, ctx.contextlevel AS ctxlevel,\n cc.path AS categorypath\n FROM {course} c\n JOIN {course_categories} cc\n ON c.category=cc.id\n JOIN {context} ctx\n ON (c.id=ctx.instanceid AND ctx.contextlevel=" . CONTEXT_COURSE . ")\n {$catclause}"; } /// Close the inline_view and join with courses table to get requested $coursefields $sql .= "\n ) inline_view\n INNER JOIN {course} c\n ON inline_view.id = c.id"; /// To keep cross-db we need to strip any prefix in the ORDER BY clause for queries using UNION $sql .= "\n " . preg_replace('/[a-z]+\\./i', '', $sort); /// Add ORDER BY clause $params['userid'] = $userid; $params['cap'] = $cap; $rs = $DB->get_recordset_sql($sql, $params); } /// Confirm rights (granted capability) for each course returned $courses = array(); $cc = 0; // keep count if ($rs) { foreach ($rs as $c) { // build the context obj $c = make_context_subobj($c); if (has_capability_in_accessdata($cap, $c->context, $accessdata, $doanything)) { $courses[] = $c; if ($limit > 0 && $cc++ > $limit) { break; } } } $rs->close(); } return $courses; }
// only show the plugin if multiple enrolment plugins // are enabled... if (strpos($CFG->enrol_plugins_enabled, ',') === false) { $showenrolplugin = true; } else { $showenrolplugin = false; } $usersprinted = array(); foreach ($userlist as $user) { if (in_array($user->id, $usersprinted)) { /// Prevent duplicates by r.hidden - MDL-13935 continue; } $usersprinted[] = $user->id; /// Add new user to the array of users printed $user = make_context_subobj($user); if (!empty($user->hidden)) { // if the assignment is hidden, display icon $hidden = " <img src=\"{$CFG->pixpath}/t/show.gif\" title=\"" . get_string('userhashiddenassignments', 'role') . "\" alt=\"" . get_string('hiddenassign') . "\" class=\"hide-show-image\"/>"; } else { $hidden = ''; } if ($user->lastaccess) { $lastaccess = format_time(time() - $user->lastaccess, $datestring); } else { $lastaccess = $strnever; } if (empty($user->country)) { $country = ''; } else { if ($countrysort) {
/** * Returns a sorted list of categories. Each category object has a context * property that is a context object. * * When asking for $parent='none' it will return all the categories, regardless * of depth. Wheen asking for a specific parent, the default is to return * a "shallow" resultset. Pass false to $shallow and it will return all * the child categories as well. * * * @param string $parent The parent category if any * @param string $sort the sortorder * @param bool $shallow - set to false to get the children too * @return array of categories */ function get_categories($parent = 'none', $sort = NULL, $shallow = true) { global $DB; if ($sort === NULL) { $sort = 'ORDER BY cc.sortorder ASC'; } elseif ($sort === '') { // leave it as empty } else { $sort = "ORDER BY {$sort}"; } if ($parent === 'none') { $sql = "SELECT cc.*,\n ctx.id AS ctxid, ctx.path AS ctxpath,\n ctx.depth AS ctxdepth, ctx.contextlevel AS ctxlevel\n FROM {course_categories} cc\n JOIN {context} ctx\n ON cc.id=ctx.instanceid AND ctx.contextlevel=" . CONTEXT_COURSECAT . "\n {$sort}"; $params = array(); } elseif ($shallow) { $sql = "SELECT cc.*,\n ctx.id AS ctxid, ctx.path AS ctxpath,\n ctx.depth AS ctxdepth, ctx.contextlevel AS ctxlevel\n FROM {course_categories} cc\n JOIN {context} ctx\n ON cc.id=ctx.instanceid AND ctx.contextlevel=" . CONTEXT_COURSECAT . "\n WHERE cc.parent=?\n {$sort}"; $params = array($parent); } else { $sql = "SELECT cc.*,\n ctx.id AS ctxid, ctx.path AS ctxpath,\n ctx.depth AS ctxdepth, ctx.contextlevel AS ctxlevel\n FROM {course_categories} cc\n JOIN {context} ctx\n ON cc.id=ctx.instanceid AND ctx.contextlevel=" . CONTEXT_COURSECAT . "\n JOIN {course_categories} ccp\n ON (cc.path LIKE " . $DB->sql_concat('ccp.path', "'%'") . ")\n WHERE ccp.id=?\n {$sort}"; $params = array($parent); } $categories = array(); if ($rs = $DB->get_recordset_sql($sql, $params)) { foreach ($rs as $cat) { $cat = make_context_subobj($cat); if ($cat->visible || has_capability('moodle/category:viewhiddencategories', $cat->context)) { $categories[$cat->id] = $cat; } } $rs->close(); } return $categories; }
/** * Returns a sorted list of categories. Each category object has a context * property that is a context object. * * When asking for $parent='none' it will return all the categories, regardless * of depth. Wheen asking for a specific parent, the default is to return * a "shallow" resultset. Pass false to $shallow and it will return all * the child categories as well. * * * @param string $parent The parent category if any * @param string $sort the sortorder * @param bool $shallow - set to false to get the children too * @return array of categories */ function get_categories($parent = 'none', $sort = NULL, $shallow = true) { global $CFG; if ($sort === NULL) { $sort = 'ORDER BY cc.sortorder ASC'; } elseif ($sort === '') { // leave it as empty } else { $sort = "ORDER BY {$sort}"; } if ($parent === 'none') { $sql = "SELECT cc.*,\n ctx.id AS ctxid, ctx.path AS ctxpath,\n ctx.depth AS ctxdepth, ctx.contextlevel AS ctxlevel\n FROM {$CFG->prefix}course_categories cc\n JOIN {$CFG->prefix}context ctx\n ON cc.id=ctx.instanceid AND ctx.contextlevel=" . CONTEXT_COURSECAT . "\n {$sort}"; } elseif ($shallow) { $parent = (int) $parent; $sql = "SELECT cc.*,\n ctx.id AS ctxid, ctx.path AS ctxpath,\n ctx.depth AS ctxdepth, ctx.contextlevel AS ctxlevel\n FROM {$CFG->prefix}course_categories cc\n JOIN {$CFG->prefix}context ctx\n ON cc.id=ctx.instanceid AND ctx.contextlevel=" . CONTEXT_COURSECAT . "\n WHERE cc.parent={$parent}\n {$sort}"; } else { $parent = (int) $parent; $sql = "SELECT cc.*,\n ctx.id AS ctxid, ctx.path AS ctxpath,\n ctx.depth AS ctxdepth, ctx.contextlevel AS ctxlevel\n FROM {$CFG->prefix}course_categories cc\n JOIN {$CFG->prefix}context ctx\n ON cc.id=ctx.instanceid AND ctx.contextlevel=" . CONTEXT_COURSECAT . "\n JOIN {$CFG->prefix}course_categories ccp\n ON (cc.path LIKE " . sql_concat('ccp.path', "'%'") . ")\n WHERE ccp.id={$parent}\n {$sort}"; } $categories = array(); if ($rs = get_recordset_sql($sql)) { while ($cat = rs_fetch_next_record($rs)) { $cat = make_context_subobj($cat); if ($cat->visible || has_capability('moodle/category:visibility', $cat->context)) { $categories[$cat->id] = $cat; } } } return $categories; }
function get_context_users_bycap($context, $capability = 'moodle/course:view', $fields = NULL, $where = NULL, $sort = NULL, $limit = 0) { global $CFG; // Plan // // - Get all the *interesting* roles -- those that // have some rolecap entry in our ctx.path contexts // // - Get all RAs for any of those roles in any of our // interesting contexts, with userid & perm data // in a nice (per user?) order // // - Walk the resultset, computing the permissions // - actually - this is all a SQL subselect // // - Fetch user records against the subselect // // Slim base fields, let callers ask for what they need... $basefields = array('id', 'username'); if (!is_null($fields)) { $fields = array_merge($basefields, $fields); $fields = array_unique($fields); } else { $fields = $basefields; } $userfields = 'u.' . implode(',u.', $fields); $contexts = substr($context->path, 1); // kill leading slash $contexts = str_replace('/', ',', $contexts); $roles = array(); $sql = "SELECT DISTINCT rc.roleid\n FROM {$CFG->prefix}role_capabilities rc\n WHERE rc.capability = '{$capability}'\n AND rc.contextid IN ({$contexts})"; $rs = get_recordset_sql($sql); if ($rs->RecordCount()) { while ($u = rs_fetch_next_record($rs)) { $roles[] = $u->roleid; } } rs_close($rs); $roles = implode(',', $roles); // // User permissions subselect SQL // // - the open join condition to // role_capabilities // // - because both rc and ra entries are // _at or above_ our context, we don't care // about their depth, we just need to sum them // $sql = "SELECT ra.userid, SUM(rc.permission) AS permission\n FROM {$CFG->prefix}role_assignments ra\n JOIN {$CFG->prefix}role_capabilities rc\n ON (ra.roleid = rc.roleid AND rc.contextid IN ({$contexts}))\n WHERE ra.contextid IN ({$contexts})\n AND ra.roleid IN ({$roles})\n GROUP BY ra.userid"; // Get users $sql = "SELECT {$userfields},\n ctx.id AS ctxid, ctx.path AS ctxpath,\n ctx.depth AS ctxdepth, ctx.contextlevel AS ctxlevel\n FROM {$CFG->prefix}user u\n JOIN {$CFG->prefix}context ctx \n ON (u.id=ctx.instanceid AND ctx.contextlevel=" . CONTEXT_USER . ")\n JOIN ({$sql}) up\n ON u.id = up.userid\n WHERE up.permission > 0 AND u.username != 'guest'"; $rs = get_recordset_sql($sql); $users = array(); $cc = 0; // keep count if ($rs->RecordCount()) { while ($u = rs_fetch_next_record($rs)) { // build the context obj $u = make_context_subobj($u); $users[] = $u; if ($limit > 0 && $cc++ > $limit) { break; } } } rs_close($rs); return $users; }
/** * Get an array of courses (with magic extra bits) * where the accessdata and in DB enrolments show * that the cap requested is available. * * The main use is for get_my_courses(). * * Notes * * - $fields is an array of fieldnames to ADD * so name the fields you really need, which will * be added and uniq'd * * - the course records have $c->context which is a fully * valid context object. Saves you a query per course! * * - the course records have $c->categorypath to make * category lookups cheap * * - current implementation is split in - * * - if the user has the cap systemwide, stupidly * grab *every* course for a capcheck. This eats * a TON of bandwidth, specially on large sites * with separate DBs... * * - otherwise, fetch "likely" courses with a wide net * that should get us _cheaply_ at least the courses we need, and some * we won't - we get courses that... * - are in a category where user has the cap * - or where use has a role-assignment (any kind) * - or where the course has an override on for this cap * * - walk the courses recordset checking the caps oneach one * the checks are all in memory and quite fast * (though we could implement a specialised variant of the * has_capability_in_accessdata() code to speed it up) * * @param string $capability - name of the capability * @param array $accessdata - accessdata session array * @param bool $doanything - if false, ignore do anything * @param string $sort - sorting fields - prefix each fieldname with "c." * @param array $fields - additional fields you are interested in... * @param int $limit - set if you want to limit the number of courses * @return array $courses - ordered array of course objects - see notes above * */ function get_user_courses_bycap($userid, $cap, $accessdata, $doanything, $sort = 'c.sortorder ASC', $fields = NULL, $limit = 0) { global $CFG; // Slim base fields, let callers ask for what they need... $basefields = array('id', 'sortorder', 'shortname', 'idnumber'); if (!is_null($fields)) { $fields = array_merge($basefields, $fields); $fields = array_unique($fields); } else { $fields = $basefields; } $coursefields = 'c.' . implode(',c.', $fields); $sort = trim($sort); if ($sort !== '') { $sort = "ORDER BY {$sort}"; } $sysctx = get_context_instance(CONTEXT_SYSTEM); if (has_capability_in_accessdata($cap, $sysctx, $accessdata, $doanything)) { // // Apparently the user has the cap sitewide, so walk *every* course // (the cap checks are moderately fast, but this moves massive bandwidth w the db) // Yuck. // $sql = "SELECT {$coursefields},\n ctx.id AS ctxid, ctx.path AS ctxpath,\n ctx.depth AS ctxdepth, ctx.contextlevel AS ctxlevel,\n cc.path AS categorypath\n FROM {$CFG->prefix}course c\n JOIN {$CFG->prefix}course_categories cc\n ON c.category=cc.id\n JOIN {$CFG->prefix}context ctx \n ON (c.id=ctx.instanceid AND ctx.contextlevel=" . CONTEXT_COURSE . ")\n {$sort} "; $rs = get_recordset_sql($sql); } else { // // narrow down where we have the caps to a few contexts // this will be a combination of // - categories where we have the rights // - courses where we have an explicit enrolment OR that have an override // $sql = "SELECT ctx.*\n FROM {$CFG->prefix}context ctx\n WHERE ctx.contextlevel=" . CONTEXT_COURSECAT . "\n ORDER BY ctx.depth"; $rs = get_recordset_sql($sql); $catpaths = array(); while ($catctx = rs_fetch_next_record($rs)) { if ($catctx->path != '' && has_capability_in_accessdata($cap, $catctx, $accessdata, $doanything)) { $catpaths[] = $catctx->path; } } rs_close($rs); $catclause = ''; if (count($catpaths)) { $cc = count($catpaths); for ($n = 0; $n < $cc; $n++) { $catpaths[$n] = "ctx.path LIKE '{$catpaths[$n]}/%'"; } $catclause = 'OR (' . implode(' OR ', $catpaths) . ')'; } unset($catpaths); $capany = ''; if ($doanything) { $capany = " OR rc.capability='moodle/site:doanything'"; } // // Note here that we *have* to have the compound clauses // in the LEFT OUTER JOIN condition for them to return NULL // appropriately and narrow things down... // $sql = "SELECT {$coursefields},\n ctx.id AS ctxid, ctx.path AS ctxpath,\n ctx.depth AS ctxdepth, ctx.contextlevel AS ctxlevel,\n cc.path AS categorypath\n FROM {$CFG->prefix}course c\n JOIN {$CFG->prefix}course_categories cc\n ON c.category=cc.id\n JOIN {$CFG->prefix}context ctx \n ON (c.id=ctx.instanceid AND ctx.contextlevel=" . CONTEXT_COURSE . ")\n LEFT OUTER JOIN {$CFG->prefix}role_assignments ra\n ON (ra.contextid=ctx.id AND ra.userid={$userid})\n LEFT OUTER JOIN {$CFG->prefix}role_capabilities rc\n ON (rc.contextid=ctx.id AND (rc.capability='{$cap}' {$capany}))\n WHERE ra.id IS NOT NULL\n OR rc.id IS NOT NULL\n {$catclause}\n {$sort} "; $rs = get_recordset_sql($sql); } $courses = array(); $cc = 0; // keep count while ($c = rs_fetch_next_record($rs)) { // build the context obj $c = make_context_subobj($c); if (has_capability_in_accessdata($cap, $c->context, $accessdata, $doanything)) { $courses[] = $c; if ($limit > 0 && $cc++ > $limit) { break; } } } rs_close($rs); return $courses; }
/** * This method actually loads the blocks for our page from the database. * * @param boolean|null $includeinvisible * null (default) - load hidden blocks if $this->page->user_is_editing(); * true - load hidden blocks. * false - don't load hidden blocks. */ public function load_blocks($includeinvisible = null) { global $DB, $CFG; if (!is_null($this->birecordsbyregion)) { // Already done. return; } if ($CFG->version < 2009050619) { // Upgrade/install not complete. Don't try too show any blocks. $this->birecordsbyregion = array(); return; } // Ensure we have been initialised. if (!isset($this->defaultregion)) { $this->page->initialise_theme_and_output(); // If there are still no block regions, then there are no blocks on this page. if (empty($this->regions)) { $this->birecordsbyregion = array(); return; } } if (is_null($includeinvisible)) { $includeinvisible = $this->page->user_is_editing(); } if ($includeinvisible) { $visiblecheck = ''; } else { $visiblecheck = 'AND (bp.visible = 1 OR bp.visible IS NULL)'; } $context = $this->page->context; $contexttest = 'bi.parentcontextid = :contextid2'; $parentcontextparams = array(); $parentcontextids = get_parent_contexts($context); if ($parentcontextids) { list($parentcontexttest, $parentcontextparams) = $DB->get_in_or_equal($parentcontextids, SQL_PARAMS_NAMED, 'parentcontext0000'); $contexttest = "({$contexttest} OR (bi.showinsubcontexts = 1 AND bi.parentcontextid {$parentcontexttest}))"; } $pagetypepatterns = matching_page_type_patterns($this->page->pagetype); list($pagetypepatterntest, $pagetypepatternparams) = $DB->get_in_or_equal($pagetypepatterns, SQL_PARAMS_NAMED, 'pagetypepatterntest0000'); $params = array('subpage1' => $this->page->subpage, 'subpage2' => $this->page->subpage, 'contextid1' => $context->id, 'contextid2' => $context->id, 'pagetype' => $this->page->pagetype, 'contextblock' => CONTEXT_BLOCK); $sql = "SELECT\n bi.id,\n bp.id AS blockpositionid,\n bi.blockname,\n bi.parentcontextid,\n bi.showinsubcontexts,\n bi.pagetypepattern,\n bi.subpagepattern,\n bi.defaultregion,\n bi.defaultweight,\n COALESCE(bp.visible, 1) AS visible,\n COALESCE(bp.region, bi.defaultregion) AS region,\n COALESCE(bp.weight, bi.defaultweight) AS weight,\n bi.configdata,\n ctx.id AS ctxid,\n ctx.path AS ctxpath,\n ctx.depth AS ctxdepth,\n ctx.contextlevel AS ctxlevel\n\n FROM {block_instances} bi\n JOIN {block} b ON bi.blockname = b.name\n LEFT JOIN {block_positions} bp ON bp.blockinstanceid = bi.id\n AND bp.contextid = :contextid1\n AND bp.pagetype = :pagetype\n AND bp.subpage = :subpage1\n JOIN {context} ctx ON ctx.contextlevel = :contextblock\n AND ctx.instanceid = bi.id\n\n WHERE\n {$contexttest}\n AND bi.pagetypepattern {$pagetypepatterntest}\n AND (bi.subpagepattern IS NULL OR bi.subpagepattern = :subpage2)\n {$visiblecheck}\n AND b.visible = 1\n\n ORDER BY\n COALESCE(bp.region, bi.defaultregion),\n COALESCE(bp.weight, bi.defaultweight),\n bi.id"; $blockinstances = $DB->get_recordset_sql($sql, $params + $parentcontextparams + $pagetypepatternparams); $this->birecordsbyregion = $this->prepare_per_region_arrays(); $unknown = array(); foreach ($blockinstances as $bi) { $bi = make_context_subobj($bi); if ($this->is_known_region($bi->region)) { $this->birecordsbyregion[$bi->region][] = $bi; } else { $unknown[] = $bi; } } // Pages don't necessarily have a defaultregion. The one time this can // happen is when there are no theme block regions, but the script itself // has a block region in the main content area. if (!empty($this->defaultregion)) { $this->birecordsbyregion[$this->defaultregion] = array_merge($this->birecordsbyregion[$this->defaultregion], $unknown); } }