Migrate all callers of Hooks::run() to use the new
HookContainer/HookRunner system.
General principles:
* Use DI if it is already used. We're not changing the way state is
managed in this patch.
* HookContainer is always injected, not HookRunner. HookContainer
is a service, it's a more generic interface, it is the only
thing that provides isRegistered() which is needed in some cases,
and a HookRunner can be efficiently constructed from it
(confirmed by benchmark). Because HookContainer is needed
for object construction, it is also needed by all factories.
* "Ask your friendly local base class". Big hierarchies like
SpecialPage and ApiBase have getHookContainer() and getHookRunner()
methods in the base class, and classes that extend that base class
are not expected to know or care where the base class gets its
HookContainer from.
* ProtectedHookAccessorTrait provides protected getHookContainer() and
getHookRunner() methods, getting them from the global service
container. The point of this is to ease migration to DI by ensuring
that call sites ask their local friendly base class rather than
getting a HookRunner from the service container directly.
* Private $this->hookRunner. In some smaller classes where accessor
methods did not seem warranted, there is a private HookRunner property
which is accessed directly. Very rarely (two cases), there is a
protected property, for consistency with code that conventionally
assumes protected=private, but in cases where the class might actually
be overridden, a protected accessor is preferred over a protected
property.
* The last resort: Hooks::runner(). Mostly for static, file-scope and
global code. In a few cases it was used for objects with broken
construction schemes, out of horror or laziness.
Constructors with new required arguments:
* AuthManager
* BadFileLookup
* BlockManager
* ClassicInterwikiLookup
* ContentHandlerFactory
* ContentSecurityPolicy
* DefaultOptionsManager
* DerivedPageDataUpdater
* FullSearchResultWidget
* HtmlCacheUpdater
* LanguageFactory
* LanguageNameUtils
* LinkRenderer
* LinkRendererFactory
* LocalisationCache
* MagicWordFactory
* MessageCache
* NamespaceInfo
* PageEditStash
* PageHandlerFactory
* PageUpdater
* ParserFactory
* PermissionManager
* RevisionStore
* RevisionStoreFactory
* SearchEngineConfig
* SearchEngineFactory
* SearchFormWidget
* SearchNearMatcher
* SessionBackend
* SpecialPageFactory
* UserNameUtils
* UserOptionsManager
* WatchedItemQueryService
* WatchedItemStore
Constructors with new optional arguments:
* DefaultPreferencesFactory
* Language
* LinkHolderArray
* MovePage
* Parser
* ParserCache
* PasswordReset
* Router
setHookContainer() now required after construction:
* AuthenticationProvider
* ResourceLoaderModule
* SearchEngine
Change-Id: Id442b0dbe43aba84bd5cf801d86dedc768b082c7
Follows-up I6da55e78d5. The makeKey() call was accidentally lost,
thus the locks became shared across all wikis.
Bug: T113916
Bug: T247028
Change-Id: Id459120965c9a6d3b68a028d2c69dc042277b5d2
Follows-up f5aaf75ad1.
* Improve some docs for these hooks.
* Add type hints.
* Add them as a subgroup within the ResourceLoader docgroup
for easy navigation.
Bug: T246855
Change-Id: I52f31e2b63dcf265b27e68ba8fd4f885d82088ac
This will make it easy to later allow the user to select which
component's specs to load and run (via CLI and GUI), e.g. for
an entire extension. We currently only have very narrow or very
wide selection mechanisms ('module' param for 1 module,
'rerun' for 1 test case, 'filter' param for global pattern match).
Bug: T250045
Depends-On: I55fe27e1c74972fcb3cdafefdc78e10e24f95b80
Change-Id: I5c01f720d787c3847228de511ce913284786ad66
Instead of exporting this as a global variable, export it as an extension
attribute.
The $wgResourceModuleSkinStyles configuration variable will continue
to be supported for its main purpose of setting skin styles. However
it may no longer be used to read these settings. The canonical copy
of this is now restricted to the ResourceLoader class and not (yet)
made publicly available (I found no use cases for it).
This opens the door to making it lazy-loaded attribute, which would help
reduce the size of the "main" APCu cache key for ExtensionRegistry.
This is not possible with global variables as those must be exported
unconditionally from Setup.php.
Bug: T32956
Bug: T247265
Change-Id: I4ecf558d9c630c91959786d2573c34e619223cef
This should be the exact same. Its more a style change than anything.
So why do it then?
* I believe this is much less confusing than code mentioning a weird
"standard class". Barely anybody knows what this is, and what the
difference between "object" and "stdClass" is.
* The code is shorter.
* It's even faster. In my micro benchmark it's twice as fast.
Change-Id: I7ee0e8ae6d9264a89b6cd1dd861f0466ae620ccc
* Where possible and easy to figure out, change `array` to something like
`array<K,V>` or `V[]` for improved static analysis to catch/prevent
regressions in CI.
* Minor doc improvements:
- consistently use the imperative mood for method briefs,
- consistently use @internal instead of @private,
- explain in @throws why they happen to inform when they should be caught
(and remove if they are not meant to be caught/handled by any caller).
* Simplify addSources() implementation as a simple loop instead recursing
(not worth the complexity, only called once or twice at runtime).
* Use more granular exceptions to distinguish between errors that indicate
a mistake on the caller (logic/invalid arguments error), and runtime
errors (which are more circumstantial).
* Update register() unit test for bad 'moduleInfo' type to use
a nested value, given that the second-parameter level type is
now verified by the signature already.
Change-Id: Id98ba1f28cb7f1c72f0a3e82f4151bcbd0f3db77
This allows us to move things that are not used on every request (e.g.
'TrackingCategories') into separate cache entries to slim down the main
one.
At the same time, fold getLazyLoadedAttribute() into the standard and
already established getAttribute(), so that client code doesn't need to
be aware of whether something is lazy-loaded or not, it'll just work.
Everything is still cached using the load queue as part of the cache key
for instant invalidation, so if an extension.json file changes, the
lazy-loaded attribute cache will invalidate too.
The cache is populated whenever loadFromQueue() happens, but if it
happens to fall out of the cache, then getLazyLoadedAttribute() will
iterate over all the loaded extension/skin.json files to read that
value. Since we end up reading everything, we populate all of the
caches again.
The caching logic was split into two more private functions
(::getCache() and ::makeCacheKey()) for easier internal reuse.
Bug: T220994
Change-Id: I290926bbedfc964195d1f576a9e06349f9e5d5ea
This can be enabled via a configuration flag. Otherwise, SqlModuleDependencyStore
will be used in order to keep using the module_deps table.
Create a dependency store class, wrapping BagOStuff, that stores known module
dependencies. Inject it into ResourceLoader and inject the path lists into
ResourceLoaderModule directly and via callback.
Bug: T113916
Change-Id: I6da55e78d5554e30e5df6b4bc45d84817f5bea15
`$this->getModule()` returns a RL object or a null. The check above already
makes sure that $module is not null so we can just set file dependencies
from the RL object returned.
In addition, this is an optimization as we reduce repeated calls to
`$this->getModule()`. Similar logic already exist in the same file from
L#116 - L#118.
Change-Id: If50c28ff5cd8eb435c9fa4f277e2d1038b52ca74
This data isn't needed for startup, and we can shave off a few K from
startup by moving it to mediawiki.base instead.
It was requested that this be done as a "package file", which
necessitated some other minor structural changes to mediawiki.base as
well.
Bug: T235350
Change-Id: I525a5203533089d5a542f83a847be58a10cb6319
These attributes are only accessed at a time when performance isn't
critical (e.g. tests), so we can skip caching them and read each
extension.json file again when we do need them.
At the same time, we want to reduce the size of the array that we're
caching due to PHP 7 performance regressions with APC (T187154).
'QUnitModules' is the first attribute to be converted into a lazy-loaded
attribute.
Bug: T220994
Change-Id: I224cdace05dbac00ff947c41daecb74b07c967bb
Avoid use of wfTimestamp and wfDebugLog global functions.
Also simplify some of the error messages around processing of
'packageFiles' definitions and throw generic LogicException
instead of MWException.
Change-Id: I55ce1f107f53dfdfe673cbe4411b0a7c4e24b2ea
This is to make it behave in a more object orientied way. The
goal is to make it be easier to allow extensions to mark certain
pages as requiring a different policy (For example, CodeEditor
extension uses a blob: url with a WebWorker. We don't want to
include that on the policy of every page, but allow the extension
to mark it as required whenever needed).
This commit does not change code behaviour in any way.
Change-Id: I4bf53dabb6e6c5446cea99a64db68b300cef2fd4
These are almost only doc changes, with two exceptions:
1-In LinkHolderArray, int-alike array keys are now cast to int, to be uniform with what we do in other code paths
2-In ExtensionRegistration, changed a line to throw an Exception
immediately, instead of an ExtensionDependencyError. This is because the
latter takes an array with msg and type, but we were passing it a plain
string (and in fact the code was bugged).
Bug: T231636
Change-Id: I8b0ef50d279c2a87490dde6a467a4e22c0710afd
ResourceLoader::getLessVars is deprecated since ca510f742 included in
MW 1.32 and hard-deprecated since 1b32592d9 included in MW 1.34.
Bug: T140804
Change-Id: If88c71ed7fdf3c6a5cf89a50197e246c201ebaa2
This change allows to use the context in the functions.
The following internal static functions from ResourceLoader get now a
reference to the ResourceLoaderContext object:
* makeLoaderImplementScript
* makeLoaderStateScript
* makeLoaderRegisterScript
* makeLoaderSourcesScript
ResouceLoader::encodeJsonForScript is duplicated to
ResourceLoaderContext::encodeJson loading the debug mode from context.
ResourceLoader::encodeJsonForScript is kept for other usages without
context.
The debug mode is loaded from $context->getDebug() instead of from
ResourceLoader::inDebugMode(). This does not support to enable the debug
mode by setting the cookie 'resourceLoaderDebug' or the configuration
variable wgResourceLoaderDebug. Only the URL parameter debug=true
enables the debug mode. This should be sufficient for the subsequent
ResourceLoader requests. The tests don't need the global variable
wgResourceLoaderDebug anymore. The initial ResourceLoader context in
OutputPage still uses ResourceLoader::inDebugMode() with cookie and
global configuration variable.
This change adds the parameter $context with a ResourceLoaderContext
object to ResourceLoaderModule::getDeprecationInformation and deprecates
omitting the parameter. Ifa1a3bb56b731b83864022a358916c6aca5d7c10
updates this in extension ExtJSBase.
Bug: T229311
Change-Id: I5341f18625209446a6d006f60244990f65530319
The 'version' and 'modules' parameters are a somewhat problematic
part of the ResourceLoaderContext object as we often pass around
the context but may be dealing with only a subset of the modules
in the outer request, or even entirely different ones (e.g.
for OutputPage's fake context 'modules' and 'version' are both
null).
This is already visible in ClientHtml where we create a derivative
context just to call setModules() and have makeVersionQuery()
work. This is now fixed.
This change is in preparation for use in ResourceLoaderImage
(to fix T233343) where we'll need to compute a version for only
1 module of a larger set, and ideally without needing to create
another context.
Bug: T233343
Change-Id: Icc1a4fd1f58c4e49e58eee43ca4ba2de6cfffc76
* Add license header where missing.
* Add missing `@since` (1.17 for most classes), except
ResourceLoaderLessVarFileModule since 1.32 (1bc62c548c).
* Remove duplicate file-level description for class-only files,
merge with the class description instead.
* Remove my own `@author` annotation from one file.
* Mark core's own FileModule subclasses as `@internal`, except
for the following which we support use of in extensions:
ResourceLoaderLessVarFileModule,
ResourceLoaderOOUIIconPackModule, and
ResourceLoaderWikiModule.
Change-Id: I336af2e4ccdbe2512594e8861b72628d24194e41
In a nut shell:
* We very often (52% of modules on enwiki) pad the hash with a zero,
which means the amount of bits we currently compute already fit in
6 characters already for most modules. For some modules (3%) we
even padded two zeroes.
* For the (now documented) use cases, the space of 78 Giga
(78 billion, or 78 milliard) seems more than we need. The space of
60 million should be enough.
This follows-up dfd046412f from 2016, which previously shortened the hash
down from 8 chars of base 64 (or 12 chars of hex) to 7 chars of base 32.
Before that change, the space was 281 Tera (64^8, or 16^12).
For more details see the added inline comment for ResourceLoader::makeHash,
and also the data at <https://phabricator.wikimedia.org/T229245>.
Bug: T229245
Change-Id: I9ad11772a33b3a44cb625275b1d7353e1393ee49
* Add a test to confirm that the ResourceLoader::respond() logic
works as intended.
* Remove the client code for preventing it from being loaded.
This can never happen in production unless there is a bug.
Instead of optimising to avoid a pointless request that only
happens when the software is broken, instead optimise for when
the software is not broken by just letting it happen. The server
already handles it just fine.
This was originally added in 2015 with 1dd7390372 to reduce
logspam, but that was instead fixed in 6d6b037e12 by making the
log message debug-only (because it's not a software problem,
it's a client-error, e.g. a broken user script or a third
party trying out different things on the load.php entry point).
Removing this makes the client a bit smaller, too :)
Change-Id: Ic5420d9329a73514f4fc27baa46ae58d94addafb
The test-only modules registered by QUnitTestResources.php are currently
were previously caught by the array_keys() catch-all in registerTestModules()
which meant that modules like 'test.sinonjs' would be requested on
SpecialJavaScriptTest despite not doing anything by itself, nor executing
at the "right" time per se through this means.
In order for it to execute at the right time, the testrunner has to depend
on it (which it does, already). But, that also means it doesn't need to
be requested separately. Doing so could be confusing.
This is neccecary in order to move 'jquery.qunit' from Resources.php
to QUnitTestResources.php as otherwise, listing in QUnitTestResources.php,
would implicitly mean SpecialJavaScriptTest.php thinks it's a test suite
and load it. That is a problem, because when we run the tests headless from
the command-line with Karma, the environment already has a QUnit interface
defined, and should not be loaded a second time by MW.
Change-Id: I08b31cd1dee516cf0d26bafdb8cc7c1223633bad
Also avoid conditional existence of variables ($fileCache). This avoids
isset(), which means we won't hide problems during refactor.
Raised by Codehealth (sonarcloud.io) as Major Code Smell:
> Merge this if statement with the enclosing one.
> https://sonarcloud.io/organizations/wmftest/rules?open=php%3AS1066&rule_key=php%3AS1066
Change-Id: Iacebbe6a68dac46cdfd1415a33a547d105b24b98
I added this 7.5 years ago with r111378 (5bf04171dc), but I can't
recall what this would have been for. Perhaps we wanted to expose
the list of modules (or test frameworks) via ApiQuerySiteInfo, but
I don't know why, or what purpose it would serve.
Change-Id: I4005979252533a752178e6f1ac9900f32132c27e
This was done as a "clever" shortcut to make sure tests a little
but shorter, but also made them less consistent with normal code.
Remove this in favour of 'class' or 'factory' options as needed.
Also remove a bunch of unneeded register() calls.
The tests cover everything affected by this change.
Side fix - isFileModule should reject modules with 'factory'
the same way it rejected raw objects and non-FileModule 'class'
cases already. This is now covered by tests as well.
Bug: T222637
Change-Id: I3996317dbcd780cc6e0f82c84e769c08a3fc42bb
Being a raw module means that when it is requested from load.php with
"only=scripts" set, then the output is *not* wrapped in an
'mw.loader.implement' closure *and* there no 'mw.loader.state()' appendix.
Instead, it is served "raw".
Before 2018, the modules 'mediawiki' and 'jquery' were raw modules.
They were needed before the client could define 'mw.loader.implement', and
could never be valid dependencies. Module 'mediawiki' merged to 'startup',
and 'jquery' became a regular module (T192623). Based on the architecture
of modules being deliverable bundles, it doesn't make sense for there to
ever be raw modules again. Anything that 'startup' needs should be bundled
with it. Anything else is a regular module.
On top of that, we never actually needed this feature because specifying
the 'only=scripts' and 'raw=1' parameters does the same thing.
The only special bit about marking modules (not requests) as "raw" was that
it allowed the client to forget to specify "raw=1" and the server would
automatically omit the 'mw.loader.state()' appendix based on whether the
module is marked as raw. As of Ie4564ec8e26ad53f2, the two remaining use
cases for raw responses now specify the 'raw=1' request parameter, and we
can get rid of the "raw module" feature and all the complexity around it.
== Startup module
In the startup module there was an interesting use of isRaw() that has
little to do with the above. The "ATTENTION" warning there applies to the
startup module only, not raw modules in general. This is now fixed by
explicitly checking for StartupModule.
Above that warning, it talked about saving bytes, which was an optimisation
given that "raw" modules don't communicate with mw.loader, they also don't
need to be registered there because even if mw.loader would try to load
them, the server would never inform mw.loader about the module having
arrived. There are now no longer any such modules.
Bug: T201483
Change-Id: I8839036e7b2b76919b6cd3aa42ccfde4d1247899