Proyectos de Subversion Moodle

Rev

Rev 1 | Mostrar el archivo completo | | | Autoría | Ultima modificación | Ver Log |

Rev 1 Rev 1441
Línea 336... Línea 336...
336
     * @param string|int $key
336
     * @param string|int $key
337
     * @param pix_icon $icon
337
     * @param pix_icon $icon
338
     * @return navigation_node
338
     * @return navigation_node
339
     */
339
     */
340
    public static function create($text, $action=null, $type=self::TYPE_CUSTOM,
340
    public static function create($text, $action=null, $type=self::TYPE_CUSTOM,
341
            $shorttext=null, $key=null, pix_icon $icon=null) {
341
            $shorttext=null, $key=null, ?pix_icon $icon=null) {
342
        if ($action && !($action instanceof moodle_url || $action instanceof action_link)) {
342
        if ($action && !($action instanceof moodle_url || $action instanceof action_link)) {
343
            debugging(
343
            debugging(
344
                "It is required that the action provided be either an action_url|moodle_url." .
344
                "It is required that the action provided be either an action_url|moodle_url." .
345
                " Please update your definition.", E_NOTICE);
345
                " Please update your definition.", E_NOTICE);
346
        }
346
        }
Línea 376... Línea 376...
376
     * @param string $shorttext
376
     * @param string $shorttext
377
     * @param string|int $key
377
     * @param string|int $key
378
     * @param pix_icon $icon
378
     * @param pix_icon $icon
379
     * @return navigation_node
379
     * @return navigation_node
380
     */
380
     */
381
    public function add($text, $action=null, $type=self::TYPE_CUSTOM, $shorttext=null, $key=null, pix_icon $icon=null) {
381
    public function add($text, $action=null, $type=self::TYPE_CUSTOM, $shorttext=null, $key=null, ?pix_icon $icon=null) {
382
        if ($action && is_string($action)) {
382
        if ($action && is_string($action)) {
383
            $action = new moodle_url($action);
383
            $action = new moodle_url($action);
384
        }
384
        }
385
        // Create child node
385
        // Create child node
386
        $childnode = self::create($text, $action, $type, $shorttext, $key, $icon);
386
        $childnode = self::create($text, $action, $type, $shorttext, $key, $icon);
Línea 882... Línea 882...
882
     * @param array $typestohide Optional. An array of node types that should be hidden.
882
     * @param array $typestohide Optional. An array of node types that should be hidden.
883
     *      If null all nodes will be hidden.
883
     *      If null all nodes will be hidden.
884
     *      If an array is given then nodes will only be hidden if their type mtatches an element in the array.
884
     *      If an array is given then nodes will only be hidden if their type mtatches an element in the array.
885
     *          e.g. array(navigation_node::TYPE_COURSE) would hide only course nodes.
885
     *          e.g. array(navigation_node::TYPE_COURSE) would hide only course nodes.
886
     */
886
     */
887
    public function hide(array $typestohide = null) {
887
    public function hide(?array $typestohide = null) {
888
        if ($typestohide === null || in_array($this->type, $typestohide)) {
888
        if ($typestohide === null || in_array($this->type, $typestohide)) {
889
            $this->display = false;
889
            $this->display = false;
890
            if ($this->has_children()) {
890
            if ($this->has_children()) {
891
                foreach ($this->children as $child) {
891
                foreach ($this->children as $child) {
892
                    $child->hide($typestohide);
892
                    $child->hide($typestohide);
Línea 1015... Línea 1015...
1015
                    'contextlocking',
1015
                    'contextlocking',
1016
                     new pix_icon($lockicon, '')
1016
                     new pix_icon($lockicon, '')
1017
                );
1017
                );
1018
            }
1018
            }
1019
        }
1019
        }
-
 
1020
    }
-
 
1021
 
-
 
1022
    /**
-
 
1023
     * Reset all static data.
-
 
1024
     *
-
 
1025
     * @throws coding_exception if called outside of a unit test
-
 
1026
     */
-
 
1027
    public static function reset_all_data(): void {
-
 
1028
        if (!defined('PHPUNIT_TEST') || !PHPUNIT_TEST) {
-
 
1029
            throw new coding_exception('Resetting all data is not allowed outside of PHPUnit tests.');
-
 
1030
        }
Línea -... Línea 1031...
-
 
1031
 
-
 
1032
        self::$fullmeurl = null;
-
 
1033
        self::$autofindactive = true;
1020
 
1034
        self::$loadadmintree = false;
1021
    }
1035
    }
Línea 1022... Línea 1036...
1022
}
1036
}
1023
 
1037
 
Línea 1350... Línea 1364...
1350
        if (during_initial_install()) {
1364
        if (during_initial_install()) {
1351
            return;
1365
            return;
1352
        }
1366
        }
Línea 1353... Línea 1367...
1353
 
1367
 
1354
        $homepage = get_home_page();
1368
        $homepage = get_home_page();
1355
        if ($homepage == HOMEPAGE_SITE) {
1369
        if ($homepage == HOMEPAGE_MY) {
1356
            // We are using the site home for the root element.
1370
            // We are using the users my moodle for the root element.
1357
            $properties = array(
1371
            $properties = array(
1358
                'key' => 'home',
1372
                'key' => 'myhome',
1359
                'type' => navigation_node::TYPE_SYSTEM,
1373
                'type' => navigation_node::TYPE_SYSTEM,
1360
                'text' => get_string('home'),
1374
                'text' => get_string('myhome'),
1361
                'action' => new moodle_url('/'),
1375
                'action' => new moodle_url('/my/'),
1362
                'icon' => new pix_icon('i/home', '')
1376
                'icon' => new pix_icon('i/dashboard', ''),
1363
            );
1377
            );
1364
        } else if ($homepage == HOMEPAGE_MYCOURSES) {
1378
        } else if ($homepage == HOMEPAGE_MYCOURSES) {
1365
            // We are using the user's course summary page for the root element.
1379
            // We are using the user's course summary page for the root element.
1366
            $properties = array(
1380
            $properties = array(
Línea 1369... Línea 1383...
1369
                'text' => get_string('mycourses'),
1383
                'text' => get_string('mycourses'),
1370
                'action' => new moodle_url('/my/courses.php'),
1384
                'action' => new moodle_url('/my/courses.php'),
1371
                'icon' => new pix_icon('i/course', '')
1385
                'icon' => new pix_icon('i/course', '')
1372
            );
1386
            );
1373
        } else {
1387
        } else {
1374
            // We are using the users my moodle for the root element.
1388
            // We are using the site home for the root element.
1375
            $properties = array(
1389
            $properties = array(
1376
                'key' => 'myhome',
1390
                'key' => 'home',
1377
                'type' => navigation_node::TYPE_SYSTEM,
1391
                'type' => navigation_node::TYPE_SYSTEM,
1378
                'text' => get_string('myhome'),
1392
                'text' => get_string('home'),
1379
                'action' => new moodle_url('/my/'),
1393
                'action' => new moodle_url('/'),
1380
                'icon' => new pix_icon('i/dashboard', '')
1394
                'icon' => new pix_icon('i/home', ''),
1381
            );
1395
            );
1382
        }
1396
        }
Línea 1383... Línea 1397...
1383
 
1397
 
1384
        // Use the parents constructor.... good good reuse
1398
        // Use the parents constructor.... good good reuse
Línea 2202... Línea 2216...
2202
            $activity = $coursenode->find($cm->id, self::TYPE_ACTIVITY);
2216
            $activity = $coursenode->find($cm->id, self::TYPE_ACTIVITY);
2203
            if (empty($activity)) {
2217
            if (empty($activity)) {
2204
                $activity = $this->load_stealth_activity($coursenode, get_fast_modinfo($course));
2218
                $activity = $this->load_stealth_activity($coursenode, get_fast_modinfo($course));
2205
            }
2219
            }
2206
        }
2220
        }
2207
   }
2221
    }
Línea 2208... Línea 2222...
2208
 
2222
 
2209
    /**
2223
    /**
2210
     * Generates an array of sections and an array of activities for the given course.
2224
     * Generates an array of sections and an array of activities for the given course.
2211
     *
2225
     *
Línea 2218... Línea 2232...
2218
        global $CFG;
2232
        global $CFG;
2219
        require_once($CFG->dirroot.'/course/lib.php');
2233
        require_once($CFG->dirroot.'/course/lib.php');
Línea 2220... Línea 2234...
2220
 
2234
 
2221
        $modinfo = get_fast_modinfo($course);
2235
        $modinfo = get_fast_modinfo($course);
-
 
2236
        $sections = $modinfo->get_section_info_all();
Línea 2222... Línea 2237...
2222
        $sections = $modinfo->get_section_info_all();
2237
        $format = course_get_format($course);
2223
 
2238
 
2224
        // For course formats using 'numsections' trim the sections list
2239
        // For course formats using 'numsections' trim the sections list
2225
        $courseformatoptions = course_get_format($course)->get_format_options();
2240
        $courseformatoptions = $format->get_format_options();
2226
        if (isset($courseformatoptions['numsections'])) {
2241
        if (isset($courseformatoptions['numsections'])) {
Línea 2227... Línea 2242...
2227
            $sections = array_slice($sections, 0, $courseformatoptions['numsections']+1, true);
2242
            $sections = array_slice($sections, 0, $courseformatoptions['numsections']+1, true);
Línea 2228... Línea 2243...
2228
        }
2243
        }
2229
 
2244
 
2230
        $activities = array();
2245
        $activities = [];
2231
 
2246
 
2232
        foreach ($sections as $key => $section) {
2247
        foreach ($sections as $key => $section) {
2233
            // Clone and unset summary to prevent $SESSION bloat (MDL-31802).
2248
            // Clone and unset summary to prevent $SESSION bloat (MDL-31802).
2234
            $sections[$key] = clone($section);
2249
            $sections[$key] = clone($section);
2235
            unset($sections[$key]->summary);
2250
            unset($sections[$key]->summary);
2236
            $sections[$key]->hasactivites = false;
2251
            $sections[$key]->hasactivites = false;
2237
            if (!array_key_exists($section->section, $modinfo->sections)) {
-
 
2238
                continue;
2252
            if (!array_key_exists($section->sectionnum, $modinfo->sections)) {
2239
            }
2253
                continue;
2240
            foreach ($modinfo->sections[$section->section] as $cmid) {
2254
            }
2241
                $cm = $modinfo->cms[$cmid];
2255
            foreach ($section->get_sequence_cm_infos() as $cm) {
2242
                $activity = new stdClass;
2256
                $activity = new stdClass;
2243
                $activity->id = $cm->id;
2257
                $activity->id = $cm->id;
2244
                $activity->course = $course->id;
2258
                $activity->course = $course->id;
2245
                $activity->section = $section->section;
2259
                $activity->section = $section->sectionnum;
2246
                $activity->name = $cm->name;
2260
                $activity->name = $cm->name;
2247
                $activity->icon = $cm->icon;
2261
                $activity->icon = $cm->icon;
2248
                $activity->iconcomponent = $cm->iconcomponent;
2262
                $activity->iconcomponent = $cm->iconcomponent;
2249
                $activity->hidden = (!$cm->visible);
2263
                $activity->hidden = (!$cm->visible);
-
 
2264
                $activity->modname = $cm->modname;
-
 
2265
                $activity->nodetype = navigation_node::NODETYPE_LEAF;
-
 
2266
                $activity->onclick = $cm->onclick;
-
 
2267
                $url = $cm->url;
-
 
2268
 
-
 
2269
                // Activities witout url but with delegated section uses the section url.
-
 
2270
                $activity->delegatedsection = $cm->get_delegated_section_info();
-
 
2271
                if (empty($cm->url) && $activity->delegatedsection) {
-
 
2272
                    $url = $format->get_view_url(
-
 
2273
                        $activity->delegatedsection->sectionnum,
2250
                $activity->modname = $cm->modname;
2274
                        ['navigation' => true]
2251
                $activity->nodetype = navigation_node::NODETYPE_LEAF;
2275
                    );
2252
                $activity->onclick = $cm->onclick;
2276
                }
2253
                $url = $cm->url;
2277
 
2254
                if (!$url) {
2278
                if (!$url) {
2255
                    $activity->url = null;
2279
                    $activity->url = null;
2256
                    $activity->display = false;
2280
                    $activity->display = false;
2257
                } else {
2281
                } else {
2258
                    $activity->url = $url->out();
2282
                    $activity->url = $url->out();
2259
                    $activity->display = $cm->is_visible_on_course_page() ? true : false;
2283
                    $activity->display = $cm->is_visible_on_course_page() ? true : false;
2260
                    if (self::module_extends_navigation($cm->modname)) {
2284
                    if (self::module_extends_navigation($cm->modname)) {
2261
                        $activity->nodetype = navigation_node::NODETYPE_BRANCH;
2285
                        $activity->nodetype = navigation_node::NODETYPE_BRANCH;
2262
                    }
2286
                    }
2263
                }
2287
                }
2264
                $activities[$cmid] = $activity;
2288
                $activities[$cm->id] = $activity;
2265
                if ($activity->display) {
2289
                if ($activity->display) {
Línea 2266... Línea 2290...
2266
                    $sections[$key]->hasactivites = true;
2290
                    $sections[$key]->hasactivites = true;
2267
                }
2291
                }
Línea 2268... Línea 2292...
2268
            }
2292
            }
2269
        }
2293
        }
2270
 
2294
 
Línea 2282... Línea 2306...
2282
        global $CFG, $DB, $USER, $SITE;
2306
        global $CFG, $DB, $USER, $SITE;
2283
        require_once($CFG->dirroot.'/course/lib.php');
2307
        require_once($CFG->dirroot.'/course/lib.php');
Línea 2284... Línea 2308...
2284
 
2308
 
Línea 2285... Línea 2309...
2285
        list($sections, $activities) = $this->generate_sections_and_activities($course);
2309
        list($sections, $activities) = $this->generate_sections_and_activities($course);
2286
 
2310
 
2287
        $navigationsections = array();
-
 
2288
        foreach ($sections as $sectionid => $section) {
2311
        $navigationsections = [];
2289
            $section = clone($section);
2312
        foreach ($sections as $sectionid => $section) {
2290
            if ($course->id == $SITE->id) {
-
 
2291
                $this->load_section_activities($coursenode, $section->section, $activities);
-
 
2292
            } else {
-
 
2293
                if (!$section->uservisible || (!$this->showemptysections &&
2313
            if ($course->id == $SITE->id) {
2294
                        !$section->hasactivites && $this->includesectionnum !== $section->section)) {
2314
                $this->load_section_activities_navigation($coursenode, $section, $activities);
Línea -... Línea 2315...
-
 
2315
                continue;
-
 
2316
            }
-
 
2317
 
2295
                    continue;
2318
            if (
-
 
2319
                !$section->uservisible
2296
                }
2320
                || (
-
 
2321
                    !$this->showemptysections
-
 
2322
                    && !$section->hasactivites
-
 
2323
                    && $this->includesectionnum !== $section->section
-
 
2324
                )
Línea 2297... Línea -...
2297
 
-
 
2298
                $sectionname = get_section_name($course, $section);
2325
            ) {
2299
                $url = course_get_url($course, $section->section, array('navigation' => true));
2326
                continue;
2300
 
-
 
2301
                $sectionnode = $coursenode->add($sectionname, $url, navigation_node::TYPE_SECTION,
-
 
2302
                    null, $section->id, new pix_icon('i/section', ''));
-
 
2303
                $sectionnode->nodetype = navigation_node::NODETYPE_BRANCH;
-
 
2304
                $sectionnode->hidden = (!$section->visible || !$section->available);
2327
            }
2305
                $sectionnode->add_attribute('data-section-name-for', $section->id);
-
 
2306
                if ($this->includesectionnum !== false && $this->includesectionnum == $section->section) {
2328
 
-
 
2329
            // Delegated sections are added from the activity node.
-
 
2330
            if ($section->get_component_instance()) {
-
 
2331
                continue;
-
 
2332
            }
-
 
2333
 
-
 
2334
            $navigationsections[$sectionid] = $this->load_section_navigation(
2307
                    $this->load_section_activities($sectionnode, $section->section, $activities);
2335
                parentnode: $coursenode,
2308
                }
2336
                section: $section,
2309
                $navigationsections[$sectionid] = $section;
2337
                activitiesdata: $activities,
Línea 2310... Línea 2338...
2310
            }
2338
            );
-
 
2339
        }
-
 
2340
        return $navigationsections;
-
 
2341
    }
-
 
2342
 
-
 
2343
    /**
-
 
2344
     * Returns true if the section is included in the breadcrumb.
-
 
2345
     *
-
 
2346
     * @param section_info $section
-
 
2347
     * @param moodle_url|null $sectionurl
-
 
2348
     * @return bool
-
 
2349
     */
-
 
2350
    protected function is_section_in_breadcrumb(section_info $section, ?moodle_url $sectionurl): bool {
-
 
2351
        // Ajax requests uses includesectionnum as param.
-
 
2352
        if ($this->includesectionnum !== false && $this->includesectionnum == $section->sectionnum) {
-
 
2353
            return true;
-
 
2354
        }
-
 
2355
 
-
 
2356
        // If we are in a section page, we need to check for any child section.
-
 
2357
        $checkchildrenurls = false;
-
 
2358
        $format = null;
-
 
2359
        if ($sectionurl && $this->page->url->compare($sectionurl, URL_MATCH_BASE)) {
-
 
2360
            $checkchildrenurls = true;
-
 
2361
            $format = course_get_format($section->course);
-
 
2362
        }
-
 
2363
 
-
 
2364
        // Activities can have delegated sections that acts as a child section.
-
 
2365
        foreach ($section->get_sequence_cm_infos() as $cm) {
-
 
2366
            $delegatedsection = $cm->get_delegated_section_info();
-
 
2367
            if (!$delegatedsection) {
-
 
2368
                continue;
-
 
2369
            }
-
 
2370
            // Check if the child node is requested via Ajax.
-
 
2371
            if ($this->includesectionnum == $delegatedsection->sectionnum) {
-
 
2372
                return true;
-
 
2373
            }
-
 
2374
 
-
 
2375
            if ($checkchildrenurls) {
-
 
2376
                $childurl = $format->get_view_url($delegatedsection, ['navigation' => true]);
-
 
2377
                if ($childurl && $this->page->url->compare($childurl, URL_MATCH_EXACT)) {
-
 
2378
                    return true;
-
 
2379
                }
-
 
2380
            }
-
 
2381
        }
-
 
2382
 
-
 
2383
        return false;
-
 
2384
    }
-
 
2385
 
-
 
2386
    /**
-
 
2387
     * Loads a section into the navigation structure.
-
 
2388
     *
-
 
2389
     * @param navigation_node $parentnode
-
 
2390
     * @param section_info $section
-
 
2391
     * @param stdClass[] $activitiesdata Array of objects containing activities data indexed by cmid.
-
 
2392
     * @return navigation_node the section navigaiton node
-
 
2393
     */
-
 
2394
    public function load_section_navigation($parentnode, $section, $activitiesdata): navigation_node {
-
 
2395
        $format = course_get_format($section->course);
-
 
2396
        $sectionname = $format->get_section_name($section);
-
 
2397
        $url = $format->get_view_url($section, ['navigation' => true]);
-
 
2398
 
-
 
2399
        $sectionnode = $parentnode->add(
-
 
2400
            text: $sectionname,
-
 
2401
            action: $url,
-
 
2402
            type: navigation_node::TYPE_SECTION,
-
 
2403
            key: $section->id,
-
 
2404
            icon: new pix_icon('i/section', ''),
-
 
2405
        );
-
 
2406
        $sectionnode->nodetype = navigation_node::NODETYPE_BRANCH;
-
 
2407
        $sectionnode->hidden = (!$section->visible || !$section->available);
-
 
2408
        $sectionnode->add_attribute('data-section-name-for', $section->id);
-
 
2409
 
-
 
2410
        // Sections content are usually loaded via ajax but the sections from the requested breadcrumb.
-
 
2411
        if ($this->is_section_in_breadcrumb($section, $url)) {
-
 
2412
            $this->load_section_activities_navigation($sectionnode, $section, $activitiesdata);
2311
        }
2413
        }
-
 
2414
        return $sectionnode;
-
 
2415
    }
-
 
2416
 
2312
        return $navigationsections;
2417
    /**
2313
    }
2418
     * Loads the activities for a section into the navigation structure.
2314
 
2419
     *
2315
    /**
-
 
2316
     * Loads all of the activities for a section into the navigation structure.
2420
     * This method is called from global_navigation::load_section_navigation(),
2317
     *
-
 
2318
     * @param navigation_node $sectionnode
2421
     * It is not intended to be called directly.
2319
     * @param int $sectionnumber
2422
     *
-
 
2423
     * @param navigation_node $sectionnode
-
 
2424
     * @param section_info $section
-
 
2425
     * @param stdClass[] $activitiesdata Array of objects containing activities data indexed by cmid.
-
 
2426
     */
2320
     * @param array $activities An array of activites as returned by {@link global_navigation::generate_sections_and_activities()}
2427
    protected function load_section_activities_navigation(
2321
     * @param stdClass $course The course object the section and activities relate to.
-
 
2322
     * @return array Array of activity nodes
-
 
Línea 2323... Línea 2428...
2323
     */
2428
        navigation_node $sectionnode,
2324
    protected function load_section_activities(navigation_node $sectionnode, $sectionnumber, array $activities, $course = null) {
2429
        section_info $section,
2325
        global $CFG, $SITE;
2430
        array $activitiesdata
2326
        // A static counter for JS function naming
2431
    ): array {
Línea 2327... Línea -...
2327
        static $legacyonclickcounter = 0;
-
 
2328
 
2432
        global $CFG, $SITE;
2329
        $activitynodes = array();
2433
 
2330
        if (empty($activities)) {
-
 
2331
            return $activitynodes;
-
 
2332
        }
-
 
2333
 
-
 
Línea -... Línea 2434...
-
 
2434
        $activitynodes = [];
2334
        if (!is_object($course)) {
2435
        if (empty($activitiesdata)) {
-
 
2436
            return $activitynodes;
2335
            $activity = reset($activities);
2437
        }
-
 
2438
 
-
 
2439
        foreach ($section->get_sequence_cm_infos() as $cm) {
-
 
2440
            $activitydata = $activitiesdata[$cm->id];
2336
            $courseid = $activity->course;
2441
 
2337
        } else {
2442
            // If activity is a delegated section, load a section node instead of the activity one.
2338
            $courseid = $course->id;
-
 
2339
        }
-
 
2340
        $showactivities = ($courseid != $SITE->id || !empty($CFG->navshowfrontpagemods));
-
 
2341
 
-
 
2342
        foreach ($activities as $activity) {
-
 
Línea 2343... Línea -...
2343
            if ($activity->section != $sectionnumber) {
-
 
2344
                continue;
-
 
2345
            }
-
 
2346
            if ($activity->icon) {
-
 
2347
                $icon = new pix_icon($activity->icon, get_string('modulename', $activity->modname), $activity->iconcomponent);
-
 
2348
            } else {
-
 
2349
                $icon = new pix_icon('monologo', get_string('modulename', $activity->modname), $activity->modname);
-
 
2350
            }
-
 
2351
 
-
 
2352
            // Prepare the default name and url for the node
-
 
2353
            $displaycontext = \context_helper::get_navigation_filter_context(context_module::instance($activity->id));
-
 
2354
            $activityname = format_string($activity->name, true, ['context' => $displaycontext]);
-
 
2355
            $action = new moodle_url($activity->url);
-
 
2356
 
-
 
2357
            // Check if the onclick property is set (puke!)
-
 
2358
            if (!empty($activity->onclick)) {
-
 
2359
                // Increment the counter so that we have a unique number.
-
 
2360
                $legacyonclickcounter++;
-
 
2361
                // Generate the function name we will use
-
 
2362
                $functionname = 'legacy_activity_onclick_handler_'.$legacyonclickcounter;
-
 
2363
                $propogrationhandler = '';
-
 
2364
                // Check if we need to cancel propogation. Remember inline onclick
-
 
2365
                // events would return false if they wanted to prevent propogation and the
-
 
2366
                // default action.
-
 
2367
                if (strpos($activity->onclick, 'return false')) {
-
 
2368
                    $propogrationhandler = 'e.halt();';
-
 
2369
                }
-
 
2370
                // Decode the onclick - it has already been encoded for display (puke)
2443
            if ($activitydata->delegatedsection) {
2371
                $onclick = htmlspecialchars_decode($activity->onclick, ENT_QUOTES);
-
 
2372
                // Build the JS function the click event will call
-
 
2373
                $jscode = "function {$functionname}(e) { $propogrationhandler $onclick }";
-
 
2374
                $this->page->requires->js_amd_inline($jscode);
-
 
2375
                // Override the default url with the new action link
-
 
2376
                $action = new action_link($action, $activityname, new component_action('click', $functionname));
2444
                $activitynodes[$activitydata->id] = $this->load_section_navigation(
Línea 2377... Línea 2445...
2377
            }
2445
                    parentnode: $sectionnode,
2378
 
2446
                    section: $activitydata->delegatedsection,
-
 
2447
                    activitiesdata: $activitiesdata,
-
 
2448
                );
-
 
2449
                continue;
-
 
2450
            }
-
 
2451
 
-
 
2452
            $activitynodes[$activitydata->id] = $this->load_activity_navigation($sectionnode, $activitydata);
-
 
2453
        }
-
 
2454
 
-
 
2455
        return $activitynodes;
-
 
2456
    }
-
 
2457
 
-
 
2458
    /**
-
 
2459
     * Loads an activity into the navigation structure.
-
 
2460
     *
-
 
2461
     * This method is called from global_navigation::load_section_activities_navigation(),
-
 
2462
     * It is not intended to be called directly.
-
 
2463
     *
-
 
2464
     * @param navigation_node $sectionnode
-
 
2465
     * @param stdClass $activitydata The acitivy navigation data generated from generate_sections_and_activities
-
 
2466
     * @return navigation_node
-
 
2467
     */
-
 
2468
    protected function load_activity_navigation(
-
 
2469
        navigation_node $sectionnode,
-
 
2470
        stdClass $activitydata,
-
 
2471
    ): navigation_node {
-
 
2472
        global $SITE, $CFG;
-
 
2473
 
-
 
2474
        $showactivities = ($activitydata->course != $SITE->id || !empty($CFG->navshowfrontpagemods));
-
 
2475
 
-
 
2476
        $icon = new pix_icon(
-
 
2477
            $activitydata->icon ?: 'monologo',
-
 
2478
            get_string('modulename', $activitydata->modname),
-
 
2479
            $activitydata->icon ? $activitydata->iconcomponent : $activitydata->modname,
-
 
2480
        );
-
 
2481
 
-
 
2482
        // Prepare the default name and url for the node.
-
 
2483
        $displaycontext = \context_helper::get_navigation_filter_context(context_module::instance($activitydata->id));
-
 
2484
        $activityname = format_string($activitydata->name, true, ['context' => $displaycontext]);
-
 
2485
 
-
 
2486
        $activitynode = $sectionnode->add(
-
 
2487
            text: $activityname,
-
 
2488
            action: $this->get_activity_action($activitydata, $activityname),
-
 
2489
            type: navigation_node::TYPE_ACTIVITY,
-
 
2490
            key: $activitydata->id,
-
 
2491
            icon: $icon,
-
 
2492
        );
-
 
2493
        $activitynode->title(get_string('modulename', $activitydata->modname));
-
 
2494
        $activitynode->hidden = $activitydata->hidden;
-
 
2495
        $activitynode->display = $showactivities && $activitydata->display;
-
 
2496
        $activitynode->nodetype = $activitydata->nodetype;
-
 
2497
 
-
 
2498
        return $activitynode;
-
 
2499
    }
-
 
2500
 
-
 
2501
    /**
-
 
2502
     * Returns the action for the activity.
-
 
2503
     *
-
 
2504
     * @param stdClass $activitydata The acitivy navigation data generated from generate_sections_and_activities
-
 
2505
     * @param string $activityname
-
 
2506
     * @return moodle_url|action_link
-
 
2507
     */
-
 
2508
    protected function get_activity_action(stdClass $activitydata, string $activityname): moodle_url|action_link {
-
 
2509
        // A static counter for JS function naming.
-
 
2510
        static $legacyonclickcounter = 0;
-
 
2511
 
-
 
2512
        $action = new moodle_url($activitydata->url);
-
 
2513
 
-
 
2514
        // Check if the onclick property is set (puke!).
-
 
2515
        if (!empty($activitydata->onclick)) {
-
 
2516
            // Increment the counter so that we have a unique number.
-
 
2517
            $legacyonclickcounter++;
-
 
2518
            // Generate the function name we will use.
-
 
2519
            $functionname = 'legacy_activity_onclick_handler_' . $legacyonclickcounter;
-
 
2520
            $propogrationhandler = '';
-
 
2521
            // Check if we need to cancel propogation. Remember inline onclick
-
 
2522
            // events would return false if they wanted to prevent propogation and the
-
 
2523
            // default action.
-
 
2524
            if (strpos($activitydata->onclick, 'return false')) {
-
 
2525
                $propogrationhandler = 'e.halt();';
-
 
2526
            }
-
 
2527
            // Decode the onclick - it has already been encoded for display (puke).
-
 
2528
            $onclick = htmlspecialchars_decode($activitydata->onclick, ENT_QUOTES);
-
 
2529
            // Build the JS function the click event will call.
-
 
2530
            $jscode = "function {$functionname}(e) { $propogrationhandler $onclick }";
-
 
2531
            $this->page->requires->js_amd_inline($jscode);
-
 
2532
            // Override the default url with the new action link.
-
 
2533
            $action = new action_link($action, $activityname, new component_action('click', $functionname));
-
 
2534
        }
-
 
2535
        return $action;
-
 
2536
    }
-
 
2537
 
-
 
2538
    /**
-
 
2539
     * Loads all of the activities for a section into the navigation structure.
-
 
2540
     *
-
 
2541
     * @param navigation_node $sectionnode
-
 
2542
     * @param int $sectionnumber
-
 
2543
     * @param array $activities An array of activites as returned by {@link global_navigation::generate_sections_and_activities()}
-
 
2544
     * @param stdClass $course The course object the section and activities relate to.
-
 
2545
     * @return array Array of activity nodes
-
 
2546
     */
-
 
2547
    #[\core\attribute\deprecated(
-
 
2548
        replacement: 'load_section_activities_navigation',
-
 
2549
        since: '4.5',
-
 
2550
        mdl: 'MDL-82845',
-
 
2551
    )]
-
 
2552
    protected function load_section_activities(navigation_node $sectionnode, $sectionnumber, array $activities, $course = null) {
2379
            $activitynode = $sectionnode->add($activityname, $action, navigation_node::TYPE_ACTIVITY, null, $activity->id, $icon);
2553
        \core\deprecation::emit_deprecation([self::class, __FUNCTION__]);
2380
            $activitynode->title(get_string('modulename', $activity->modname));
2554
        if (!is_object($course)) {
2381
            $activitynode->hidden = $activity->hidden;
2555
            $activity = reset($activities);
2382
            $activitynode->display = $showactivities && $activity->display;
2556
            $courseid = $activity->course;
2383
            $activitynode->nodetype = $activity->nodetype;
2557
        } else {
Línea 2577... Línea 2751...
2577
                } else {
2751
                } else {
2578
                    $usernode->add(get_string('viewprofile'), new moodle_url('/user/view.php', $baseargs));
2752
                    $usernode->add(get_string('viewprofile'), new moodle_url('/user/view.php', $baseargs));
2579
                }
2753
                }
2580
            }
2754
            }
Línea 2581... Línea -...
2581
 
-
 
2582
            if (!empty($CFG->navadduserpostslinks)) {
-
 
2583
                // Add nodes for forum posts and discussions if the user can view either or both
-
 
2584
                // There are no capability checks here as the content of the page is based
-
 
2585
                // purely on the forums the current user has access too.
-
 
2586
                $forumtab = $usernode->add(get_string('forumposts', 'forum'));
-
 
2587
                $forumtab->add(get_string('posts', 'forum'), new moodle_url('/mod/forum/user.php', $baseargs));
-
 
2588
                $forumtab->add(get_string('discussions', 'forum'), new moodle_url('/mod/forum/user.php',
-
 
2589
                        array_merge($baseargs, array('mode' => 'discussions'))));
-
 
2590
            }
-
 
2591
 
2755
 
2592
            // Add blog nodes.
2756
            // Add blog nodes.
2593
            if (!empty($CFG->enableblogs)) {
2757
            if (!empty($CFG->enableblogs)) {
2594
                if (!$this->cache->cached('userblogoptions'.$user->id)) {
2758
                if (!$this->cache->cached('userblogoptions'.$user->id)) {
2595
                    require_once($CFG->dirroot.'/blog/lib.php');
2759
                    require_once($CFG->dirroot.'/blog/lib.php');
Línea 2973... Línea 3137...
2973
            $siteparticipantsnode->remove();
3137
            $siteparticipantsnode->remove();
2974
        }
3138
        }
Línea 2975... Línea 3139...
2975
 
3139
 
2976
        // Badges.
3140
        // Badges.
2977
        if ($navoptions->badges) {
3141
        if ($navoptions->badges) {
Línea 2978... Línea 3142...
2978
            $url = new moodle_url('/badges/view.php', array('type' => 2, 'id' => $course->id));
3142
            $url = new moodle_url('/badges/index.php', ['type' => 2, 'id' => $course->id]);
2979
 
3143
 
2980
            $coursenode->add(get_string('coursebadges', 'badges'), $url,
3144
            $coursenode->add(get_string('coursebadges', 'badges'), $url,
2981
                    navigation_node::TYPE_SETTING, null, 'badgesview',
3145
                    navigation_node::TYPE_SETTING, null, 'badgesview',
Línea 3010... Línea 3174...
3010
            ]);
3174
            ]);
3011
            $coursenode->add(get_string('communication', 'communication'), $url,
3175
            $coursenode->add(get_string('communication', 'communication'), $url,
3012
                navigation_node::TYPE_SETTING, null, 'communication');
3176
                navigation_node::TYPE_SETTING, null, 'communication');
3013
        }
3177
        }
Línea -... Línea 3178...
-
 
3178
 
-
 
3179
        if ($navoptions->overview) {
-
 
3180
            $coursenode->add(
-
 
3181
                text: get_string('activities'),
-
 
3182
                action: new moodle_url('/course/overview.php', ['id' => $course->id]),
-
 
3183
                type: self::TYPE_CONTAINER,
-
 
3184
                key: 'courseoverview',
-
 
3185
                icon: new pix_icon('i/info', ''),
-
 
3186
            );
-
 
3187
        }
3014
 
3188
 
3015
        return true;
3189
        return true;
3016
    }
3190
    }
3017
    /**
3191
    /**
3018
     * This generates the structure of the course that won't be generated when
3192
     * This generates the structure of the course that won't be generated when
Línea 3057... Línea 3231...
3057
 
3231
 
Línea 3058... Línea 3232...
3058
        $filterselect = 0;
3232
        $filterselect = 0;
3059
 
3233
 
3060
        // Badges.
3234
        // Badges.
3061
        if ($navoptions->badges) {
3235
        if ($navoptions->badges) {
3062
            $url = new moodle_url($CFG->wwwroot . '/badges/view.php', array('type' => 1));
3236
            $url = new moodle_url($CFG->wwwroot . '/badges/index.php', ['type' => 1]);
Línea 3063... Línea 3237...
3063
            $coursenode->add(get_string('sitebadges', 'badges'), $url, navigation_node::TYPE_CUSTOM);
3237
            $coursenode->add(get_string('sitebadges', 'badges'), $url, navigation_node::TYPE_CUSTOM);
3064
        }
3238
        }
Línea 3888... Línea 4062...
3888
     * @param string $shorttext
4062
     * @param string $shorttext
3889
     * @param string|int $key A key to identify this node with. Key + type is unique to a parent.
4063
     * @param string|int $key A key to identify this node with. Key + type is unique to a parent.
3890
     * @param pix_icon $icon An optional icon to use for this node.
4064
     * @param pix_icon $icon An optional icon to use for this node.
3891
     * @return navigation_node
4065
     * @return navigation_node
3892
     */
4066
     */
3893
    public function add($text, $action=null, $type=self::TYPE_CUSTOM, $shorttext=null, $key=null, pix_icon $icon=null) {
4067
    public function add($text, $action=null, $type=self::TYPE_CUSTOM, $shorttext=null, $key=null, ?pix_icon $icon=null) {
3894
        if ($this->content !== null) {
4068
        if ($this->content !== null) {
3895
            debugging('Nav bar items must be printed before $OUTPUT->header() has been called', DEBUG_DEVELOPER);
4069
            debugging('Nav bar items must be printed before $OUTPUT->header() has been called', DEBUG_DEVELOPER);
3896
        }
4070
        }
Línea 3897... Línea 4071...
3897
 
4071
 
Línea 3934... Línea 4108...
3934
     * @param string $shorttext
4108
     * @param string $shorttext
3935
     * @param string|int $key A key to identify this node with. Key + type is unique to a parent.
4109
     * @param string|int $key A key to identify this node with. Key + type is unique to a parent.
3936
     * @param pix_icon $icon An optional icon to use for this node.
4110
     * @param pix_icon $icon An optional icon to use for this node.
3937
     * @return navigation_node
4111
     * @return navigation_node
3938
     */
4112
     */
3939
    public function prepend($text, $action=null, $type=self::TYPE_CUSTOM, $shorttext=null, $key=null, pix_icon $icon=null) {
4113
    public function prepend($text, $action=null, $type=self::TYPE_CUSTOM, $shorttext=null, $key=null, ?pix_icon $icon=null) {
3940
        if ($this->content !== null) {
4114
        if ($this->content !== null) {
3941
            debugging('Nav bar items must be printed before $OUTPUT->header() has been called', DEBUG_DEVELOPER);
4115
            debugging('Nav bar items must be printed before $OUTPUT->header() has been called', DEBUG_DEVELOPER);
3942
        }
4116
        }
3943
        // Properties array used when creating the new navigation node.
4117
        // Properties array used when creating the new navigation node.
3944
        $itemarray = array(
4118
        $itemarray = array(
Línea 4466... Línea 4640...
4466
     * @param string $shorttext
4640
     * @param string $shorttext
4467
     * @param string|int $key a key to access the node by.
4641
     * @param string|int $key a key to access the node by.
4468
     * @param pix_icon $icon An icon that appears next to the node.
4642
     * @param pix_icon $icon An icon that appears next to the node.
4469
     * @return navigation_node with the new node added to it.
4643
     * @return navigation_node with the new node added to it.
4470
     */
4644
     */
4471
    public function add($text, $url=null, $type=null, $shorttext=null, $key=null, pix_icon $icon=null) {
4645
    public function add($text, $url=null, $type=null, $shorttext=null, $key=null, ?pix_icon $icon=null) {
4472
        $node = parent::add($text, $url, $type, $shorttext, $key, $icon);
4646
        $node = parent::add($text, $url, $type, $shorttext, $key, $icon);
4473
        $node->add_class('root_node');
4647
        $node->add_class('root_node');
4474
        return $node;
4648
        return $node;
4475
    }
4649
    }
Línea 4484... Línea 4658...
4484
     * @param string $shorttext
4658
     * @param string $shorttext
4485
     * @param string|int $key a key to access the node by.
4659
     * @param string|int $key a key to access the node by.
4486
     * @param pix_icon $icon An icon that appears next to the node.
4660
     * @param pix_icon $icon An icon that appears next to the node.
4487
     * @return navigation_node $node with the new node added to it.
4661
     * @return navigation_node $node with the new node added to it.
4488
     */
4662
     */
4489
    public function prepend($text, $url=null, $type=null, $shorttext=null, $key=null, pix_icon $icon=null) {
4663
    public function prepend($text, $url=null, $type=null, $shorttext=null, $key=null, ?pix_icon $icon=null) {
4490
        $children = $this->children;
4664
        $children = $this->children;
4491
        $childrenclass = get_class($children);
4665
        $childrenclass = get_class($children);
4492
        $this->children = new $childrenclass;
4666
        $this->children = new $childrenclass;
4493
        $node = $this->add($text, $url, $type, $shorttext, $key, $icon);
4667
        $node = $this->add($text, $url, $type, $shorttext, $key, $icon);
4494
        foreach ($children as $child) {
4668
        foreach ($children as $child) {
Línea 4529... Línea 4703...
4529
     *      navigation tree
4703
     *      navigation tree
4530
     * @param part_of_admin_tree $adminbranch The branch to add, if null generate the admin
4704
     * @param part_of_admin_tree $adminbranch The branch to add, if null generate the admin
4531
     *      tree and start at the beginning
4705
     *      tree and start at the beginning
4532
     * @return mixed A key to access the admin tree by
4706
     * @return mixed A key to access the admin tree by
4533
     */
4707
     */
4534
    protected function load_administration_settings(navigation_node $referencebranch=null, part_of_admin_tree $adminbranch=null) {
4708
    protected function load_administration_settings(?navigation_node $referencebranch=null, ?part_of_admin_tree $adminbranch=null) {
4535
        global $CFG;
4709
        global $CFG;
Línea 4536... Línea 4710...
4536
 
4710
 
4537
        // Check if we are just starting to generate this navigation.
4711
        // Check if we are just starting to generate this navigation.
Línea 4697... Línea 4871...
4697
            $coursenode->add(get_string('coursecompletion', 'completion'), $url, self::TYPE_SETTING, null, 'coursecompletion',
4871
            $coursenode->add(get_string('coursecompletion', 'completion'), $url, self::TYPE_SETTING, null, 'coursecompletion',
4698
                             new pix_icon('i/settings', ''));
4872
                             new pix_icon('i/settings', ''));
4699
        }
4873
        }
Línea 4700... Línea 4874...
4700
 
4874
 
-
 
4875
        if (!$adminoptions->update && $adminoptions->tags) {
-
 
4876
            $url = \core\router\util::get_path_for_callable([
-
 
4877
                \core_course\route\controller\tags_controller::class,
4701
        if (!$adminoptions->update && $adminoptions->tags) {
4878
                'administer_tags',
4702
            $url = new moodle_url('/course/tags.php', array('id' => $course->id));
4879
            ], ['course' => $course->id]);
4703
            $coursenode->add(get_string('coursetags', 'tag'), $url, self::TYPE_SETTING, null, 'coursetags', new pix_icon('i/settings', ''));
4880
            $coursenode->add(get_string('coursetags', 'tag'), $url, self::TYPE_SETTING, null, 'coursetags', new pix_icon('i/settings', ''));
4704
            $coursenode->get('coursetags')->set_force_into_more_menu();
4881
            $coursenode->get('coursetags')->set_force_into_more_menu();
Línea 4705... Línea 4882...
4705
        }
4882
        }
Línea 4739... Línea 4916...
4739
            if (!$reportnav->has_children()) {
4916
            if (!$reportnav->has_children()) {
4740
                $reportnav->remove();
4917
                $reportnav->remove();
4741
            }
4918
            }
4742
        }
4919
        }
Línea -... Línea 4920...
-
 
4920
 
-
 
4921
        // Grade penalty navigation.
-
 
4922
        \core_grades\penalty_manager::extend_navigation_course($coursenode, $course, $coursecontext);
4743
 
4923
 
4744
        // Check if we can view the gradebook's setup page.
4924
        // Check if we can view the gradebook's setup page.
4745
        if ($adminoptions->gradebook) {
4925
        if ($adminoptions->gradebook) {
4746
            $url = new moodle_url('/grade/edit/tree/index.php', array('id' => $course->id));
4926
            $url = new moodle_url('/grade/edit/tree/index.php', array('id' => $course->id));
4747
            $coursenode->add(get_string('gradebooksetup', 'grades'), $url, self::TYPE_SETTING,
4927
            $coursenode->add(get_string('gradebooksetup', 'grades'), $url, self::TYPE_SETTING,
Línea 4763... Línea 4943...
4763
            badges_add_course_navigation($coursenode, $course);
4943
            badges_add_course_navigation($coursenode, $course);
4764
        }
4944
        }
Línea 4765... Línea 4945...
4765
 
4945
 
4766
        // Questions
4946
        // Questions
-
 
4947
        require_once($CFG->libdir . '/questionlib.php');
4767
        require_once($CFG->libdir . '/questionlib.php');
4948
        $baseurl = \core_question\local\bank\question_bank_helper::get_url_for_qbank_list($course->id);
Línea 4768... Línea 4949...
4768
        question_extend_settings_navigation($coursenode, $coursecontext)->trim_if_empty();
4949
        question_extend_settings_navigation($coursenode, $coursecontext, $baseurl)->trim_if_empty();
4769
 
4950
 
4770
        if ($adminoptions->update) {
4951
        if ($adminoptions->update) {
4771
            // Repository Instances
4952
            // Repository Instances
Línea 4793... Línea 4974...
4793
        }
4974
        }
Línea 4794... Línea 4975...
4794
 
4975
 
4795
        // Let plugins hook into course navigation.
4976
        // Let plugins hook into course navigation.
4796
        $pluginsfunction = get_plugins_with_function('extend_navigation_course', 'lib.php');
4977
        $pluginsfunction = get_plugins_with_function('extend_navigation_course', 'lib.php');
4797
        foreach ($pluginsfunction as $plugintype => $plugins) {
4978
        foreach ($pluginsfunction as $plugintype => $plugins) {
4798
            // Ignore the report plugin as it was already loaded above.
4979
            // Ignore the report and gradepenalty plugins as they were already loaded above.
4799
            if ($plugintype == 'report') {
4980
            if ($plugintype == 'report' || $plugintype == 'gradepenalty') {
4800
                continue;
4981
                continue;
4801
            }
4982
            }
4802
            foreach ($plugins as $pluginfunction) {
4983
            foreach ($plugins as $pluginfunction) {
4803
                $pluginfunction($coursenode, $course, $coursecontext);
4984
                $pluginfunction($coursenode, $course, $coursecontext);
Línea 5189... Línea 5370...
5189
 
5370
 
5190
            // Add the user profile to the dashboard.
5371
            // Add the user profile to the dashboard.
5191
            $profilenode = $mainpage->add(get_string('profile'), new moodle_url('/user/profile.php',
5372
            $profilenode = $mainpage->add(get_string('profile'), new moodle_url('/user/profile.php',
Línea 5192... Línea -...
5192
                    array('id' => $user->id)), self::TYPE_SETTING, null, 'myprofile');
-
 
5193
 
-
 
5194
            if (!empty($CFG->navadduserpostslinks)) {
-
 
5195
                // Add nodes for forum posts and discussions if the user can view either or both
-
 
5196
                // There are no capability checks here as the content of the page is based
-
 
5197
                // purely on the forums the current user has access too.
-
 
5198
                $forumtab = $profilenode->add(get_string('forumposts', 'forum'));
-
 
5199
                $forumtab->add(get_string('posts', 'forum'), new moodle_url('/mod/forum/user.php', $baseargs), null, 'myposts');
-
 
5200
                $forumtab->add(get_string('discussions', 'forum'), new moodle_url('/mod/forum/user.php',
-
 
5201
                        array_merge($baseargs, array('mode' => 'discussions'))), null, 'mydiscussions');
-
 
5202
            }
5373
                    array('id' => $user->id)), self::TYPE_SETTING, null, 'myprofile');
5203
 
5374
 
5204
            // Add blog nodes.
5375
            // Add blog nodes.
5205
            if (!empty($CFG->enableblogs)) {
5376
            if (!empty($CFG->enableblogs)) {
5206
                if (!$this->cache->cached('userblogoptions'.$user->id)) {
5377
                if (!$this->cache->cached('userblogoptions'.$user->id)) {
Línea 5757... Línea 5928...
5757
            }
5928
            }
5758
        }
5929
        }
Línea 5759... Línea 5930...
5759
 
5930
 
5760
        // Questions
5931
        // Questions
-
 
5932
        require_once($CFG->libdir . '/questionlib.php');
5761
        require_once($CFG->libdir . '/questionlib.php');
5933
        $baseurl = \core_question\local\bank\question_bank_helper::get_url_for_qbank_list($course->id);
Línea 5762... Línea 5934...
5762
        question_extend_settings_navigation($frontpage, $coursecontext)->trim_if_empty();
5934
        question_extend_settings_navigation($frontpage, $coursecontext, $baseurl)->trim_if_empty();
5763
 
5935
 
5764
        // Manage files
5936
        // Manage files
5765
        if ($adminoptions->files) {
5937
        if ($adminoptions->files) {
Línea 5995... Línea 6167...
5995
        }
6167
        }
5996
    }
6168
    }
5997
}
6169
}
Línea 5998... Línea 6170...
5998
 
6170
 
5999
/**
6171
/**
6000
 * The cache class used by global navigation and settings navigation.
6172
 * The navigation_cache class is used for global and settings navigation data.
6001
 *
6173
 *
6002
 * It is basically an easy access point to session with a bit of smarts to make
-
 
6003
 * sure that the information that is cached is valid still.
6174
 * It provides an easy access to the session cache with TTL of 1800 seconds.
6004
 *
6175
 *
6005
 * Example use:
6176
 * Example use:
6006
 * <code php>
6177
 * <code php>
6007
 * if (!$cache->viewdiscussion()) {
6178
 * if (!$cache->viewdiscussion()) {
Línea 6015... Línea 6186...
6015
 * @category  navigation
6186
 * @category  navigation
6016
 * @copyright 2009 Sam Hemelryk
6187
 * @copyright 2009 Sam Hemelryk
6017
 * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
6188
 * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
6018
 */
6189
 */
6019
class navigation_cache {
6190
class navigation_cache {
6020
    /** @var int represents the time created */
6191
    /** @var cache_session The session cache instance */
6021
    protected $creation;
6192
    protected $cache;
6022
    /** @var array An array of session keys */
6193
    /** @var array The current cache area data */
6023
    protected $session;
6194
    protected $session = [];
-
 
6195
 
6024
    /**
6196
    /**
6025
     * The string to use to segregate this particular cache. It can either be
6197
     * @var string A unique string to segregate this particular cache.
6026
     * unique to start a fresh cache or if you want to share a cache then make
6198
     * It can either be unique to start a fresh cache or shared to use an existing cache.
6027
     * it the string used in the original cache.
-
 
6028
     * @var string
-
 
6029
     */
6199
     */
6030
    protected $area;
6200
    protected $area;
6031
    /** @var int a time that the information will time out */
-
 
6032
    protected $timeout;
-
 
6033
    /** @var stdClass The current context */
-
 
6034
    protected $currentcontext;
-
 
6035
    /** @var int cache time information */
6201
    /** @var int cache time information */
-
 
6202
    #[\core\attribute\deprecated(null, since: '4.5', reason: 'This constant is no longer needed.', mdl: 'MDL-79628')]
6036
    const CACHETIME = 0;
6203
    const CACHETIME = 0;
6037
    /** @var int cache user id */
6204
    /** @var int cache user id */
-
 
6205
    #[\core\attribute\deprecated(null, since: '4.5', reason: 'This constant is no longer needed.', mdl: 'MDL-79628')]
6038
    const CACHEUSERID = 1;
6206
    const CACHEUSERID = 1;
6039
    /** @var int cache value */
6207
    /** @var int cache value */
6040
    const CACHEVALUE = 2;
6208
    const CACHEVALUE = 2;
6041
    /** @var null|array An array of navigation cache areas to expire on shutdown */
6209
    /** @var null|array An array of cache areas to expire on shutdown */
6042
    public static $volatilecaches;
6210
    public static $volatilecaches = null;
Línea 6043... Línea 6211...
6043
 
6211
 
6044
    /**
6212
    /**
6045
     * Contructor for the cache. Requires two arguments
6213
     * Contructor for the cache. Requires a area string be passed in.
6046
     *
6214
     *
6047
     * @param string $area The string to use to segregate this particular cache
-
 
6048
     *                it can either be unique to start a fresh cache or if you want
-
 
6049
     *                to share a cache then make it the string used in the original
-
 
6050
     *                cache
6215
     * @param string $area The unique string to segregate this particular cache.
6051
     * @param int $timeout The number of seconds to time the information out after
6216
     * @param int $timeout Deprecated since Moodle 4.5. The number of seconds to time the information out after
6052
     */
6217
     */
6053
    public function __construct($area, $timeout=1800) {
6218
    public function __construct($area, $timeout = null) {
6054
        $this->creation = time();
6219
        if ($timeout !== null) {
6055
        $this->area = $area;
6220
            debugging(
6056
        $this->timeout = time() - $timeout;
6221
                'The timeout argument has been deprecated. Please remove it from your method calls.',
6057
        if (rand(0,100) === 0) {
6222
                DEBUG_DEVELOPER,
6058
            $this->garbage_collection();
6223
            );
-
 
6224
        }
-
 
6225
        global $USER;
-
 
6226
        $this->area = "user_{$USER->id}_{$area}";
6059
        }
6227
        $this->cache = cache::make('core', 'navigation_cache');
Línea 6060... Línea 6228...
6060
    }
6228
    }
6061
 
6229
 
6062
    /**
6230
    /**
6063
     * Used to set up the cache within the SESSION.
6231
     * Ensure the navigation cache is initialised
6064
     *
-
 
6065
     * This is called for each access and ensure that we don't put anything into the session before
6232
     *
6066
     * it is required.
6233
     * This is called for each access and ensures that no data is put into the cache before it is required.
6067
     */
-
 
6068
    protected function ensure_session_cache_initialised() {
6234
     */
-
 
6235
    protected function ensure_navigation_cache_initialised() {
6069
        global $SESSION;
6236
        if (empty($this->session)) {
6070
        if (empty($this->session)) {
6237
            $this->session = $this->cache->get($this->area);
6071
            if (!isset($SESSION->navcache)) {
6238
            if (!is_array($this->session)) {
6072
                $SESSION->navcache = new stdClass;
-
 
6073
            }
-
 
6074
            if (!isset($SESSION->navcache->{$this->area})) {
-
 
6075
                $SESSION->navcache->{$this->area} = array();
-
 
6076
            }
6239
                $this->session = [];
6077
            $this->session = &$SESSION->navcache->{$this->area}; // pointer to array, =& is correct here
6240
            }
Línea 6078... Línea 6241...
6078
        }
6241
        }
6079
    }
6242
    }
6080
 
6243
 
6081
    /**
6244
    /**
6082
     * Magic Method to retrieve something by simply calling using = cache->key
6245
     * Magic Method to retrieve a cached item by simply calling using = cache->key
6083
     *
6246
     *
6084
     * @param mixed $key The identifier for the information you want out again
6247
     * @param mixed $key The identifier for the cached information
6085
     * @return void|mixed Either void or what ever was put in
6248
     * @return mixed|void The cached information or void if not found
6086
     */
6249
     */
6087
    public function __get($key) {
6250
    public function __get($key) {
6088
        if (!$this->cached($key)) {
6251
        if (!$this->cached($key)) {
6089
            return;
-
 
6090
        }
6252
            return;
Línea 6091... Línea 6253...
6091
        $information = $this->session[$key][self::CACHEVALUE];
6253
        }
6092
        return unserialize($information);
6254
        return unserialize($this->session[$key][self::CACHEVALUE]);
6093
    }
6255
    }
6094
 
6256
 
6095
    /**
6257
    /**
6096
     * Magic method that simply uses {@link set();} to store something in the cache
6258
     * Magic method that simply uses {@see navigation_cache::set()} to store an item in the cache
6097
     *
6259
     *
6098
     * @param string|int $key
6260
     * @param string|int $key The key to store the information against
6099
     * @param mixed $information
6261
     * @param mixed $information The information to cache
Línea 6100... Línea 6262...
6100
     */
6262
     */
6101
    public function __set($key, $information) {
6263
    public function __set($key, $information) {
6102
        $this->set($key, $information);
6264
        $this->set($key, $information);
6103
    }
6265
    }
6104
 
6266
 
6105
    /**
6267
    /**
6106
     * Sets some information against the cache (session) for later retrieval
6268
     * Sets some information in the session cache for later retrieval
6107
     *
-
 
6108
     * @param string|int $key
6269
     *
6109
     * @param mixed $information
6270
     * @param string|int $key
6110
     */
6271
     * @param mixed $information
-
 
6272
     */
6111
    public function set($key, $information) {
6273
    public function set($key, $information) {
6112
        global $USER;
6274
        $this->ensure_navigation_cache_initialised();
6113
        $this->ensure_session_cache_initialised();
6275
        $information = serialize($information);
6114
        $information = serialize($information);
6276
        $this->session[$key] = [self::CACHEVALUE => $information];
6115
        $this->session[$key]= array(self::CACHETIME=>time(), self::CACHEUSERID=>$USER->id, self::CACHEVALUE=>$information);
6277
        $this->cache->set($this->area, $this->session);
6116
    }
6278
    }
6117
    /**
6279
    /**
6118
     * Check the existence of the identifier in the cache
6280
     * Check the existence of the identifier in the cache
6119
     *
-
 
6120
     * @param string|int $key
6281
     *
6121
     * @return bool
-
 
6122
     */
6282
     * @param string|int $key The identifier to check
6123
    public function cached($key) {
-
 
6124
        global $USER;
6283
     * @return bool True if the item exists in the cache, false otherwise
6125
        $this->ensure_session_cache_initialised();
6284
     */
6126
        if (!array_key_exists($key, $this->session) || !is_array($this->session[$key]) || $this->session[$key][self::CACHEUSERID]!=$USER->id || $this->session[$key][self::CACHETIME] < $this->timeout) {
6285
    public function cached($key) {
6127
            return false;
6286
        $this->ensure_navigation_cache_initialised();
6128
        }
6287
        return isset($this->session[$key]) &&
6129
        return true;
6288
            is_array($this->session[$key]);
6130
    }
6289
    }
6131
    /**
6290
    /**
6132
     * Compare something to it's equivilant in the cache
6291
     * Compare something to it's equivilant in the cache
6133
     *
6292
     *
6134
     * @param string $key
6293
     * @param string $key  The key to check
6135
     * @param mixed $value
6294
     * @param mixed $value The value to compare
6136
     * @param bool $serialise Whether to serialise the value before comparison
6295
     * @param bool $serialise Whether to serialise the value before comparison
6137
     *              this should only be set to false if the value is already
6296
     *              this should only be set to false if the value is already
6138
     *              serialised
6297
     *              serialised
6139
     * @return bool If the value is the same false if it is not set or doesn't match
6298
     * @return bool True if the value is the same as the cached one, false otherwise
6140
     */
6299
     */
6141
    public function compare($key, $value, $serialise = true) {
6300
    public function compare($key, $value, $serialise = true) {
6142
        if ($this->cached($key)) {
-
 
6143
            if ($serialise) {
-
 
6144
                $value = serialize($value);
6301
        if ($this->cached($key)) {
6145
            }
6302
            if ($serialise) {
6146
            if ($this->session[$key][self::CACHEVALUE] === $value) {
6303
                $value = serialize($value);
6147
                return true;
6304
            }
6148
            }
6305
            return $this->session[$key][self::CACHEVALUE] === $value;
6149
        }
6306
        }
6150
        return false;
6307
        return false;
6151
    }
-
 
6152
    /**
6308
    }
6153
     * Wipes the entire cache, good to force regeneration
6309
    /**
6154
     */
6310
     * Deletes the entire cache area, forcing a fresh cache to be created
6155
    public function clear() {
6311
     */
6156
        global $SESSION;
-
 
6157
        unset($SESSION->navcache);
-
 
6158
        $this->session = null;
-
 
6159
    }
-
 
6160
    /**
-
 
6161
     * Checks all cache entries and removes any that have expired, good ole cleanup
-
 
6162
     */
-
 
6163
    protected function garbage_collection() {
-
 
6164
        if (empty($this->session)) {
-
 
6165
            return true;
-
 
6166
        }
-
 
6167
        foreach ($this->session as $key=>$cachedinfo) {
-
 
6168
            if (is_array($cachedinfo) && $cachedinfo[self::CACHETIME]<$this->timeout) {
-
 
6169
                unset($this->session[$key]);
-
 
6170
            }
6312
    public function clear() {
6171
        }
6313
        $this->cache->delete($this->area);
6172
    }
6314
        $this->session = [];
6173
 
-
 
6174
    /**
-
 
6175
     * Marks the cache as being volatile (likely to change)
6315
    }
6176
     *
6316
    /**
6177
     * Any caches marked as volatile will be destroyed at the on shutdown by
6317
     * Marks the cache as volatile (likely to change)
6178
     * {@link navigation_node::destroy_volatile_caches()} which is registered
6318
     *
6179
     * as a shutdown function if any caches are marked as volatile.
6319
     * Any caches marked as volatile will be destroyed on shutdown by {@see navigation_node::destroy_volatile_caches()}
6180
     *
6320
     *
6181
     * @param bool $setting True to destroy the cache false not too
6321
     * @param bool $setting True to mark the cache as volatile, false to remove the volatile flag
6182
     */
6322
     */
Línea 6183... Línea 6323...
6183
    public function volatile($setting = true) {
6323
    public function volatile($setting = true) {
6184
        if (self::$volatilecaches===null) {
6324
        if (self::$volatilecaches === null) {
6185
            self::$volatilecaches = array();
6325
            self::$volatilecaches = [];
Línea 6194... Línea 6334...
6194
    }
6334
    }
Línea 6195... Línea 6335...
6195
 
6335
 
6196
    /**
6336
    /**
6197
     * Destroys all caches marked as volatile
6337
     * Destroys all caches marked as volatile
6198
     *
6338
     *
6199
     * This function is static and works in conjunction with the static volatilecaches
-
 
6200
     * property of navigation cache.
6339
     * This function is static and works with the static volatilecaches property of navigation cache.
6201
     * Because this function is static it manually resets the cached areas back to an
-
 
6202
     * empty array.
6340
     * It manually resets the cached areas back to an empty array.
6203
     */
6341
     */
6204
    public static function destroy_volatile_caches() {
-
 
6205
        global $SESSION;
6342
    public static function destroy_volatile_caches() {
-
 
6343
        if (is_array(self::$volatilecaches) && count(self::$volatilecaches) > 0) {
6206
        if (is_array(self::$volatilecaches) && count(self::$volatilecaches)>0) {
6344
            $cache = cache::make('core', 'navigation_cache');
6207
            foreach (self::$volatilecaches as $area) {
6345
            foreach (self::$volatilecaches as $area) {
6208
                $SESSION->navcache->{$area} = array();
6346
                $cache->delete($area);
6209
            }
-
 
6210
        } else {
6347
            }
6211
            $SESSION->navcache = new stdClass;
6348
            self::$volatilecaches = null;
6212
        }
6349
        }
6213
    }
6350
    }