From: Aryeh Gregor Date: Fri, 3 Aug 2018 08:25:15 +0000 (+0300) Subject: Introduce ParserFactory service X-Git-Tag: 1.34.0-rc.0~4493 X-Git-Url: http://git.cyclocoop.org/%22%2C%20generer_url_ecrire%28?a=commitdiff_plain;h=62515f7b15571317a5053a70a4ae316e10cef659;p=lhc%2Fweb%2Fwiklou.git Introduce ParserFactory service Bug: T200881 Change-Id: I257e78200983cb10afb76de1f07dd1b9d531c52a --- diff --git a/autoload.php b/autoload.php index e02a743a10..feddcddd0b 100644 --- a/autoload.php +++ b/autoload.php @@ -1078,6 +1078,7 @@ $wgAutoloadLocalClasses = [ 'Parser' => __DIR__ . '/includes/parser/Parser.php', 'ParserCache' => __DIR__ . '/includes/parser/ParserCache.php', 'ParserDiffTest' => __DIR__ . '/includes/parser/ParserDiffTest.php', + 'ParserFactory' => __DIR__ . '/includes/parser/ParserFactory.php', 'ParserOptions' => __DIR__ . '/includes/parser/ParserOptions.php', 'ParserOutput' => __DIR__ . '/includes/parser/ParserOutput.php', 'ParsoidVirtualRESTService' => __DIR__ . '/includes/libs/virtualrest/ParsoidVirtualRESTService.php', diff --git a/includes/MediaWikiServices.php b/includes/MediaWikiServices.php index 080a7f94b0..79e55f8a18 100644 --- a/includes/MediaWikiServices.php +++ b/includes/MediaWikiServices.php @@ -39,6 +39,7 @@ use MimeAnalyzer; use ObjectCache; use Parser; use ParserCache; +use ParserFactory; use PasswordFactory; use ProxyLookup; use SearchEngine; @@ -682,6 +683,14 @@ class MediaWikiServices extends ServiceContainer { return $this->getService( 'ParserCache' ); } + /** + * @since 1.32 + * @return ParserFactory + */ + public function getParserFactory() { + return $this->getService( 'ParserFactory' ); + } + /** * @since 1.32 * @return PasswordFactory diff --git a/includes/ServiceWiring.php b/includes/ServiceWiring.php index 08f7d663dd..5b64a600a4 100644 --- a/includes/ServiceWiring.php +++ b/includes/ServiceWiring.php @@ -383,6 +383,15 @@ return [ ); }, + 'ParserFactory' => function ( MediaWikiServices $services ) : ParserFactory { + return new ParserFactory( + $services->getMainConfig()->get( 'ParserConf' ), + $services->getMagicWordFactory(), + $services->getContentLanguage(), + wfUrlProtocols() + ); + }, + 'PasswordFactory' => function ( MediaWikiServices $services ) : PasswordFactory { $config = $services->getMainConfig(); return new PasswordFactory( diff --git a/includes/parser/Parser.php b/includes/parser/Parser.php index 4073864d22..833e5c8e7f 100644 --- a/includes/parser/Parser.php +++ b/includes/parser/Parser.php @@ -263,13 +263,21 @@ class Parser { /** @var MagicWordFactory */ private $magicWordFactory; + /** @var Language */ + private $contLang; + /** - * @param array $conf + * @param array $conf See $wgParserConf documentation * @param MagicWordFactory|null $magicWordFactory + * @param Language|null $contLang Content language + * @param string|null $urlProtocols As returned from wfUrlProtocols() */ - public function __construct( $conf = [], MagicWordFactory $magicWordFactory = null ) { + public function __construct( + array $conf = [], MagicWordFactory $magicWordFactory = null, Language $contLang = null, + $urlProtocols = null + ) { $this->mConf = $conf; - $this->mUrlProtocols = wfUrlProtocols(); + $this->mUrlProtocols = $urlProtocols ?? wfUrlProtocols(); $this->mExtLinkBracketedRegex = '/\[(((?i)' . $this->mUrlProtocols . ')' . self::EXT_LINK_ADDR . self::EXT_LINK_URL_CLASS . '*)\p{Zs}*([^\]\\x00-\\x08\\x0a-\\x1F\\x{FFFD}]*?)\]/Su'; @@ -289,10 +297,10 @@ class Parser { } wfDebug( __CLASS__ . ": using preprocessor: {$this->mPreprocessorClass}\n" ); - $this->magicWordFactory = $magicWordFactory; - if ( !$magicWordFactory ) { - $this->magicWordFactory = MediaWikiServices::getInstance()->getMagicWordFactory(); - } + $this->magicWordFactory = $magicWordFactory ?? + MediaWikiServices::getInstance()->getMagicWordFactory(); + + $this->contLang = $contLang ?? MediaWikiServices::getInstance()->getContentLanguage(); } /** @@ -972,7 +980,7 @@ class Parser { * @return Language */ public function getContentLanguage() { - return $this->magicWordFactory->getContentLanguage(); + return $this->contLang; } /** @@ -2154,7 +2162,7 @@ class Parser { if ( $useLinkPrefixExtension ) { # Match the end of a line for a word that's not followed by whitespace, # e.g. in the case of 'The Arab al[[Razi]]', 'al' will be matched - $charset = $this->getContentLanguage()->linkPrefixCharset(); + $charset = $this->contLang->linkPrefixCharset(); $e2 = "/^((?>.*[^$charset]|))(.+)$/sDu"; } @@ -2710,11 +2718,10 @@ class Parser { break; case 'namespace': $value = str_replace( '_', ' ', - $this->getContentLanguage()->getNsText( $this->mTitle->getNamespace() ) ); + $this->contLang->getNsText( $this->mTitle->getNamespace() ) ); break; case 'namespacee': - $value = wfUrlencode( $this->getContentLanguage()-> - getNsText( $this->mTitle->getNamespace() ) ); + $value = wfUrlencode( $this->contLang->getNsText( $this->mTitle->getNamespace() ) ); break; case 'namespacenumber': $value = $this->mTitle->getNamespace(); @@ -2863,7 +2870,7 @@ class Parser { if ( !$this->getRevisionObject() ) { # Get the timezone-adjusted timestamp $mtts seconds in the future $resThen = substr( - $this->getContentLanguage()->userAdjust( wfTimestamp( TS_MW, time() + $mtts ), '' ), + $this->contLang->userAdjust( wfTimestamp( TS_MW, time() + $mtts ), '' ), $start, $len ); @@ -3415,7 +3422,7 @@ class Parser { $function = $this->mFunctionSynonyms[1][$function]; } else { # Case insensitive functions - $function = $this->getContentLanguage()->lc( $function ); + $function = $this->contLang->lc( $function ); if ( isset( $this->mFunctionSynonyms[0][$function] ) ) { $function = $this->mFunctionSynonyms[0][$function]; } else { @@ -4519,14 +4526,14 @@ class Parser { */ private function pstPass2( $text, $user ) { # Note: This is the timestamp saved as hardcoded wikitext to the database, we use - # $this->getContentLanguage() here in order to give everyone the same signature and use the - # default one rather than the one selected in each user's preferences. (see also T14815) + # $this->contLang here in order to give everyone the same signature and use the default one + # rather than the one selected in each user's preferences. (see also T14815) $ts = $this->mOptions->getTimestamp(); $timestamp = MWTimestamp::getLocalInstance( $ts ); $ts = $timestamp->format( 'YmdHis' ); $tzMsg = $timestamp->getTimezoneMessage()->inContentLanguage()->text(); - $d = $this->getContentLanguage()->timeanddate( $ts, false, false ) . " ($tzMsg)"; + $d = $this->contLang->timeanddate( $ts, false, false ) . " ($tzMsg)"; # Variable replacement # Because mOutputType is OT_WIKI, this will only process {{subst:xxx}} type tags @@ -4892,7 +4899,7 @@ class Parser { foreach ( $synonyms as $syn ) { # Case if ( !$sensitive ) { - $syn = $this->getContentLanguage()->lc( $syn ); + $syn = $this->contLang->lc( $syn ); } # Add leading hash if ( !( $flags & self::SFH_NO_HASH ) ) { @@ -5736,7 +5743,7 @@ class Parser { # Since this value will be saved into the parser cache, served # to other users, and potentially even used inside links and such, # it needs to be consistent for all visitors. - $this->mRevisionTimestamp = $this->getContentLanguage()->userAdjust( $timestamp, '' ); + $this->mRevisionTimestamp = $this->contLang->userAdjust( $timestamp, '' ); } return $this->mRevisionTimestamp; diff --git a/includes/parser/ParserFactory.php b/includes/parser/ParserFactory.php new file mode 100644 index 0000000000..7b66f9c6db --- /dev/null +++ b/includes/parser/ParserFactory.php @@ -0,0 +1,63 @@ +conf = $conf; + $this->magicWordFactory = $magicWordFactory; + $this->contLang = $contLang; + $this->urlProtocols = $urlProtocols; + } + + /** + * @return Parser + * @since 1.32 + */ + public function create() : Parser { + return new Parser( $this->conf, $this->magicWordFactory, $this->contLang, + $this->urlProtocols ); + } +} diff --git a/tests/phpunit/includes/parser/ParserFactoryTest.php b/tests/phpunit/includes/parser/ParserFactoryTest.php new file mode 100644 index 0000000000..55a1af47e2 --- /dev/null +++ b/tests/phpunit/includes/parser/ParserFactoryTest.php @@ -0,0 +1,54 @@ +assertSame( $instanceConstructor->getNumberOfParameters(), + $factoryConstructor->getNumberOfParameters(), + 'Parser and ParserFactory constructors have an inconsistent number of parameters. ' . + 'Did you add a parameter to one and not the other?' ); + } + + public function testAllArgumentsWerePassed() { + $factoryConstructor = new ReflectionMethod( 'ParserFactory', '__construct' ); + $mocks = []; + foreach ( $factoryConstructor->getParameters() as $param ) { + $type = (string)$param->getType(); + if ( $type === 'array' ) { + $val = [ 'porcupines will tell me your secrets' . count( $mocks ) ]; + } elseif ( class_exists( $type ) || interface_exists( $type ) ) { + $val = $this->createMock( $type ); + } elseif ( $type === '' ) { + // Optimistically assume a string is okay + $val = 'I will de-quill them first' . count( $mocks ); + } else { + $this->fail( "Unrecognized parameter type $type in ParserFactory constructor" ); + } + $mocks[] = $val; + } + + $factory = new ParserFactory( ...$mocks ); + $parser = $factory->create(); + + foreach ( ( new ReflectionObject( $parser ) )->getProperties() as $prop ) { + $prop->setAccessible( true ); + foreach ( $mocks as $idx => $mock ) { + if ( $prop->getValue( $parser ) === $mock ) { + unset( $mocks[$idx] ); + } + } + } + + $this->assertCount( 0, $mocks, 'Not all arguments to the ParserFactory constructor were ' . + 'found in Parser member variables' ); + } +}