/data/core/templates/frontend_init.php
}
}
}
if (defined('PAGE') && PAGE != 404) {
// Auto unset signin tfa variables if set
if (
!str_contains($_GET['route'], '/queries/') &&
(isset($_SESSION['remember']) || isset($_SESSION['username']) || isset($_SESSION['email']) || isset($_SESSION['password'])) &&
!isset($_POST['tfa_code'])
) {
unset($_SESSION['remember'], $_SESSION['username'], $_SESSION['email'], $_SESSION['password']);
}
}
if (file_exists(ROOT_PATH . '/custom/templates/' . TEMPLATE . '/template.php')) {
/** @var TemplateBase $template */
require(ROOT_PATH . '/custom/templates/' . TEMPLATE . '/template.php');
} else {
/** @var TemplateBase $template */
require(ROOT_PATH . '/custom/templates/DefaultRevamp/template.php');
}
// Basic template variables
$template->getEngine()->addVariables([
'CONFIG_PATH' => defined('CONFIG_PATH') ? CONFIG_PATH . '/' : '/',
'OG_URL' => Output::getClean(rtrim(URL::getSelfURL(), '/') . $_SERVER['REQUEST_URI']),
'SITE_NAME' => Output::getClean(SITE_NAME),
'SITE_HOME' => URL::build('/'),
'USER_INFO_URL' => URL::build('/queries/user/', 'id='),
'GUEST' => $language->get('user', 'guest'),
]);
$cache->setCache('backgroundcache');
if ($cache->isCached('og_image')) {
// Assign the image value now, some pages may override it (via Page Metadata config)
$template->getEngine()->addVariable('OG_IMAGE', rtrim(URL::getSelfURL(), '/') . $cache->retrieve('og_image'));
}
// User related actions
if ($user->isLoggedIn()) {
/data/modules/Members/pages/members.php
* @author Aberdeener
* @license MIT
* @version 2.2.0
*
* @var ?array $template_pagination
* @var Cache $cache
* @var FakeSmarty $smarty
* @var Language $language
* @var Language $members_language
* @var Navigation $cc_nav
* @var Navigation $navigation
* @var Navigation $staffcp_nav
* @var Pages $pages
* @var TemplateBase $template
* @var User $user
* @var Widgets $widgets
*/
const PAGE = 'members';
$page_title = $members_language->get('members', 'members');
require_once ROOT_PATH . '/core/templates/frontend_init.php';
if (isset($_GET['group'])) {
if (!in_array($_GET['group'], json_decode(Settings::get('member_list_viewable_groups', '{}', 'Members'), true))) {
Redirect::to(URL::build('/members'));
}
$viewing_list = 'group';
$viewing_group = Group::find($_GET['group']);
$template->getEngine()->addVariables([
'VIEWING_GROUP' => [
'id' => $viewing_group->id,
'name' => Output::getClean($viewing_group->name),
],
]);
$lists_viewing = [];
} else {
$viewing_list = $_GET['list'] ?? 'overview';
if ($viewing_list !== 'overview'
&& (!MemberListManager::getInstance()->listExists($viewing_list) || !MemberListManager::getInstance()->getList($viewing_list)->isEnabled())
/data/index.php
require(ROOT_PATH . '/modules/Core/pages/index.php');
}
}
die;
}
$route = rtrim(strtok($_GET['route'], '?'), '/');
$all_pages = $pages->returnPages();
if (array_key_exists($route, $all_pages)) {
$pages->setActivePage($all_pages[$route]);
if (isset($all_pages[$route]['custom'])) {
require(implode(DIRECTORY_SEPARATOR, [ROOT_PATH, 'modules', 'Core', 'pages', 'custom.php']));
die;
}
$path = implode(DIRECTORY_SEPARATOR, [ROOT_PATH, 'modules', $all_pages[$route]['module'], $all_pages[$route]['file']]);
if (file_exists($path)) {
require($path);
die;
}
} else {
// Use recursion to check - might have URL parameters in path
$path_array = explode('/', $route);
for ($i = count($path_array) - 2; $i > 0; $i--) {
$new_path = '/';
for ($n = 1; $n <= $i; $n++) {
$new_path .= $path_array[$n] . '/';
}
$new_path = rtrim($new_path, '/');
if (array_key_exists($new_path, $all_pages)) {
$path = implode(DIRECTORY_SEPARATOR, [ROOT_PATH, 'modules', $all_pages[$new_path]['module'], $all_pages[$new_path]['file']]);
if (file_exists($path)) {
$pages->setActivePage($all_pages[$new_path]);
require($path);
/data/core/init.php
SELECT * FROM nl2_groups WHERE `default_group` = '1';
: [DiscordHook::class, 'execute'],
'events' => json_decode($hook->events, true),
];
}
$cache->store('hooks', $hook_array);
}
}
}
EventHandler::registerWebhooks($hook_array);
// Get IP
$ip = HttpUtils::getRemoteAddress();
// Define default group pre validation
$cache->setCache('pre_validation_default');
$group_id = null;
if ($cache->isCached('pre_validation_default')) {
$group_id = $cache->retrieve('pre_validation_default');
} else {
$group_id = DB::getInstance()->get('groups', ['default_group', '1'])->results();
$group_id = $group_id[0]->id;
}
define('PRE_VALIDATED_DEFAULT', $group_id);
// Perform tasks if the user is logged in
if ($user->isLoggedIn()) {
Debugging::setCanViewDetailedError($user->hasPermission('admincp.errors'));
Debugging::setCanGenerateDebugLink($user->hasPermission('admincp.core.debugging'));
// Ensure a user is not banned
if ($user->data()->isbanned == 1) {
$user->logout();
Session::flash('home_error', $language->get('user', 'you_have_been_banned'));
Redirect::to(URL::build('/'));
}
// Is the IP address banned?
$ip_bans = DB::getInstance()->get('ip_bans', ['ip', $ip])->results();
if (count($ip_bans)) {
/data/core/init.php
SELECT * FROM nl2_hooks WHERE `id` <> '0';
|| str_contains($_GET['route'], 'store/listener')
)) {
// Can continue as normal
} else {
require(ROOT_PATH . '/core/includes/maintenance.php');
die;
}
} else {
// Display notice to admin stating maintenance mode is enabled
define('BYPASS_MAINTENANCE', true);
}
}
// Webhooks
$hook_array = [];
if (Util::isModuleEnabled('Discord Integration')) {
$cache->setCache('hooks');
if ($cache->isCached('hooks')) {
$hook_array = $cache->retrieve('hooks');
} else {
$hooks = DB::getInstance()->get('hooks', ['id', '<>', 0])->results();
if (count($hooks)) {
foreach ($hooks as $hook) {
if ($hook->action != 1 && $hook->action != 2) {
continue;
}
// TODO: more extendable webhook system, #2676
if ($hook->action == 2 && !class_exists(DiscordHook::class)) {
continue;
}
$hook_array[] = [
'id' => $hook->id,
'url' => Output::getClean($hook->url),
'action' => $hook->action == 1
? [WebHook::class, 'execute']
: [DiscordHook::class, 'execute'],
'events' => json_decode($hook->events, true),
];
}
/data/core/classes/Core/Settings.php
SELECT `name`, `value` FROM `nl2_settings` WHERE `module` = 'Referrals';
$cache_name = $module !== null ? $module : 'core';
self::$_cached_settings[$cache_name] = $cache;
}
/**
* Get a setting from the database table `nl2_settings`.
*
* @param string $setting Setting to check.
* @param ?string $fallback Fallback to return if $setting is not set in DB. Defaults to null.
* @param string $module Module name to keep settings separate from other modules. Set module
* to 'Core' for global settings.
* @return ?string Setting from DB or $fallback.
*/
public static function get(string $setting, ?string $fallback = null, string $module = 'core'): ?string
{
if (!self::hasSettingsCache($module)) {
// Load all settings for this module and store it as a dictionary
if ($module === 'core') {
$result = DB::getInstance()->query('SELECT `name`, `value` FROM `nl2_settings` WHERE `module` IS NULL')->results();
} else {
$result = DB::getInstance()->query('SELECT `name`, `value` FROM `nl2_settings` WHERE `module` = ?', [$module])->results();
}
$cache = [];
foreach ($result as $row) {
$cache[$row->name] = $row->value;
}
self::setSettingsCache($module, $cache);
}
$cache = &self::getSettingsCache($module);
return $cache[$setting] ?? $fallback;
}
/**
* Modify a setting in the database table `nl2_settings`.
*
* @param string $setting Setting name.
* @param string|null $new_value New setting value, or null to delete
* @param string $module Module name to keep settings separate from other modules. Set module
/data/modules/Referrals/module.php
SELECT id, custom_url FROM nl2_referrals WHERE disabled = 0 AND custom_url IS NOT NULL;
// Check if module version changed
$cache->setCache('referrals_module_cache');
if (!$cache->isCached('module_version')) {
$cache->store('module_version', $module_version);
} else {
if ($module_version != $cache->retrieve('module_version')) {
// Version have changed, Perform actions
$this->initialiseUpdate($cache->retrieve('module_version'));
$cache->store('module_version', $module_version);
if ($cache->isCached('update_check')) {
$cache->erase('update_check');
}
}
}
try {
// Define URLs which belong to this module
$referrals = $this->_db->query('SELECT id, custom_url FROM nl2_referrals WHERE disabled = 0 AND custom_url IS NOT NULL');
if ($referrals->count()) {
foreach ($referrals->results() as $referral) {
$pages->add('Referrals', '/' . $referral->custom_url, 'pages/referral.php');
}
}
} catch (Exception $e) {
// Database tables don't exist yet
}
// Events
EventHandler::registerEvent(ReferralRegistrationEvent::class);
// Listeners
EventHandler::registerListener(UserRegisteredEvent::class, [RegistrationListener::class, 'registration']);
EventHandler::registerListener(UserValidatedEvent::class, [RegistrationListener::class, 'userValidated']);
EventHandler::registerListener(DiscordWebhookFormatterEvent::class, [RegistrationListener::class, 'discordEmbedFormatter']);
// Store integration
$percentage = Settings::get('store_sale_percentage', '0', 'Referrals');
/data/core/classes/Core/Settings.php
SELECT `name`, `value` FROM `nl2_settings` WHERE `module` = 'Store';
$cache_name = $module !== null ? $module : 'core';
self::$_cached_settings[$cache_name] = $cache;
}
/**
* Get a setting from the database table `nl2_settings`.
*
* @param string $setting Setting to check.
* @param ?string $fallback Fallback to return if $setting is not set in DB. Defaults to null.
* @param string $module Module name to keep settings separate from other modules. Set module
* to 'Core' for global settings.
* @return ?string Setting from DB or $fallback.
*/
public static function get(string $setting, ?string $fallback = null, string $module = 'core'): ?string
{
if (!self::hasSettingsCache($module)) {
// Load all settings for this module and store it as a dictionary
if ($module === 'core') {
$result = DB::getInstance()->query('SELECT `name`, `value` FROM `nl2_settings` WHERE `module` IS NULL')->results();
} else {
$result = DB::getInstance()->query('SELECT `name`, `value` FROM `nl2_settings` WHERE `module` = ?', [$module])->results();
}
$cache = [];
foreach ($result as $row) {
$cache[$row->name] = $row->value;
}
self::setSettingsCache($module, $cache);
}
$cache = &self::getSettingsCache($module);
return $cache[$setting] ?? $fallback;
}
/**
* Modify a setting in the database table `nl2_settings`.
*
* @param string $setting Setting name.
* @param string|null $new_value New setting value, or null to delete
* @param string $module Module name to keep settings separate from other modules. Set module
/data/core/classes/Integrations/IntegrationBase.php
SELECT * FROM nl2_integrations WHERE name = 'Discord';
* @author Partydragen
* @version 2.1.0
* @license MIT
*/
abstract class IntegrationBase
{
private DB $_db;
private IntegrationData $_data;
protected string $_icon;
private array $_errors = [];
protected Language $_language;
protected ?string $_settings = null;
protected string $_name;
protected ?int $_order;
public function __construct()
{
$this->_db = DB::getInstance();
$integration = $this->_db->query('SELECT * FROM nl2_integrations WHERE name = ?', [$this->_name]);
if ($integration->count()) {
$integration = $integration->first();
$this->_data = new IntegrationData($integration);
$this->_order = $integration->order;
} else {
// Register integration to database
$this->_db->query('INSERT INTO nl2_integrations (name) VALUES (?)', [
$this->_name,
]);
$integration = $this->_db->query('SELECT * FROM nl2_integrations WHERE name = ?', [$this->_name])->first();
$this->_data = new IntegrationData($integration);
$this->_order = $integration->order;
}
}
/**
* Get the name of this integration.
/data/modules/Lists/module.php
SELECT * FROM `nl2_lists_submissions` WHERE `vanity_url` IS NOT NULL;
Lists::getInstance()->registerProviderConnection(new DiscordConnection());
Lists::getInstance()->registerProviderConnection(new NamelessMCConnection());
Lists::getInstance()->registerProviderConnection(new BF2142Connection());
EventHandler::registerEvent(ListSubmissionCreatedEvent::class);
// Store Listener
EventHandler::registerListener(PaymentCompletedEvent::class, [StorePaymentListener::class, 'paymentCompleted']);
// Register page for each lists
$lists = DB::getInstance()->query('SELECT * FROM nl2_lists WHERE provider IS NOT NULL AND url IS NOT NULL');
if ($lists->count()) {
foreach ($lists->results() as $list) {
// Register page
$pages->add('Lists', $list->url, 'pages/submissions.php', 'lists-' . $list->id, true);
$pages->add('Lists', $list->url . '/new', 'pages/new_submission.php', 'lists-' . $list->id);
}
}
// Register page for each submission that has own vanity url
$submissions = DB::getInstance()->query('SELECT * FROM `nl2_lists_submissions` WHERE `vanity_url` IS NOT NULL');
foreach ($submissions->results() as $submission) {
$pages->add('Lists', '/' . $submission->vanity_url, 'pages/submission.php');
}
}
public function onInstall() {
PhinxAdapter::migrate($this->getName(), __DIR__ . '/includes/migrations');
mkdir(ROOT_PATH . '/uploads/lists_icons');
mkdir(ROOT_PATH . '/uploads/lists_images');
mkdir(ROOT_PATH . '/uploads/lists_banners');
}
public function onUninstall() {
PhinxAdapter::rollback($this->getName(), __DIR__ . '/includes/migrations');
}
public function onEnable() {
PhinxAdapter::migrate($this->getName(), __DIR__ . '/includes/migrations');
/data/modules/Lists/module.php
SELECT * FROM nl2_lists WHERE provider IS NOT NULL AND url IS NOT NULL;
$pages->add('Lists', '/panel/lists/settings', 'pages/panel/settings.php');
$pages->add('Lists', '/panel/lists', 'pages/panel/lists.php');
$pages->add('Lists', '/panel/lists/tags', 'pages/panel/tags.php');
$pages->add('Lists', '/queries/querysubmissions', 'queries/querysubmissions.php');
// Register provider connections
Lists::getInstance()->registerProviderConnection(new DefaultConnection());
Lists::getInstance()->registerProviderConnection(new MinecraftConnection());
Lists::getInstance()->registerProviderConnection(new VotifierConnection());
Lists::getInstance()->registerProviderConnection(new MCStatisticsConnection());
Lists::getInstance()->registerProviderConnection(new DiscordConnection());
Lists::getInstance()->registerProviderConnection(new NamelessMCConnection());
Lists::getInstance()->registerProviderConnection(new BF2142Connection());
EventHandler::registerEvent(ListSubmissionCreatedEvent::class);
// Store Listener
EventHandler::registerListener(PaymentCompletedEvent::class, [StorePaymentListener::class, 'paymentCompleted']);
// Register page for each lists
$lists = DB::getInstance()->query('SELECT * FROM nl2_lists WHERE provider IS NOT NULL AND url IS NOT NULL');
if ($lists->count()) {
foreach ($lists->results() as $list) {
// Register page
$pages->add('Lists', $list->url, 'pages/submissions.php', 'lists-' . $list->id, true);
$pages->add('Lists', $list->url . '/new', 'pages/new_submission.php', 'lists-' . $list->id);
}
}
// Register page for each submission that has own vanity url
$submissions = DB::getInstance()->query('SELECT * FROM `nl2_lists_submissions` WHERE `vanity_url` IS NOT NULL');
foreach ($submissions->results() as $submission) {
$pages->add('Lists', '/' . $submission->vanity_url, 'pages/submission.php');
}
}
public function onInstall() {
PhinxAdapter::migrate($this->getName(), __DIR__ . '/includes/migrations');
mkdir(ROOT_PATH . '/uploads/lists_icons');
mkdir(ROOT_PATH . '/uploads/lists_images');
/data/core/classes/Database/PhinxAdapter.php
SELECT version, migration_name FROM nl2_phinxlog_lists;
if (!$migrationDir) {
$migrationDir = __DIR__ . '/../../migrations';
}
$migration_files = array_map(
static function ($file_name) {
[$version, $migration_name] = explode('_', $file_name, 2);
$migration_name = str_replace(['.php', '_'], '', ucwords($migration_name, '_'));
return $version . '_' . $migration_name;
},
array_filter(scandir($migrationDir), static function ($file_name) {
// Pattern that matches Phinx migration file names (eg: 20230403000000_create_stroopwafel_table.php)
return preg_match('/^\d{14}_\w+\.php$/', $file_name);
}),
);
$migration_database_entries = array_map(static function ($row) {
return $row->version . '_' . $row->migration_name;
}, DB::getInstance()->query("SELECT version, migration_name FROM $table")->results());
$missing = array_diff($migration_files, $migration_database_entries);
$extra = array_diff($migration_database_entries, $migration_files);
if ($returnResults) {
return [
'missing' => count($missing),
'extra' => count($extra),
];
}
// Likely a pull from the repo dev branch or migrations
// weren't run during an upgrade script.
if (($missing_count = count($missing)) > 0) {
echo "There are $missing_count migrations files which have not been executed:" . '<br>';
foreach ($missing as $missing_migration) {
echo " - $missing_migration" . '<br>';
}
}
/data/core/classes/Core/Module.php
SELECT * FROM nl2_modules WHERE `name` = 'Core';
/**
* Get this module's ID.
*
* @return int The ID for the module
*/
public function getId(): int
{
return DB::getInstance()->query('SELECT `id` FROM nl2_modules WHERE `name` = ?', [$this->_name])->first()->id;
}
/**
* Get a module ID from name.
*
* @param string $name Module name
*
* @return ?int Module ID
*/
public static function getIdFromName(string $name): ?int
{
$query = DB::getInstance()->get('modules', ['name', $name]);
if ($query->count()) {
return $query->first()->id;
}
return null;
}
/**
* Get a module name from ID.
*
* @param int $id Module ID
*
* @return ?string Module name
*/
public static function getNameFromId(int $id): ?string
{
$query = DB::getInstance()->get('modules', ['id', $id]);
if ($query->count()) {
/data/core/classes/Integrations/IntegrationBase.php
SELECT * FROM nl2_integrations WHERE name = 'Google';
* @author Partydragen
* @version 2.1.0
* @license MIT
*/
abstract class IntegrationBase
{
private DB $_db;
private IntegrationData $_data;
protected string $_icon;
private array $_errors = [];
protected Language $_language;
protected ?string $_settings = null;
protected string $_name;
protected ?int $_order;
public function __construct()
{
$this->_db = DB::getInstance();
$integration = $this->_db->query('SELECT * FROM nl2_integrations WHERE name = ?', [$this->_name]);
if ($integration->count()) {
$integration = $integration->first();
$this->_data = new IntegrationData($integration);
$this->_order = $integration->order;
} else {
// Register integration to database
$this->_db->query('INSERT INTO nl2_integrations (name) VALUES (?)', [
$this->_name,
]);
$integration = $this->_db->query('SELECT * FROM nl2_integrations WHERE name = ?', [$this->_name])->first();
$this->_data = new IntegrationData($integration);
$this->_order = $integration->order;
}
}
/**
* Get the name of this integration.
/data/core/classes/Integrations/IntegrationBase.php
SELECT * FROM nl2_integrations WHERE name = 'Minecraft';
* @author Partydragen
* @version 2.1.0
* @license MIT
*/
abstract class IntegrationBase
{
private DB $_db;
private IntegrationData $_data;
protected string $_icon;
private array $_errors = [];
protected Language $_language;
protected ?string $_settings = null;
protected string $_name;
protected ?int $_order;
public function __construct()
{
$this->_db = DB::getInstance();
$integration = $this->_db->query('SELECT * FROM nl2_integrations WHERE name = ?', [$this->_name]);
if ($integration->count()) {
$integration = $integration->first();
$this->_data = new IntegrationData($integration);
$this->_order = $integration->order;
} else {
// Register integration to database
$this->_db->query('INSERT INTO nl2_integrations (name) VALUES (?)', [
$this->_name,
]);
$integration = $this->_db->query('SELECT * FROM nl2_integrations WHERE name = ?', [$this->_name])->first();
$this->_data = new IntegrationData($integration);
$this->_order = $integration->order;
}
}
/**
* Get the name of this integration.
/data/modules/Core/module.php
SELECT * FROM nl2_custom_pages_permissions WHERE `group_id` = '0';
$navigation->add(
$custom_page->id,
Output::getClean($custom_page->title),
(is_null($redirect)) ? URL::build(Output::urlEncodeAllowSlashes($custom_page->url)) : $redirect,
'footer', $custom_page->target ? '_blank' : null,
2000,
$custom_page->icon
);
break;
}
break 2;
}
break;
}
}
}
}
}
} else {
$custom_page_permissions = DB::getInstance()->get('custom_pages_permissions', ['group_id', 0])->results();
if (count($custom_page_permissions)) {
foreach ($custom_pages as $custom_page) {
$redirect = null;
if ($custom_page->redirect == 1) {
$redirect = Output::getClean($custom_page->link);
}
$pages->addCustom(Output::urlEncodeAllowSlashes($custom_page->url), Output::getClean($custom_page->title), !$custom_page->basic);
foreach ($custom_page_permissions as $permission) {
if ($permission->page_id == $custom_page->id) {
if ($permission->view == 1) {
// Check cache for order
if (!$cache->isCached($custom_page->id . '_order')) {
// Create cache entry now
$page_order = 200;
$cache->store($custom_page->id . '_order', 200);
} else {
$page_order = $cache->retrieve($custom_page->id . '_order');
/data/modules/Core/module.php
SELECT * FROM nl2_custom_pages WHERE `id` <> '0';
}
// "More" dropdown
$cache->setCache('navbar_icons');
if ($cache->isCached('more_dropdown_icon')) {
$icon = $cache->retrieve('more_dropdown_icon');
} else {
$icon = '';
}
$cache->setCache('navbar_order');
if ($cache->isCached('more_dropdown_order')) {
$order = $cache->retrieve('more_dropdown_order');
} else {
$order = 2500;
}
$navigation->addDropdown('more_dropdown', $language->get('general', 'more'), 'top', $order, $icon);
// Custom pages
$custom_pages = DB::getInstance()->get('custom_pages', ['id', '<>', 0])->results();
if (count($custom_pages)) {
$more = [];
$cache->setCache('navbar_order');
if ($user->isLoggedIn()) {
// Check all groups
$user_groups = $user->getAllGroupIds();
foreach ($custom_pages as $custom_page) {
$redirect = null;
// Get redirect URL if enabled
if ($custom_page->redirect == 1) {
$redirect = $custom_page->link;
}
$pages->addCustom(Output::urlEncodeAllowSlashes($custom_page->url), Output::getClean($custom_page->title), !$custom_page->basic);
foreach ($user_groups as $user_group) {
$custom_page_permissions = DB::getInstance()->get('custom_pages_permissions', ['group_id', $user_group])->results();
/data/core/classes/Core/Settings.php
SELECT `name`, `value` FROM `nl2_settings` WHERE `module` IS NULL;
private static function setSettingsCache(?string $module, array $cache): void
{
$cache_name = $module !== null ? $module : 'core';
self::$_cached_settings[$cache_name] = $cache;
}
/**
* Get a setting from the database table `nl2_settings`.
*
* @param string $setting Setting to check.
* @param ?string $fallback Fallback to return if $setting is not set in DB. Defaults to null.
* @param string $module Module name to keep settings separate from other modules. Set module
* to 'Core' for global settings.
* @return ?string Setting from DB or $fallback.
*/
public static function get(string $setting, ?string $fallback = null, string $module = 'core'): ?string
{
if (!self::hasSettingsCache($module)) {
// Load all settings for this module and store it as a dictionary
if ($module === 'core') {
$result = DB::getInstance()->query('SELECT `name`, `value` FROM `nl2_settings` WHERE `module` IS NULL')->results();
} else {
$result = DB::getInstance()->query('SELECT `name`, `value` FROM `nl2_settings` WHERE `module` = ?', [$module])->results();
}
$cache = [];
foreach ($result as $row) {
$cache[$row->name] = $row->value;
}
self::setSettingsCache($module, $cache);
}
$cache = &self::getSettingsCache($module);
return $cache[$setting] ?? $fallback;
}
/**
* Modify a setting in the database table `nl2_settings`.
*
* @param string $setting Setting name.