Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
<?php
2
// This file is part of Moodle - http://moodle.org/
3
//
4
// Moodle is free software: you can redistribute it and/or modify
5
// it under the terms of the GNU General Public License as published by
6
// the Free Software Foundation, either version 3 of the License, or
7
// (at your option) any later version.
8
//
9
// Moodle is distributed in the hope that it will be useful,
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
// GNU General Public License for more details.
13
//
14
// You should have received a copy of the GNU General Public License
15
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
16
 
17
/**
18
 * This file contains the cache factory class.
19
 *
20
 * This file is part of Moodle's cache API, affectionately called MUC.
21
 * It contains the components that are requried in order to use caching.
22
 *
23
 * @package    core
24
 * @category   cache
25
 * @copyright  2012 Sam Hemelryk
26
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
27
 */
28
 
29
defined('MOODLE_INTERNAL') || die();
30
 
31
/**
32
 * The cache factory class.
33
 *
34
 * This factory class is important because it stores instances of objects used by the cache API and returns them upon requests.
35
 * This allows us to both reuse objects saving on overhead, and gives us an easy place to "reset" the cache API in situations that
36
 * we need such as unit testing.
37
 *
38
 * @copyright  2012 Sam Hemelryk
39
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
40
 */
41
class cache_factory {
42
 
43
    /** The cache has not been initialised yet. */
44
    const STATE_UNINITIALISED = 0;
45
    /** The cache is in the process of initialising itself. */
46
    const STATE_INITIALISING = 1;
47
    /** The cache is in the process of saving its configuration file. */
48
    const STATE_SAVING = 2;
49
    /** The cache is ready to use. */
50
    const STATE_READY = 3;
51
    /** The cache is currently updating itself */
52
    const STATE_UPDATING = 4;
53
    /** The cache encountered an error while initialising. */
54
    const STATE_ERROR_INITIALISING = 9;
55
    /** The cache has been disabled. */
56
    const STATE_DISABLED = 10;
57
    /** The cache stores have been disabled */
58
    const STATE_STORES_DISABLED = 11;
59
 
60
    /**
61
     * An instance of the cache_factory class created upon the first request.
62
     * @var cache_factory
63
     */
64
    protected static $instance;
65
 
66
    /**
67
     * An array containing caches created for definitions
68
     * @var array
69
     */
70
    protected $cachesfromdefinitions = array();
71
 
72
    /**
73
     * Array of caches created by parameters, ad-hoc definitions will have been used.
74
     * @var array
75
     */
76
    protected $cachesfromparams = array();
77
 
78
    /**
79
     * An array of stores organised by definitions.
80
     * @var array
81
     */
82
    protected $definitionstores = array();
83
 
84
    /**
85
     * An array of instantiated stores.
86
     * @var array
87
     */
88
    protected $stores = array();
89
 
90
    /**
91
     * An array of configuration instances
92
     * @var array
93
     */
94
    protected $configs = array();
95
 
96
    /**
97
     * An array of initialised definitions
98
     * @var array
99
     */
100
    protected $definitions = array();
101
 
102
    /**
103
     * An array of lock plugins.
104
     * @var array
105
     */
106
    protected $lockplugins = array();
107
 
108
    /**
109
     * The current state of the cache API.
110
     * @var int
111
     */
112
    protected $state = 0;
113
 
114
    /**
115
     * The current cache display helper.
116
     * @var core_cache\local\administration_display_helper
117
     */
118
    protected static $displayhelper = null;
119
 
120
    /**
121
     * Returns an instance of the cache_factory class.
122
     *
123
     * @param bool $forcereload If set to true a new cache_factory instance will be created and used.
124
     * @return cache_factory
125
     */
126
    public static function instance($forcereload = false) {
127
        global $CFG;
128
        if ($forcereload || self::$instance === null) {
129
            // Initialise a new factory to facilitate our needs.
130
            if (defined('CACHE_DISABLE_ALL') && CACHE_DISABLE_ALL !== false) {
131
                // The cache has been disabled. Load disabledlib and start using the factory designed to handle this
132
                // situation. It will use disabled alternatives where available.
133
                require_once($CFG->dirroot.'/cache/disabledlib.php');
134
                self::$instance = new cache_factory_disabled();
135
            } else if ((defined('PHPUNIT_TEST') && PHPUNIT_TEST) || defined('BEHAT_SITE_RUNNING')) {
136
                // We're using the test factory.
137
                require_once($CFG->dirroot.'/cache/tests/fixtures/lib.php');
138
                self::$instance = new cache_phpunit_factory();
139
                if (defined('CACHE_DISABLE_STORES') && CACHE_DISABLE_STORES !== false) {
140
                    // The cache stores have been disabled.
141
                    self::$instance->set_state(self::STATE_STORES_DISABLED);
142
                }
143
 
144
            } else if (!empty($CFG->alternative_cache_factory_class)) {
145
                $factoryclass = $CFG->alternative_cache_factory_class;
146
                self::$instance = new $factoryclass();
147
            } else {
148
                // We're using the regular factory.
149
                self::$instance = new cache_factory();
150
                if (defined('CACHE_DISABLE_STORES') && CACHE_DISABLE_STORES !== false) {
151
                    // The cache stores have been disabled.
152
                    self::$instance->set_state(self::STATE_STORES_DISABLED);
153
                }
154
            }
155
        }
156
        return self::$instance;
157
    }
158
 
159
    /**
160
     * Protected constructor, please use the static instance method.
161
     */
162
    protected function __construct() {
163
        // Nothing to do here.
164
    }
165
 
166
    /**
167
     * Resets the arrays containing instantiated caches, stores, and config instances.
168
     */
169
    public static function reset() {
170
        $factory = self::instance();
171
        $factory->reset_cache_instances();
172
        $factory->configs = array();
173
        $factory->definitions = array();
174
        $factory->definitionstores = array();
175
        $factory->lockplugins = array(); // MUST be null in order to force its regeneration.
176
        // Reset the state to uninitialised.
177
        $factory->state = self::STATE_UNINITIALISED;
178
    }
179
 
180
    /**
181
     * Resets the stores, clearing the array of created stores.
182
     *
183
     * Cache objects still held onto by the code that initialised them will remain as is
184
     * however all future requests for a cache/store will lead to a new instance being re-initialised.
185
     */
186
    public function reset_cache_instances() {
187
        $this->cachesfromdefinitions = array();
188
        $this->cachesfromparams = array();
189
        $this->stores = array();
190
    }
191
 
192
    /**
193
     * Creates a cache object given the parameters for a definition.
194
     *
195
     * If a cache has already been created for the given definition then that cache instance will be returned.
196
     *
197
     * @param string $component
198
     * @param string $area
199
     * @param array $identifiers
200
     * @param string $unused Used to be data source aggregate however that was removed and this is now unused.
201
     * @return cache_application|cache_session|cache_request
202
     */
203
    public function create_cache_from_definition($component, $area, array $identifiers = array(), $unused = null) {
204
        $identifierstring = empty($identifiers) ? '' : '/'.http_build_query($identifiers);
205
        $definitionname = $component.'/'.$area.$identifierstring;
206
        if (isset($this->cachesfromdefinitions[$definitionname])) {
207
            $cache = $this->cachesfromdefinitions[$definitionname];
208
            return $cache;
209
        }
210
        $definition = $this->create_definition($component, $area);
211
        // Identifiers are cached as part of the cache creation, so we store a cloned version of the cache.
212
        $cacheddefinition = clone($definition);
213
        $cacheddefinition->set_identifiers($identifiers);
214
        $cache = $this->create_cache($cacheddefinition);
215
 
216
        // Loaders are always held onto to speed up subsequent requests.
217
        $this->cachesfromdefinitions[$definitionname] = $cache;
218
        return $cache;
219
    }
220
 
221
    /**
222
     * Creates an ad-hoc cache from the given param.
223
     *
224
     * If a cache has already been created using the same params then that cache instance will be returned.
225
     *
226
     * @param int $mode
227
     * @param string $component
228
     * @param string $area
229
     * @param array $identifiers
230
     * @param array $options An array of options, available options are:
231
     *   - simplekeys : Set to true if the keys you will use are a-zA-Z0-9_
232
     *   - simpledata : Set to true if the type of the data you are going to store is scalar, or an array of scalar vars
233
     *   - staticacceleration : If set to true the cache will hold onto data passing through it.
234
     *   - staticaccelerationsize : The maximum number of items to hold onto for acceleration purposes.
235
     * @return cache_application|cache_session|cache_request
236
     */
237
    public function create_cache_from_params($mode, $component, $area, array $identifiers = array(), array $options = array()) {
238
        $identifierstring = empty($identifiers) ? '' : '_'.http_build_query($identifiers);
239
        $key = "{$mode}_{$component}_{$area}{$identifierstring}";
240
        if (isset($this->cachesfromparams[$key])) {
241
            return $this->cachesfromparams[$key];
242
        }
243
        // Regular cache definitions are cached inside create_definition().  This is not the case for Adhoc definitions
244
        // using load_adhoc().  They are built as a new object on each call.
245
        // We do not need to clone the definition because we know it's new.
246
        $definition = cache_definition::load_adhoc($mode, $component, $area, $options);
247
        $definition->set_identifiers($identifiers);
248
        $cache = $this->create_cache($definition);
249
        $this->cachesfromparams[$key] = $cache;
250
        return $cache;
251
    }
252
 
253
    /**
254
     * Common public method to create a cache instance given a definition.
255
     *
256
     * This is used by the static make methods.
257
     *
258
     * @param cache_definition $definition
259
     * @return cache_application|cache_session|cache_store
260
     * @throws coding_exception
261
     */
262
    public function create_cache(cache_definition $definition) {
263
        $class = $definition->get_cache_class();
264
        $stores = cache_helper::get_stores_suitable_for_definition($definition);
265
        foreach ($stores as $key => $store) {
266
            if (!$store::are_requirements_met()) {
267
                unset($stores[$key]);
268
            }
269
        }
270
        if (count($stores) === 0) {
271
            // Hmm still no stores, better provide a dummy store to mimic functionality. The dev will be none the wiser.
272
            $stores[] = $this->create_dummy_store($definition);
273
        }
274
        $loader = null;
275
        if ($definition->has_data_source()) {
276
            $loader = $definition->get_data_source();
277
        }
278
        while (($store = array_pop($stores)) !== null) {
279
            $loader = new $class($definition, $store, $loader);
280
        }
281
        return $loader;
282
    }
283
 
284
    /**
285
     * Creates a store instance given its name and configuration.
286
     *
287
     * If the store has already been instantiated then the original object will be returned. (reused)
288
     *
289
     * @param string $name The name of the store (must be unique remember)
290
     * @param array $details
291
     * @param cache_definition $definition The definition to instantiate it for.
292
     * @return boolean|cache_store
293
     */
294
    public function create_store_from_config($name, array $details, cache_definition $definition) {
295
        if (!array_key_exists($name, $this->stores)) {
296
            // Properties: name, plugin, configuration, class.
297
            $class = $details['class'];
298
            if (!$class::are_requirements_met()) {
299
                return false;
300
            }
301
            $store = new $class($details['name'], $details['configuration']);
302
            $this->stores[$name] = $store;
303
        }
304
        /* @var cache_store $store */
305
        $store = $this->stores[$name];
306
        // We check are_requirements_met although we expect is_ready is going to check as well.
307
        if (!$store::are_requirements_met() || !$store->is_ready() || !$store->is_supported_mode($definition->get_mode())) {
308
            return false;
309
        }
310
        // We always create a clone of the original store.
311
        // If we were to clone a store that had already been initialised with a definition then
312
        // we'd run into a myriad of issues.
313
        // We use a method of the store to create a clone rather than just creating it ourselves
314
        // so that if any store out there doesn't handle cloning they can override this method in
315
        // order to address the issues.
316
        $store = $this->stores[$name]->create_clone($details);
317
        $store->initialise($definition);
318
        $definitionid = $definition->get_id();
319
        if (!isset($this->definitionstores[$definitionid])) {
320
            $this->definitionstores[$definitionid] = array();
321
        }
322
        $this->definitionstores[$definitionid][] = $store;
323
        return $store;
324
    }
325
 
326
    /**
327
     * Returns an array of cache stores that have been initialised for use in definitions.
328
     * @param cache_definition $definition
329
     * @return array
330
     */
331
    public function get_store_instances_in_use(cache_definition $definition) {
332
        $id = $definition->get_id();
333
        if (!isset($this->definitionstores[$id])) {
334
            return array();
335
        }
336
        return $this->definitionstores[$id];
337
    }
338
 
339
    /**
340
     * Returns the cache instances that have been used within this request.
341
     * @since Moodle 2.6
342
     * @return array
343
     */
344
    public function get_caches_in_use() {
345
        return $this->cachesfromdefinitions;
346
    }
347
 
348
    /**
349
     * Gets all adhoc caches that have been used within this request.
350
     *
351
     * @return cache_store[] Caches currently in use
352
     */
353
    public function get_adhoc_caches_in_use() {
354
        return $this->cachesfromparams;
355
    }
356
 
357
    /**
358
     * Creates a cache config instance with the ability to write if required.
359
     *
360
     * @param bool $writer If set to true an instance that can update the configuration will be returned.
361
     * @return cache_config|cache_config_writer
362
     */
363
    public function create_config_instance($writer = false) {
364
        global $CFG;
365
 
366
        // The class to use.
367
        $class = 'cache_config';
368
        // Are we running tests of some form?
369
        $testing = (defined('PHPUNIT_TEST') && PHPUNIT_TEST) || defined('BEHAT_SITE_RUNNING');
370
 
371
        // Check if this is a PHPUnit test and redirect to the phpunit config classes if it is.
372
        if ($testing) {
373
            require_once($CFG->dirroot.'/cache/locallib.php');
374
            require_once($CFG->dirroot.'/cache/tests/fixtures/lib.php');
375
            // We have just a single class for PHP unit tests. We don't care enough about its
376
            // performance to do otherwise and having a single method allows us to inject things into it
377
            // while testing.
378
            $class = 'cache_config_testing';
379
        }
380
 
381
        // Check if we need to create a config file with defaults.
382
        $needtocreate = !$class::config_file_exists();
383
 
384
        if ($writer || $needtocreate) {
385
            require_once($CFG->dirroot.'/cache/locallib.php');
386
            if (!$testing) {
387
                $class .= '_writer';
388
            }
389
        }
390
 
391
        $error = false;
392
        if ($needtocreate) {
393
            // Create the default configuration.
394
            // Update the state, we are now initialising the cache.
395
            self::set_state(self::STATE_INITIALISING);
396
            /** @var cache_config_writer $class */
397
            $configuration = $class::create_default_configuration();
398
            if ($configuration !== true) {
399
                // Failed to create the default configuration. Disable the cache stores and update the state.
400
                self::set_state(self::STATE_ERROR_INITIALISING);
401
                $this->configs[$class] = new $class;
402
                $this->configs[$class]->load($configuration);
403
                $error = true;
404
            }
405
        }
406
 
407
        if (!array_key_exists($class, $this->configs)) {
408
            // Create a new instance and call it to load it.
409
            $this->configs[$class] = new $class;
410
            $this->configs[$class]->load();
411
        }
412
 
413
        if (!$error) {
414
            // The cache is now ready to use. Update the state.
415
            self::set_state(self::STATE_READY);
416
        }
417
 
418
        // Return the instance.
419
        return $this->configs[$class];
420
    }
421
 
422
    /**
423
     * Creates a definition instance or returns the existing one if it has already been created.
424
     * @param string $component
425
     * @param string $area
426
     * @param string $unused This used to be data source aggregate - however that functionality has been removed and
427
     *        this argument is now unused.
428
     * @return cache_definition
429
     * @throws coding_exception If the definition cannot be found.
430
     */
431
    public function create_definition($component, $area, $unused = null) {
432
        $id = $component.'/'.$area;
433
        if (!isset($this->definitions[$id])) {
434
            // This is the first time this definition has been requested.
435
            if ($this->is_initialising()) {
436
                // We're initialising the cache right now. Don't try to create another config instance.
437
                // We'll just use an ad-hoc cache for the time being.
438
                $definition = cache_definition::load_adhoc(cache_store::MODE_REQUEST, $component, $area);
439
            } else {
440
                // Load all the known definitions and find the desired one.
441
                $instance = $this->create_config_instance();
442
                $definition = $instance->get_definition_by_id($id);
443
                if (!$definition) {
444
                    // Oh-oh the definition doesn't exist.
445
                    // There are several things that could be going on here.
446
                    // We may be installing/upgrading a site and have hit a definition that hasn't been used before.
447
                    // Of the developer may be trying to use a newly created definition.
448
                    if ($this->is_updating()) {
449
                        // The cache is presently initialising and the requested cache definition has not been found.
450
                        // This means that the cache initialisation has requested something from a cache (I had recursive nightmares about this).
451
                        // To serve this purpose and avoid errors we are going to make use of an ad-hoc cache rather than
452
                        // search for the definition which would possibly cause an infitite loop trying to initialise the cache.
453
                        $definition = cache_definition::load_adhoc(cache_store::MODE_REQUEST, $component, $area);
454
                    } else {
455
                        // Either a typo of the developer has just created the definition and is using it for the first time.
456
                        $this->reset();
457
                        $instance = $this->create_config_instance(true);
458
                        $instance->update_definitions();
459
                        $definition = $instance->get_definition_by_id($id);
460
                        if (!$definition) {
461
                            throw new coding_exception('The requested cache definition does not exist.'. $id, $id);
462
                        }
463
                        if (!$this->is_disabled()) {
464
                            debugging('Cache definitions reparsed causing cache reset in order to locate definition.
465
                                You should bump the version number to ensure definitions are reprocessed.', DEBUG_DEVELOPER);
466
                        }
467
                        $definition = cache_definition::load($id, $definition);
468
                    }
469
                } else {
470
                    $definition = cache_definition::load($id, $definition);
471
                }
472
            }
473
            $this->definitions[$id] = $definition;
474
        }
475
        return $this->definitions[$id];
476
    }
477
 
478
    /**
479
     * Creates a dummy store object for use when a loader has no potential stores to use.
480
     *
481
     * @param cache_definition $definition
482
     * @return cachestore_dummy
483
     */
484
    protected function create_dummy_store(cache_definition $definition) {
485
        global $CFG;
486
        require_once($CFG->dirroot.'/cache/classes/dummystore.php');
487
        $store = new cachestore_dummy();
488
        $store->initialise($definition);
489
        return $store;
490
    }
491
 
492
    /**
493
     * Returns a lock instance ready for use.
494
     *
495
     * @param array $config
496
     * @return cache_lock_interface
497
     */
498
    public function create_lock_instance(array $config) {
499
        global $CFG;
500
        if (!array_key_exists('name', $config) || !array_key_exists('type', $config)) {
501
            throw new coding_exception('Invalid cache lock instance provided');
502
        }
503
        $name = $config['name'];
504
        $type = $config['type'];
505
        unset($config['name']);
506
        unset($config['type']);
507
 
508
        if (!isset($this->lockplugins[$type])) {
509
            $pluginname = substr($type, 10);
510
            $file = $CFG->dirroot."/cache/locks/{$pluginname}/lib.php";
511
            if (file_exists($file) && is_readable($file)) {
512
                require_once($file);
513
            }
514
            if (!class_exists($type)) {
515
                throw new coding_exception('Invalid lock plugin requested.');
516
            }
517
            $this->lockplugins[$type] = $type;
518
        }
519
        if (!array_key_exists($type, $this->lockplugins)) {
520
            throw new coding_exception('Invalid cache lock type.');
521
        }
522
        $class = $this->lockplugins[$type];
523
        return new $class($name, $config);
524
    }
525
 
526
    /**
527
     * Returns the current state of the cache API.
528
     *
529
     * @return int
530
     */
531
    public function get_state() {
532
        return $this->state;
533
    }
534
 
535
    /**
536
     * Updates the state fo the cache API.
537
     *
538
     * @param int $state
539
     * @return bool
540
     */
541
    public function set_state($state) {
542
        if ($state <= $this->state) {
543
            return false;
544
        }
545
        $this->state = $state;
546
        return true;
547
    }
548
 
549
    /**
550
     * Informs the factory that the cache is currently updating itself.
551
     *
552
     * This forces the state to upgrading and can only be called once the cache is ready to use.
553
     * Calling it ensure we don't try to reinstantite things when requesting cache definitions that don't exist yet.
554
     */
555
    public function updating_started() {
556
        if ($this->state !== self::STATE_READY) {
557
            return false;
558
        }
559
        $this->state = self::STATE_UPDATING;
560
        return true;
561
    }
562
 
563
    /**
564
     * Informs the factory that the upgrading has finished.
565
     *
566
     * This forces the state back to ready.
567
     */
568
    public function updating_finished() {
569
        $this->state = self::STATE_READY;
570
    }
571
 
572
    /**
573
     * Returns true if the cache API has been disabled.
574
     *
575
     * @return bool
576
     */
577
    public function is_disabled() {
578
        return $this->state === self::STATE_DISABLED;
579
    }
580
 
581
    /**
582
     * Returns true if the cache is currently initialising itself.
583
     *
584
     * This includes both initialisation and saving the cache config file as part of that initialisation.
585
     *
586
     * @return bool
587
     */
588
    public function is_initialising() {
589
        return $this->state === self::STATE_INITIALISING || $this->state === self::STATE_SAVING;
590
    }
591
 
592
    /**
593
     * Returns true if the cache is currently updating itself.
594
     *
595
     * @return bool
596
     */
597
    public function is_updating() {
598
        return $this->state === self::STATE_UPDATING;
599
    }
600
 
601
    /**
602
     * Disables as much of the cache API as possible.
603
     *
604
     * All of the magic associated with the disabled cache is wrapped into this function.
605
     * In switching out the factory for the disabled factory it gains full control over the initialisation of objects
606
     * and can use all of the disabled alternatives.
607
     * Simple!
608
     *
609
     * This function has been marked as protected so that it cannot be abused through the public API presently.
610
     * Perhaps in the future we will allow this, however as per the build up to the first release containing
611
     * MUC it was decided that this was just to risky and abusable.
612
     */
613
    protected static function disable() {
614
        global $CFG;
615
        require_once($CFG->dirroot.'/cache/disabledlib.php');
616
        self::$instance = new cache_factory_disabled();
617
    }
618
 
619
    /**
620
     * Returns true if the cache stores have been disabled.
621
     *
622
     * @return bool
623
     */
624
    public function stores_disabled() {
625
        return $this->state === self::STATE_STORES_DISABLED || $this->is_disabled();
626
    }
627
 
628
    /**
629
     * Disables cache stores.
630
     *
631
     * The cache API will continue to function however none of the actual stores will be used.
632
     * Instead the dummy store will be provided for all cache requests.
633
     * This is useful in situations where you cannot be sure any stores are working.
634
     *
635
     * In order to re-enable the cache you must call the cache factories static reset method:
636
     * <code>
637
     * // Disable the cache factory.
638
     * cache_factory::disable_stores();
639
     * // Re-enable the cache factory by resetting it.
640
     * cache_factory::reset();
641
     * </code>
642
     */
643
    public static function disable_stores() {
644
        // First reset to clear any static acceleration array.
645
        $factory = self::instance();
646
        $factory->reset_cache_instances();
647
        $factory->set_state(self::STATE_STORES_DISABLED);
648
    }
649
 
650
    /**
651
     * Returns an instance of the current display_helper.
652
     *
653
     * @return core_cache\administration_helper
654
     */
655
    public static function get_administration_display_helper(): core_cache\administration_helper {
656
        if (is_null(self::$displayhelper)) {
657
            self::$displayhelper = new \core_cache\local\administration_display_helper();
658
        }
659
        return self::$displayhelper;
660
    }
661
 
662
    /**
663
     * Gets the cache_config_writer to use when caching is disabled.
664
     * This should only be called from cache_factory_disabled.
665
     *
666
     * @return cache_config_writer
667
     */
668
    public static function get_disabled_writer(): cache_config_writer {
669
        global $CFG;
670
 
671
        // Figure out if we are in a recursive loop using late static binding.
672
        // This happens when get_disabled_writer is not overridden. We just want the default.
673
        $loop = false;
674
        if (!empty($CFG->alternative_cache_factory_class)) {
675
            $loop = get_called_class() === $CFG->alternative_cache_factory_class;
676
        }
677
 
678
        if (!$loop && !empty($CFG->alternative_cache_factory_class)) {
679
            // Get the class to use from the alternative factory.
680
            $factoryinstance = new $CFG->alternative_cache_factory_class();
681
            return $factoryinstance::get_disabled_writer();
682
        } else {
683
            // We got here from cache_factory_disabled.
684
            // We should use the default writer here.
685
            // Make sure we have a default config if needed.
686
            if (!cache_config::config_file_exists()) {
687
                cache_config_writer::create_default_configuration(true);
688
            }
689
 
690
            return new cache_config_writer();
691
        }
692
    }
693
}