Now that the ObjectFactory library supports object creation with
services (T222409), the special page factory can use the object
factory to create special pages based off a spec, allowing the
creation of special pages that need services injected.
The object factory now also handles constructing from class name
and from callable.
This also deprecates providing the special page list with an
instance of SpecialPage, which hasn't been necessary since
r15031.
Bug: T222388
Change-Id: Iabb78ce5c98cfb3b586644be35d984871cb750cb
GetBlockedStatus.
* ObjectFactory is available as a service. When used as a service, the object
specs can now specify needed DI services.
GetBlockedStatus.
* ObjectFactory is available as a service. When used as a service, the object
specs can now specify needed DI services.
+* (T222388) Special pages can now be specified as an ObjectFactory spec,
+ allowing the construction of special pages that require services to be
+ injected in their constructor.
=== External library changes in 1.34 ===
=== External library changes in 1.34 ===
or extend RevisionSearchResult.
* Skin::getSkinNameMessages() is deprecated and no longer used.
* The mediawiki.RegExp module is deprecated; use mw.util.escapeRegExp() instead.
or extend RevisionSearchResult.
* Skin::getSkinNameMessages() is deprecated and no longer used.
* The mediawiki.RegExp module is deprecated; use mw.util.escapeRegExp() instead.
+* Specifying a SpecialPage object for the list of special pages (either through
+ the SpecialPage_initList hook or by adding to $wgSpecialPages) is now
+ deprecated.
=== Other changes in 1.34 ===
* …
=== Other changes in 1.34 ===
* …
},
"SpecialPages": {
"type": "object",
},
"SpecialPages": {
"type": "object",
- "description": "SpecialPages implemented in this extension (mapping of page name to class name)"
+ "description": "SpecialPages implemented in this extension (mapping of page name to class name or to ObjectFactory spec)"
},
"AutoloadNamespaces": {
"type": "object",
},
"AutoloadNamespaces": {
"type": "object",
},
"SpecialPages": {
"type": "object",
},
"SpecialPages": {
"type": "object",
- "description": "SpecialPages implemented in this extension (mapping of page name to class name)"
+ "description": "SpecialPages implemented in this extension (mapping of page name to class name or to ObjectFactory spec)"
},
"AutoloadNamespaces": {
"type": "object",
},
"AutoloadNamespaces": {
"type": "object",
return new SpecialPageFactory(
new ServiceOptions(
SpecialPageFactory::$constructorOptions, $services->getMainConfig() ),
return new SpecialPageFactory(
new ServiceOptions(
SpecialPageFactory::$constructorOptions, $services->getMainConfig() ),
- $services->getContentLanguage()
+ $services->getContentLanguage(),
+ $services->getObjectFactory()
use SpecialPage;
use Title;
use User;
use SpecialPage;
use Title;
use User;
+use Wikimedia\ObjectFactory;
/**
* Factory for handling the special page list and generating SpecialPage objects.
/**
* Factory for handling the special page list and generating SpecialPage objects.
/** @var Language */
private $contLang;
/** @var Language */
private $contLang;
+ /** @var ObjectFactory */
+ private $objectFactory;
+
/**
* TODO Make this a const when HHVM support is dropped (T192166)
*
/**
* TODO Make this a const when HHVM support is dropped (T192166)
*
/**
* @param ServiceOptions $options
* @param Language $contLang
/**
* @param ServiceOptions $options
* @param Language $contLang
+ * @param ObjectFactory $objectFactory
- public function __construct( ServiceOptions $options, Language $contLang ) {
+ public function __construct(
+ ServiceOptions $options,
+ Language $contLang,
+ ObjectFactory $objectFactory
+ ) {
$options->assertRequiredOptions( self::$constructorOptions );
$this->options = $options;
$this->contLang = $contLang;
$options->assertRequiredOptions( self::$constructorOptions );
$this->options = $options;
$this->contLang = $contLang;
+ $this->objectFactory = $objectFactory;
if ( isset( $specialPageList[$realName] ) ) {
$rec = $specialPageList[$realName];
if ( isset( $specialPageList[$realName] ) ) {
$rec = $specialPageList[$realName];
- if ( is_callable( $rec ) ) {
- // Use callback to instantiate the special page
- $page = $rec();
- } elseif ( is_string( $rec ) ) {
- $className = $rec;
- $page = new $className;
- } elseif ( $rec instanceof SpecialPage ) {
+ if ( $rec instanceof SpecialPage ) {
+ wfDeprecated(
+ "a SpecialPage instance (for $realName) in " .
+ '$wgSpecialPages or from the SpecialPage_initList hook',
+ '1.34'
+ );
+
$page = $rec; // XXX: we should deep clone here
$page = $rec; // XXX: we should deep clone here
+ } elseif ( is_array( $rec ) || is_string( $rec ) || is_callable( $rec ) ) {
+ $page = $this->objectFactory->createObject(
+ $rec,
+ [
+ 'allowClassName' => true,
+ 'allowCallable' => true
+ ]
+ );
'callback array' => [
[ 'SpecialPageTestHelper', 'newSpecialAllPages' ],
false
'callback array' => [
[ 'SpecialPageTestHelper', 'newSpecialAllPages' ],
false
+ ],
+ 'object factory spec' => [
+ [ 'class' => SpecialAllPages::class ],
+ false
$this->assertTrue( $called, 'Recursive call succeeded' );
}
$this->assertTrue( $called, 'Recursive call succeeded' );
}
+ /**
+ * @covers \MediaWiki\Special\SpecialPageFactory::getPage
+ */
+ public function testSpecialPageCreationThatRequiresService() {
+ $type = null;
+
+ $this->setMwGlobals( 'wgSpecialPages',
+ [ 'TestPage' => [
+ 'factory' => function ( $spf ) use ( &$type ) {
+ $type = get_class( $spf );
+
+ return new class() extends SpecialPage {
+
+ };
+ },
+ 'services' => [
+ 'SpecialPageFactory'
+ ]
+ ] ]
+ );
+
+ SpecialPageFactory::getPage( 'TestPage' );
+
+ $this->assertEquals( \MediaWiki\Special\SpecialPageFactory::class, $type );
+ }