mediawiki-skins-Vector/includes/ServiceWiring.php

262 lines
7.3 KiB
PHP
Raw Normal View History

<?php
/**
* Service Wirings for Vector skin
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* http://www.gnu.org/copyleft/gpl.html
*
* @file
* @since 1.35
*/
use MediaWiki\MediaWikiServices;
use MediaWiki\Skins\Vector\Constants;
use MediaWiki\Skins\Vector\FeatureManagement\FeatureManager;
use MediaWiki\Skins\Vector\FeatureManagement\Requirements\DynamicConfigRequirement;
use MediaWiki\Skins\Vector\FeatureManagement\Requirements\OverridableConfigRequirement;
return [
Constants::SERVICE_FEATURE_MANAGER => static function ( MediaWikiServices $services ) {
featureManager: Add DynamicConfigRequirement requirement We expect the vast majority of requirements and features to be defined in services as possible. However, there are some "complex" requirements that require additional application/HTTP request state. Unfortunately, service wiring is done before some of that state is available. I65702426 attempted to work around this by requiring clients of the Feature Manager to pass that additional state on every interaction with the system. Those complex requirements would then select the parts of the state that they required when it was required. However implementations of \IContextSource are God objects and their use should be limited. Whilst reviewing I65702426, Stephen Niedzielski mentioned that the application state being available is a requirement. This remarkably simple solution: - Keeps the Requirement interface and FeatureManager API free of God objects; - Is true to the nature of the Feature Manager - it makes clear and centralizes the various checks for application state being available across the codebase; and - Inject a Requirement implementations' dependencies at construction time It just so happens that the $wgFullyInitialised variable flags whether the application state is available... Changes: - Add the the FeatureManager\Requirements\DynamicConfigRequirement class and tests. The DynamicConfigRequirement lazily evaluates a single configuration value whenever ::isMet is invoked - Register an DynamicConfigRequirement instance, configured to evaluate $wgFullyInitialised while constructing the Vector.FeatureManager service Bug: T244481 Change-Id: I7a2cdc2dfdf20d78e4548f07cf53994563b234b3
2020-03-13 17:22:59 +00:00
$featureManager = new FeatureManager();
$featureManager->registerRequirement(
new DynamicConfigRequirement(
$services->getMainConfig(),
Constants::CONFIG_KEY_FULLY_INITIALISED,
Constants::REQUIREMENT_FULLY_INITIALISED
)
);
featureManager: Add DynamicConfigRequirement requirement We expect the vast majority of requirements and features to be defined in services as possible. However, there are some "complex" requirements that require additional application/HTTP request state. Unfortunately, service wiring is done before some of that state is available. I65702426 attempted to work around this by requiring clients of the Feature Manager to pass that additional state on every interaction with the system. Those complex requirements would then select the parts of the state that they required when it was required. However implementations of \IContextSource are God objects and their use should be limited. Whilst reviewing I65702426, Stephen Niedzielski mentioned that the application state being available is a requirement. This remarkably simple solution: - Keeps the Requirement interface and FeatureManager API free of God objects; - Is true to the nature of the Feature Manager - it makes clear and centralizes the various checks for application state being available across the codebase; and - Inject a Requirement implementations' dependencies at construction time It just so happens that the $wgFullyInitialised variable flags whether the application state is available... Changes: - Add the the FeatureManager\Requirements\DynamicConfigRequirement class and tests. The DynamicConfigRequirement lazily evaluates a single configuration value whenever ::isMet is invoked - Register an DynamicConfigRequirement instance, configured to evaluate $wgFullyInitialised while constructing the Vector.FeatureManager service Bug: T244481 Change-Id: I7a2cdc2dfdf20d78e4548f07cf53994563b234b3
2020-03-13 17:22:59 +00:00
$context = RequestContext::getMain();
// Feature: Languages in sidebar
// ================================
$featureManager->registerRequirement(
new OverridableConfigRequirement(
$services->getMainConfig(),
$context->getUser(),
$context->getRequest(),
$services->getCentralIdLookupFactory()->getNonLocalLookup(),
Constants::CONFIG_KEY_LANGUAGE_IN_HEADER,
Constants::REQUIREMENT_LANGUAGE_IN_HEADER,
null,
Constants::CONFIG_LANGUAGE_IN_HEADER_TREATMENT_AB_TEST
)
);
// ---
// Temporary T286932 - remove after languages A/B test is finished.
$requirementName = 'T286932';
// MultiConfig checks each config in turn, allowing us to override the main config for specific keys. In this
// case, override the "VectorLanguageInHeaderABTest" configuration value so that the following requirement
// always buckets the user as if the language treatment A/B test were running.
$config = new MultiConfig( [
new HashConfig( [
Constants::CONFIG_LANGUAGE_IN_HEADER_TREATMENT_AB_TEST => true,
] ),
$services->getMainConfig(),
] );
$featureManager->registerRequirement(
new OverridableConfigRequirement(
$config,
$context->getUser(),
$context->getRequest(),
$services->getCentralIdLookupFactory()->getNonLocalLookup(),
Constants::CONFIG_KEY_LANGUAGE_IN_HEADER,
$requirementName,
/* $overrideName = */ '',
Constants::CONFIG_LANGUAGE_IN_HEADER_TREATMENT_AB_TEST
)
);
// ---
$featureManager->registerFeature(
Constants::FEATURE_LANGUAGE_IN_HEADER,
[
Constants::REQUIREMENT_FULLY_INITIALISED,
Constants::REQUIREMENT_LANGUAGE_IN_HEADER,
]
);
// Feature: T293470: Language in main page header
// ================================
$featureManager->registerRequirement(
new OverridableConfigRequirement(
$services->getMainConfig(),
$context->getUser(),
$context->getRequest(),
null,
Constants::CONFIG_LANGUAGE_IN_MAIN_PAGE_HEADER,
Constants::REQUIREMENT_LANGUAGE_IN_MAIN_PAGE_HEADER
)
);
$featureManager->registerSimpleRequirement(
Constants::REQUIREMENT_IS_MAIN_PAGE,
$context->getTitle() ? $context->getTitle()->isMainPage() : false
);
$featureManager->registerFeature(
Constants::FEATURE_LANGUAGE_IN_MAIN_PAGE_HEADER,
[
Constants::REQUIREMENT_FULLY_INITIALISED,
Constants::REQUIREMENT_IS_MAIN_PAGE,
Constants::REQUIREMENT_LANGUAGE_IN_HEADER,
Constants::REQUIREMENT_LANGUAGE_IN_MAIN_PAGE_HEADER
]
);
// Feature: T295555: Language switch alert in sidebar
// ================================
$featureManager->registerRequirement(
new OverridableConfigRequirement(
$services->getMainConfig(),
$context->getUser(),
$context->getRequest(),
null,
Constants::CONFIG_LANGUAGE_ALERT_IN_SIDEBAR,
Constants::REQUIREMENT_LANGUAGE_ALERT_IN_SIDEBAR
)
);
$featureManager->registerFeature(
Constants::FEATURE_LANGUAGE_ALERT_IN_SIDEBAR,
[
Constants::REQUIREMENT_FULLY_INITIALISED,
Constants::REQUIREMENT_LANGUAGE_IN_HEADER,
Constants::REQUIREMENT_LANGUAGE_ALERT_IN_SIDEBAR
]
);
// Feature: T297610: Table of Contents
// ================================
$featureManager->registerRequirement(
new OverridableConfigRequirement(
$services->getMainConfig(),
$context->getUser(),
$context->getRequest(),
null,
Constants::CONFIG_TABLE_OF_CONTENTS,
Constants::REQUIREMENT_TABLE_OF_CONTENTS,
Constants::QUERY_PARAM_TABLE_OF_CONTENTS,
null
)
);
$featureManager->registerFeature(
Constants::FEATURE_TABLE_OF_CONTENTS,
[
Constants::REQUIREMENT_FULLY_INITIALISED,
Constants::REQUIREMENT_TABLE_OF_CONTENTS
]
);
// Feature: Sticky header
// ================================
$featureManager->registerRequirement(
new OverridableConfigRequirement(
$services->getMainConfig(),
$context->getUser(),
$context->getRequest(),
null,
Constants::CONFIG_STICKY_HEADER,
Constants::REQUIREMENT_STICKY_HEADER
)
);
$featureManager->registerRequirement(
new OverridableConfigRequirement(
$services->getMainConfig(),
$context->getUser(),
$context->getRequest(),
null,
Constants::CONFIG_STICKY_HEADER_EDIT,
Constants::REQUIREMENT_STICKY_HEADER_EDIT
)
);
$featureManager->registerFeature(
Constants::FEATURE_STICKY_HEADER,
[
Constants::REQUIREMENT_FULLY_INITIALISED,
Constants::REQUIREMENT_STICKY_HEADER
]
);
$featureManager->registerFeature(
Constants::FEATURE_STICKY_HEADER_EDIT,
[
Constants::REQUIREMENT_FULLY_INITIALISED,
Constants::REQUIREMENT_STICKY_HEADER,
Constants::REQUIREMENT_STICKY_HEADER_EDIT,
]
);
// Feature: Title above tabs
// ================================
$featureManager->registerRequirement(
new OverridableConfigRequirement(
$services->getMainConfig(),
$context->getUser(),
$context->getRequest(),
null,
Constants::CONFIG_TITLE_ABOVE_TABS,
Constants::REQUIREMENT_TITLE_ABOVE_TABS
)
);
$featureManager->registerFeature(
Constants::FEATURE_TITLE_ABOVE_TABS,
[
Constants::REQUIREMENT_FULLY_INITIALISED,
Constants::REQUIREMENT_TITLE_ABOVE_TABS,
]
);
// Feature: Grid
// ================================
$featureManager->registerRequirement(
new OverridableConfigRequirement(
$services->getMainConfig(),
$context->getUser(),
$context->getRequest(),
null,
Constants::CONFIG_GRID,
Constants::REQUIREMENT_GRID
)
);
// Requires both table of contents and title above tabs
// to be enabled to simplify the number of variants it needs
// to consider.
$featureManager->registerFeature(
Constants::FEATURE_GRID,
[
Constants::REQUIREMENT_FULLY_INITIALISED,
Constants::REQUIREMENT_TITLE_ABOVE_TABS,
Constants::REQUIREMENT_GRID,
Constants::REQUIREMENT_TABLE_OF_CONTENTS,
]
);
featureManager: Add DynamicConfigRequirement requirement We expect the vast majority of requirements and features to be defined in services as possible. However, there are some "complex" requirements that require additional application/HTTP request state. Unfortunately, service wiring is done before some of that state is available. I65702426 attempted to work around this by requiring clients of the Feature Manager to pass that additional state on every interaction with the system. Those complex requirements would then select the parts of the state that they required when it was required. However implementations of \IContextSource are God objects and their use should be limited. Whilst reviewing I65702426, Stephen Niedzielski mentioned that the application state being available is a requirement. This remarkably simple solution: - Keeps the Requirement interface and FeatureManager API free of God objects; - Is true to the nature of the Feature Manager - it makes clear and centralizes the various checks for application state being available across the codebase; and - Inject a Requirement implementations' dependencies at construction time It just so happens that the $wgFullyInitialised variable flags whether the application state is available... Changes: - Add the the FeatureManager\Requirements\DynamicConfigRequirement class and tests. The DynamicConfigRequirement lazily evaluates a single configuration value whenever ::isMet is invoked - Register an DynamicConfigRequirement instance, configured to evaluate $wgFullyInitialised while constructing the Vector.FeatureManager service Bug: T244481 Change-Id: I7a2cdc2dfdf20d78e4548f07cf53994563b234b3
2020-03-13 17:22:59 +00:00
return $featureManager;
}
];