Passed
Branch master (05c266)
by Andreas
09:55
created

midcom_config::_complete_defaults()   A

Complexity

Conditions 4
Paths 8

Size

Total Lines 11
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 4.0312

Importance

Changes 0
Metric Value
cc 4
eloc 7
nc 8
nop 0
dl 0
loc 11
ccs 7
cts 8
cp 0.875
crap 4.0312
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * @package midcom
4
 * @author CONTENT CONTROL http://www.contentcontrol-berlin.de/
5
 * @copyright CONTENT CONTROL http://www.contentcontrol-berlin.de/
6
 * @license http://www.gnu.org/licenses/gpl.html GNU General Public License
7
 */
8
9
use Symfony\Component\DependencyInjection\ContainerBuilder;
10
11
/**
12
 * Core configuration defaults.
13
 *
14
 * As always, you must not change this file. Instead, you have two levels of customization,
15
 * merged in the order listed here:
16
 *
17
 * <b>Site-specific configuration:</b>
18
 *
19
 * MidCOM will include the file <i>midcom::get()->config->get('midcom_config_basedir') . /midcom.conf</i> which must be a regular
20
 * PHP file. You may populate the global array $midcom_config_site in this file. It should
21
 * list all options that apply to all installations (like the Cache backend selection
22
 * or the indexer host).
23
 *
24
 * Example:
25
 *
26
 * <code>
27
 * $GLOBALS['midcom_config_site']['cache_module_content_backend'] =
28
 *     ['directory' => 'content/', 'driver' => 'sqlite'];
29
 * </code>
30
 *
31
 * <b>Instance-specific configuration:</b>
32
 *
33
 * After including the site itself, MidCOM also merges the contents of the global array
34
 * $midcom_config_local, which may hold configuration data for the website itself.
35
 *
36
 * These settings must be set for all sites:
37
 * - midcom_root_topic_guid
38
 *
39
 * You will usually include these lines somewhere before actually including MidCOM.
40
 *
41
 * <code>
42
 * $GLOBALS['midcom_config_local']['midcom_root_topic_guid'] = '123456789...';
43
 * </code>
44
 *
45
 * <b>Configuration setting overview:</b>
46
 *
47
 * The following configuration options are available for the MidCOM core along
48
 * with their defaults, shown in alphabetical order:
49
 *
50
 * <b>Authentication configuration</b>
51
 *
52
 * - <b>boolean allow_sudo:</b> Set this to true (the default) to allow components to
53
 *   request super user privileges for certain operations. This is mainly used to allow
54
 *   anonymous access to the system without having to store a user account everywhere.
55
 * - <b>string auth_backend:</b> The authentication backend to use, the "simple"
56
 *   backend is used as a default.
57
 * - <b>boolean auth_check_client_ip:</b> Control whether to check the client IP address
58
 *   on each subsequent request when authentication a user. This is enabled by default
59
 *   as it will make session hijacking much harder. You should not turn it off unless
60
 *   you have very good reasons to do.
61
 * - <b>int auth_login_session_timeout:</b> The login session timeout to use, this
62
 *   defaults to 3600 seconds (1 hour). Use 0 to have the session stay active until manual logout
63
 * - <b>string auth_frontend:</b> The authentication frontend to use, the "form" frontend
64
 *   is used by default.
65
 * - <b>int auth_login_form_httpcode</b>: HTTP return code used in MidCOM login screens,
66
 *   either 403 (403 Forbidden) or 200 (200 OK), defaulting to 403.
67
 *
68
 * <b>Authentication Backend configuration: "simple"</b>
69
 *
70
 * - <b>auth_backend_simple_cookie_secure:</b> Set the "secure" flag on cookie, defaults to true, applies only when actually using SSL/TLS
71
 * - <b>auth_backend_simple_cookie_id:</b> The ID appended to the cookie prefix, separating
72
 *   auth cookies for different sites. Defaults to 1.
73
 * - <b>auth_failure_callback:</b> value acceptable by call_user_func() (array or string), callback
74
 *   function/method to be called on failed login, it must take exactly one argument which is the username as string.
75
 * - <b>auth_success_callback:</b> value acceptable by call_user_func() (array or string), callback
76
 *   function/method to be called on successful login, no values are passed.
77
 *
78
 * <b>Cache configuration</b>
79
 *
80
 * - <b>array cache_autoload_queue:</b> The cache module loading queue during startup, you
81
 *   should normally have no need to change this (unless you want to add your own caching modules,
82
 *   in which case you have to ensure that the loading queue of MidCOM itself (as seen in this
83
 *   file) is not changed.
84
 * - <b>string cache_base_directory:</b> The directory where to place cache files for MidCOM.
85
 *      This defaults to {project_dir}/var/cache
86
 *
87
 * - <b>Array cache_module_content_backend:</b> The configuration of the content cache backend.
88
 *   Check the documentation of midcom_services_cache_backend of what options are available here.
89
 *   In general, you should use this only to change the backend driver.
90
 *   In all other cases you should leave this option untouched. The defaults are to store all
91
 *   cache databases into the 'content/' subdirectory of the cache base directory.
92
 * - <b>boolean cache_module_content_uncached:</b> Set this to true if you want the site to run in an uncached
93
 *      mode. This is different from cache_disable in that the regular header preprocessing is
94
 *   done anyway, allowing for browser side caching. Essentially, the computing order is the
95
 *   same (no_cache for example is considered like usual), but the cache file is not stored.
96
 *   This defaults to false.
97
 * - <b>string cache_module_content_headers_strategy:</b> Valid values are<br/>
98
 *   'no-cache' activates no-cache mode that actively tries to circumvent all caching<br/>
99
 *   'revalidate' is the default which sets 'must-revalidate'. Expires defaults to the current time, so this behaves like 'no-cache' unless expires() is called<br/>
100
 *   'public' and 'private' enable caching with the cache-control header of the same name, default expiry timestamps are generated using the cache_module_content_default_lifetime
101
 * - <b>int cache_module_content_default_lifetime:</b> How many seconds from now to set the default Expires header to, defaults to 15 minutes. Also used as default expiry time for content-cache entries that have no expiry set.
102
 * - <b>string cache_module_content_headers_strategy_authenticated:</b> Defaults to 'private', this is equivalent to cache_module_content_headers_strategy but applies when we have authenticated user.
103
 * - <b>int cache_module_content_default_lifetime_authenticated:</b> defaults to 0, equivalent to cache_module_content_default_lifetime but applies to authenticated users (except this does not set content-cache expiry). These two options are added to combat braindead proxies.
104
 * - <b>string cache_module_content_caching_strategy:</b> Valid values are<br/>
105
 *   'user' the "classic" mode, per user content-cache, default<br/>
106
 *   'memberships' cache per group memberships (users that have same memberships share same cache), for many cases this should offer more performance and smaller cache but if you use per-user privileges or other user specific processing this will cause hard-to-debug issues<br/>
107
 *   'public' everything goes to single public cache, disabling logins altogether will likely be safer.
108
 * - <b>string cache_module_memcache_backend:</b> The cache backend to use for the memcache caching
109
 *   module. The default is null, which disables the module entirely. This is the default. If you
110
 *   have both memcached and the memcached PHP extension installed, set this to 'memcached', to enable
111
 *   the cache.
112
 * - <b>Array cache_module_memcache_backend_config:</b> The backend configuration to use if a backend
113
 *   was specified. See the individual backend documentations for more information about the allowed
114
 *   option set. This defaults to an empty array.
115
 * - <b>Array cache_module_memcache_data_groups:</b> The data groups available for the memcache module.
116
 *   You should normally not have to touch this, see the memcache module documentation for details.
117
 *   This defaults to ['ACL', 'PARENT'].
118
 *
119
 * See also midcom_services_cache, the midcom_services_cache_backend class hierarchy and
120
 * the midcom_services_cache_module class hierarchy.
121
 *
122
 * <b>Indexer configuration</b>
123
 *
124
 * - <b>string indexer_backend:</b> The default indexer backend to use. This defaults to the false,
125
 *   indicating that <i>no</i> indexing should be done. Right now, the SOLR backend is recommended.
126
 * - <b>indexer_reindex_allowed_ips:</b> Array of IPs that don't need to basic authenticate themselves
127
 *   to run MidCOM reindexing or cron.
128
 *
129
 * <b>Indexer backend configuration: SOLR module</b>
130
 *
131
 * - <b>string indexer_xmltcp_host:</b> The host name or IP address where the indexer daemon is running.
132
 *   This defaults to "tcp://127.0.0.1", which is the default bind address of the daemon.
133
 * - <b>int indexer_xmltcp_port:</b> The port to which to connect. This defaults to 8983, which is the
134
 *      default port of the daemon.
135
 *
136
 * <b>Logging configuration</b>
137
 *
138
 * - <b>string log_filename:</b> The filename to dump logging messages to, this
139
 *      defaults to {kernel.logs_dir}/midcom.log.
140
 * - <b>int log_level:</b> The logging level to use when starting up the logger, set to
141
 *   MIDCOM_LOG_ERROR by default. You cannot use the MIDCOM* constants when setting
142
 *   micdom_config_local, as they are not defined at that point. Use 0 for CRITICAL,
143
 *   1 for ERROR, 2 for WARNING, 3 for INFO and 4 for DEBUG level logging.
144
 * - <b>array error_actions:</b> Actions to run when a specific error code is produced. This can
145
 *   be used for saving logs about 404 errors from broken links, or sending an error 500 to
146
 *   webmaster for analysis.
147
 *
148
 *   Configuration example:
149
 *
150
 * <code>
151
 * $GLOBALS['midcom_config_local']['error_actions'] = array
152
 * (
153
 *     500 => array
154
 *     (
155
 *         'action' => 'email',
156
 *         'email' => '[email protected]',
157
 *     ),
158
 *     404 => array
159
 *     (
160
 *         'action' => 'log',
161
 *         'filename' => '/var/log/broken_links.log',
162
 *     ),
163
 * );
164
 * </code>
165
 *
166
 * <b>MidCOM Core configuration</b>
167
 *
168
 * - <b>GUID midcom_root_topic_guid:</b> This is the GUID of the topic we should handle.
169
 *   This must be set on a per-site basis, otherwise MidCOM won't start up.
170
 * - <b>string midcom_sgconfig_basedir:</b> The base snippetdir where the current
171
 *   sites' configuration is stored. This defaults to "/sitegroup-config" which will
172
 *   result in the original default shared sitegroup-wide configuration.
173
 * - <b>string midcom_site_url:</b> The fully qualified URL to the Website. A trailing
174
 *   slash is required. It defaults to '/'.
175
 *   If an absolute local URL is given to this value, the full URL of the current host
176
 *   is prefixed to its value, so that this configuration key can be used for Location
177
 *   headers. You must not use a relative URL. This key will be completed by the MidCOM
178
 *   Application constructor, before that, it might contain a URL which is not suitable
179
 *   for relocations.
180
 * - <b>string midcom_tempdir:</b> A temporary directory that can be used when components
181
 *   need to write out files. Defaults to '/tmp'.
182
 * - <b>mixed midcom_max_memory:</b> The maximum memory limit to use doing resource-intensive tasks
183
 *   like when reindexing the entire site, which can require quite some amount of memory, as the complete NAP
184
 *   cache has to be loaded and binary indexing can take some memory, too. Defaults to -1.
185
 *  - <b>mixed midcom_max_execution_time:</b> The maximum execution time for resource-intensive tasks
186
 *  - <b>array midcom_components:</b> Additional out-of-tree components as name => path pairs
187
 *
188
 * <b>RCS system</b>
189
 *
190
 *  <b>string midcom_services_rcs_bin_dir</b>: the prefix for the rcs utilities (default: /usr/bin)
191
 *  <b>string midcom_services_rcs_root </b>: the directory where the rcs files get placed. (default: must be set!)
192
 *  <b>boolean midcom_services_rcs_enable</b>:  if set, midcom will fail hard if the rcs service is not operational. (default: false)
193
 *
194
 * <b>Style Engine</b>
195
 *
196
 * - <b>Array styleengine_default_styles:</b> Use this array to set site-wide default
197
 *   styles to be used for the components. This is an array indexing component name to
198
 *   style path. Components not present in this array use the default style delivered
199
 *   with the component. Any style set directly on a topic or inherited to it will
200
 *   override these settings. This defaults to an empty Array.
201
 *
202
 * <b>Toolbars System</b>
203
 *
204
 * The CSS classes and IDs used by the toolbars service can be configured using these
205
 * options:
206
 *
207
 * - <b>string toolbars_host_style_class:</b> defaults to "midcom_toolbar host_toolbar"
208
 * - <b>string toolbars_host_style_id:</b> defaults to ""
209
 * - <b>string toolbars_node_style_class:</b> defaults to "midcom_toolbar node_toolbar"
210
 * - <b>string toolbars_node_style_id:</b> defaults to ""
211
 * - <b>string toolbars_view_style_class:</b> defaults to midcom_toolbar view_toolbar
212
 * - <b>string toolbars_view_style_id:</b> defaults to ""
213
 * - <b>string toolbars_object_style_class:</b> defaults to midcom_toolbar object_toolbar
214
 * - <b>string toolbars_simple_css_path:</b> this defaults to MIDCOM_STATIC_URL/midcom.services.toolbars/simple.css
215
 *   and is used to set the css for the toolbars used with onsite editing.
216
 * - <b>boolean toolbars_enable_centralized:</b> defaults to true, whether to enable the centralized,
217
 *   javascript-floating MidCOM toolbar that users can display with midcom::get()->toolbars->show();
218
 *
219
 * <b>Utility Programs</b>
220
 *
221
 * The various paths set here lead to the utility programs required by MidCOM, both
222
 * mandatory and optional applications are listed here. To indicate that a certain
223
 * application is unavailable, set it to null. The defaults assume that the files are within the
224
 * $PATH of the Apache user and should be sufficient in most cases. Package maintainers
225
 * are encouraged to make the paths explicit.
226
 *
227
 * - <b>string utility_imagemagick_base:</b> The base path of the ImageMagick executables,
228
 *   the tools <i>mogrify</i>, <i>identify</i> and <i>convert</i> are needed for almost
229
 *   all kinds of image operations in MidCOM and have to be present therefore. The path
230
 *   entered here requires a trailing slash.
231
 * - <b>string utility_jpegtran:</b> JPEGTran is used to do lossless rotation of JPEG
232
 *   images for automatic EXIF rotation in n.s.photos for example. If unavailable,
233
 *   there is an automatic fallback to imagemagick.
234
 * - <b>string utility_catdoc:</b> Transforms Word Documents into text for indexing.
235
 * - <b>string utility_pdftotext:</b> Transforms PDF Documents into text for indexing.
236
 * - <b>string utility_unrtf:</b> Transforms RTF Documents into text files for indexing.
237
 *
238
 * <b>Visibility settings (NAP and DBA)</b>
239
 *
240
 * - <b>boolean show_hidden_objects:</b> This flag indicates whether objects that are
241
 *   invisible either by explicit hiding or by their scheduling should be shown anyway.
242
 *   This defaults to true at this time
243
 * - <b>boolean show_unapproved_objects:</b> This flag indicates whether objects should be
244
 *   shown even if they are not approved. This defaults to true.
245
 *
246
 * @package midcom
247
 */
248
class midcom_config implements ArrayAccess
249
{
250
    private $_default_config = [
251
        // Authentication configuration
252
        'auth_type' => 'Legacy',
253
        'auth_backend' => 'simple',
254
        'auth_backend_simple_cookie_id' => 1,
255
        'auth_login_session_timeout' => 3600,
256
        'auth_login_session_update_interval' => 300,
257
        'auth_frontend' => 'form',
258
        'auth_check_client_ip' => true,
259
        'auth_allow_sudo' => true,
260
        'auth_login_form_httpcode' => 403,
261
        'auth_save_prev_login' => false,
262
        'auth_success_callback' => null,
263
        'auth_failure_callback' => null,
264
        'auth_allow_trusted' => false,
265
        'person_class' => 'openpsa_person',
266
267
        // set secure flag on cookie (applies only when using SSL)
268
        'auth_backend_simple_cookie_secure' => true,
269
270
        // Cache configuration
271
        'cache_base_directory' => '',
272
        'cache_autoload_queue' => ['content', 'nap', 'memcache'],
273
274
        //Memory Caching Daemon
275
        'cache_module_memcache_backend' => 'flatfile',
276
        'cache_module_memcache_backend_config' => [],
277
        'cache_module_memcache_data_groups' => ['ACL', 'PARENT', 'L10N', 'MISC'],
278
279
        // Defaults:
280
        'cache_module_content_backend' => ['driver' => 'flatfile'],
281
        'cache_module_content_uncached' => true,
282
        'cache_module_content_headers_strategy' => 'revalidate',
283
        'cache_module_content_headers_strategy_authenticated' => 'private',
284
        // Seconds, added to gmdate() for expiry timestamp (in case no other expiry is set),
285
        // also used as default expiry for content-cache entries that have no expiry set
286
        'cache_module_content_default_lifetime' => 900,
287
        // as above but concerns only authenticated state
288
        'cache_module_content_default_lifetime_authenticated' => 0,
289
        // Valid options are 'user' (default), 'memberships' and 'public'
290
        'cache_module_content_caching_strategy' => 'user',
291
292
        // CRON Service configuration
293
        'cron_day_hours' => 0,
294
        'cron_day_minutes' => 0,
295
        'cron_hour_minutes' => 30,
296
297
        // I18n Subsystem configuration
298
        'i18n_available_languages' => null,
299
        'i18n_fallback_language' => 'en',
300
301
        // Indexer Configuration
302
        'indexer_backend' => false,
303
        'indexer_reindex_allowed_ips' => ['127.0.0.1'],
304
305
        'indexer_config_options' => ['fl' => '*,score', 'rows' => 1000, 'defType' => 'dismax', 'qf' => 'content'],
306
307
        // XMLTCP indexer backend
308
        'indexer_xmltcp_host' => "127.0.0.1",
309
        'indexer_xmltcp_port' => 8983,
310
        'indexer_xmltcp_core' => null,
311
312
        // Logging Configuration
313
        'log_filename' => null,
314
        'log_level' => MIDCOM_LOG_ERROR,
315
        'error_actions' => [],
316
317
        // Core configuration
318
        'midcom_root_topic_guid' => '',
319
        'midcom_config_basedir' => '/etc/midgard/',
320
        'midcom_sgconfig_basedir' => '/sitegroup-config',
321
        'midcom_site_url' => '/',
322
        'midcom_site_title' => '',
323
        'midcom_tempdir' => '/tmp',
324
        'midcom_max_memory' => -1,
325
        'midcom_max_execution_time' => 0,
326
        'midcom_components' => [],
327
328
        // Visibility settings (NAP)
329
        'show_hidden_objects' => true,
330
        'show_unapproved_objects' => true,
331
        // Style Engine defaults
332
        'styleengine_default_styles' => [],
333
334
        // Toolbars service
335
        'toolbars_host_style_class' => 'midcom_toolbar host_toolbar',
336
        'toolbars_host_style_id' => null,
337
        'toolbars_node_style_class' => 'midcom_toolbar node_toolbar',
338
        'toolbars_node_style_id' => null,
339
        'toolbars_view_style_class' => 'midcom_toolbar view_toolbar',
340
        'toolbars_view_style_id' => null,
341
        'toolbars_help_style_class' => 'midcom_toolbar help_toolbar',
342
        'toolbars_help_style_id' => null,
343
        'toolbars_simple_css_path' => null,
344
        'toolbars_enable_centralized' => true,
345
346
        // Public attachment caching directives
347
        'attachment_cache_enabled' => false,
348
        'attachment_cache_root' => '/var/lib/midgard/vhosts/example.net/80/midcom-static/blobs',
349
        'attachment_cache_url' => '/midcom-static/blobs',
350
351
        //X-sendfile support
352
        'attachment_xsendfile_enable' => false,
353
354
        // Utilities
355
        'utility_imagemagick_base' => '',
356
        'utility_jpegtran' => 'jpegtran',
357
        'utility_catdoc' => 'catdoc',
358
        'utility_pdftotext' => 'pdftotext',
359
        'utility_unrtf' => 'unrtf',
360
361
        'midcom_services_rcs_bin_dir' => '/usr/bin',
362
        'midcom_services_rcs_backend_class' => midcom_services_rcs_backend_rcs::class,
363
        'midcom_services_rcs_root' => '',
364
        'midcom_services_rcs_enable' => true,
365
366
        // Metadata system
367
368
        // Enables approval/scheduling controls (does not influence visibility checks using
369
        // show_unapproved_objects). Disabled by default. Unsafe to Link Prefetching!
370
        'metadata_approval' => false,
371
        'metadata_scheduling' => false,
372
        'metadata_lock_timeout' => 60,    // Time in minutes
373
        'staging2live_staging' => false,
374
375
        // Set the datamanager schema used by the Metadata Service
376
        'metadata_schema' => 'file:/midcom/config/metadata_default.inc',
377
378
        // Map MidCOM metadata properties to HTML meta tags
379
        'metadata_head_elements' => [
380
            'published'   => 'DC.date',
381
            'description'   => 'description',
382
        ],
383
384
        // Whether to gather and display Open Graph Protocol metadata for Midgard pages
385
        'metadata_opengraph' => false,
386
387
        // Component system
388
        // Show only these components when creating or editing
389
        'component_listing_allowed' => null,
390
        'component_listing_excluded' => null,
391
392
        // Page class (body class)
393
        // If this argument is set to true, sanitized name of the component is added to the page class string.
394
        'page_class_include_component' => true,
395
396
        // If this argument is set to true, All midcom_show_style calls wrap the style with HTML comments defining the style path
397
        'wrap_style_show_with_name' => false,
398
399
        // Related to JavaScript libraries
400
        'jquery_version' => '3.6.0.min',
401
        'jquery_ui_version' => '1.12.1',
402
        'jquery_ui_theme' => null,
403
        'jquery_load_from_google' => false,
404
405
        /**
406
         * Sessioning service, disabling the service will help with external caches.
407
         * The second option is to allow logged in users to benefit from the service
408
         */
409
        'sessioning_service_enable' => true,
410
        'sessioning_service_always_enable_for_users' => true,
411
412
        /**
413
         * Trash cleanup, purge deleted objects after X days
414
         */
415
        'cron_purge_deleted_after' => 25,
416
417
        /**
418
         * Theme support
419
         */
420
        'theme' => '',
421
    ];
422
423
    private $_merged_config = [];
424
425 9
    public function __construct()
426
    {
427 9
        $this->_complete_defaults();
428
429 9
        $this->_merged_config = array_merge(
430 9
            $this->_default_config,
431 9
            $GLOBALS['midcom_config_site'] ?? [],
432 9
            $GLOBALS['midcom_config_local'] ?? []
433
        );
434
    }
435
436 9
    private function _complete_defaults()
437
    {
438 9
        if (class_exists('Memcached')) {
439 9
            $this->_default_config['cache_module_content_backend'] = ['driver' => 'memcached'];
440 9
            $this->_default_config['cache_module_memcache_backend'] = 'memcached';
441
        }
442 9
        if (isset($_SERVER['SERVER_ADDR'])) {
443
            $this->_default_config['indexer_reindex_allowed_ips'][] = $_SERVER['SERVER_ADDR'];
444
        }
445 9
        if (!empty($_SERVER['SERVER_NAME'])) {
446 9
            $this->_default_config['midcom_site_title'] = $_SERVER['SERVER_NAME'];
447
        }
448
    }
449
450 707
    public function get(string $key, $default = null)
451
    {
452 707
        if (!$this->offsetExists($key)) {
453 350
            return $default;
454
        }
455
456 706
        if (   $key === 'auth_type'
457 706
            && !in_array($this->_merged_config[$key], ['Plaintext', 'Legacy', 'SHA256'])) {
458
            throw new midcom_error('Unsupported authentication type');
459
        }
460
        // Check the midcom_config site prefix for absolute local urls
461 706
        if (   $key === 'midcom_site_url'
462 706
            && str_starts_with($this->_merged_config[$key], '/')) {
463
            $this->_merged_config[$key] = midcom::get()->get_page_prefix() . substr($this->_merged_config[$key], 1);
464
        }
465
466 706
        return $this->_merged_config[$key];
467
    }
468
469 3
    public function get_array(string $key) : array
470
    {
471 3
        if ($value = $this->get($key)) {
472
            if (!is_array($value)) {
473
                throw new midcom_error('Config key "' . $key . '" is not an array');
474
            }
475
            return $value;
476
        }
477 3
        return [];
478
    }
479
480
    public function export_to(ContainerBuilder $builder)
481
    {
482
        foreach ($this->_merged_config as $key => $value) {
483
            $builder->setParameter('midcom.' . $key, $value);
484
        }
485
    }
486
487 11
    public function set(string $key, $value)
488
    {
489 11
        $this->_merged_config[$key] = $value;
490
    }
491
492 5
    #[\ReturnTypeWillChange]
493
    public function offsetSet($offset, $value)
494
    {
495 5
        $this->set($offset, $value);
496
    }
497
498 707
    public function offsetExists($offset) : bool
499
    {
500 707
        return isset($this->_merged_config[$offset]);
501
    }
502
503
    public function offsetUnset($offset) : void
504
    {
505
        unset($this->_merged_config[$offset]);
506
    }
507
508 87
    #[\ReturnTypeWillChange]
509
    public function offsetGet($offset)
510
    {
511 87
        return $this->get($offset);
512
    }
513
}
514