2023/06/24
|
Saturday, June 24, 2023 (#175)
|
|
References |
Notes
- SpecialPageFactory.php line 1449 (was 1318) calls $this->getPage( $name );
- SpecialPageFactory.php line 1411 (was 1283) calls
$this->objectFactory->createObject($rec,['allowClassName' => true,'allowCallable' => true]);- This seems to be where the problem comes in:
- $rec is supposed to be an array or a string that matches certain criteria.
$rec = $specialPageList[$realName];[ $realName ] = $this->resolveAlias( $name );// extracts $realName from the first item returned (the "real name" is always first, I guess... seems a bit sloppy)
- This seems to be where the problem comes in:
- ObjectFactory.php line 152 calls static::getObjectFromSpec( $spec, $options );
- ObjectFactory.php line 177 calls static::validateSpec( $spec, $options );
- ObjectFactory.php line 302 is in validateSpec( $spec, array $options ), throws exception
the problem flows like this: in this->getPage( $name ); we have
if ( is_array( $rec ) || is_string( $rec ) || is_callable( $rec ) ) {
$page = $this->objectFactory->createObject( $rec, [ 'allowClassName' => true,'allowCallable' => true ]);
}
...which implies that it should be perfectly okay to call createObject() with a string, but then we have createObject( $spec, array $options = [] ) calling static::getObjectFromSpec( $spec, $options ); which calls static::validateSpec( $spec, $options ); which then goes:
if ( is_string( $spec ) && class_exists( $spec ) ) {
if ( empty( $options['allowClassName'] ) ) {
throw new InvalidArgumentException('Passing a raw class name is not allowed here. Use [ \'class\' => $classname ] instead.');
}
return [ 'class' => $spec ];
}
if ( !is_array( $spec ) ) {
throw new InvalidArgumentException( 'Provided specification is not an array.' );
}
...so I think what I'm getting from that is that it's only okay to call $this->objectFactory->createObject( $rec, /*...*/ ) if $rec is not a class name.
So then we have the questions:
- Q1: From where is the string-value of $rec being retrieved?
- The list comes from
$this->getPageList() - ...and how that list is generated is... Complicated.
- ...but there's a wide variety of examples, when CORE_LIST is defined near the top of the class, of what the array entries are supposed to look like.
- Q1a: So, somehow our SpecialPage class gets added to the list as just a string. Where does that happen? Presumably in SpecialPage's constructor...
- Nope, not there; that just initializes the SpecialPage object's members. Presumably the class is registered by whatever reads the extension.json file.
- Q1a1: How are extension pages loaded?
- The list comes from
- Q2: What is it supposed to be, if it's not a class name?
I don't know the answer to the above questions, but I did solve the problem: as implied on Manual:Special_pages, the filename must match the class name -- so it can't be just Special.php, it has to be SpecialClassInspector.php. (Maybe there's some configuration detail you can put in extension.json to override this, but I don't currently know what that is if it exists.)
2023-07-09 update: I got this same error again -- this time because of a namespace change. Fixing the extension.json file to have the correct namespace fixed the problem. I conclude (from these two data-points) that this error indicates that the class of the SpecialPage does not match the class referenced in extension.json.