diff --git a/.github/workflows/codacy.yml b/.github/workflows/codacy.yml index 6da719e5f..18f61c9bd 100644 --- a/.github/workflows/codacy.yml +++ b/.github/workflows/codacy.yml @@ -15,10 +15,10 @@ name: Codacy Security Scan on: push: - branches: [ master ] + branches: [ main ] pull_request: # The branches below must be a subset of the branches above - branches: [ master ] + branches: [ main ] schedule: - cron: '31 7 * * 0' diff --git a/.github/workflows/mediawiki-tests.yml b/.github/workflows/mediawiki-tests.yml index 72332740e..7221ef14d 100644 --- a/.github/workflows/mediawiki-tests.yml +++ b/.github/workflows/mediawiki-tests.yml @@ -2,9 +2,9 @@ name: Quibble and Phan on: push: - branches: [ master ] + branches: [ main ] pull_request: - branches: [ master ] + branches: [ main ] jobs: test: @@ -13,13 +13,20 @@ jobs: strategy: matrix: include: - # Latest stable MediaWiki - PHP 8.1 (phan) + # Latest MediaWiki LTS - PHP 8.1 (phan) - mw: 'REL1_43' php: 8.1 php-docker: 81 experimental: false stage: phan + # Latest stable MediaWiki - PHP 8.1 (phan) + - mw: 'REL1_44' + php: 8.1 + php-docker: 81 + experimental: true + stage: phan + # Latest MediaWiki master - PHP 8.1 (phan) - mw: 'master' php: 8.1 @@ -27,19 +34,26 @@ jobs: experimental: true stage: phan - # Latest MediaWiki master - PHP 7.4 (coverage) + # Latest MediaWiki master - PHP 8.1 (coverage) - mw: 'master' - php: 7.4 - php-docker: 74 + php: 8.1 + php-docker: 81 experimental: false stage: coverage - # Latest stable MediaWiki - PHP 8.1 (phpunit) + # Latest MediaWiki LTS - PHP 8.1 (phpunit) - mw: 'REL1_43' php: 8.1 php-docker: 81 experimental: false stage: phpunit + + # Latest stable MediaWiki - PHP 8.1 (phpunit) + - mw: 'REL1_44' + php: 8.1 + php-docker: 81 + experimental: false + stage: phpunit # Latest MediaWiki master - PHP 8.1 (phpunit) - mw: 'master' @@ -74,8 +88,8 @@ jobs: env: DOCKER_REGISTRY: docker-registry.wikimedia.org DOCKER_ORG: releng - QUIBBLE_DOCKER_IMAGE: quibble-buster-php${{ matrix.php-docker }} - COVERAGE_DOCKER_IMAGE: quibble-buster-php${{ matrix.php-docker }}-coverage + QUIBBLE_DOCKER_IMAGE: quibble-bullseye-php${{ matrix.php-docker }} + COVERAGE_DOCKER_IMAGE: quibble-bullseye-php${{ matrix.php-docker }}-coverage PHAN_DOCKER_IMAGE: mediawiki-phan-php${{ matrix.php-docker }} MEDIAWIKI_VERSION: ${{ matrix.mw }} @@ -121,7 +135,7 @@ jobs: curl -sL https://raw.githubusercontent.com/wikimedia/integration-config/master/zuul/dependencies.yaml -o dependencies.yaml curl -sL https://raw.githubusercontent.com/wikimedia/integration-config/master/zuul/phan_dependencies.yaml -o phan_dependencies.yaml curl -sL https://raw.githubusercontent.com/wikimedia/integration-config/master/zuul/parameter_functions.py -o pf.py - curl -sL https://raw.githubusercontent.com/miraheze/ci-scripts/master/mediawiki/resolve_dependencies.py -o rd.py + curl -sL https://raw.githubusercontent.com/miraheze/ci-scripts/main/mediawiki/resolve_dependencies.py -o rd.py if [ -e dependencies ]; then echo "DEPENDENCIES=$(python3 rd.py dependencies)" >> $GITHUB_ENV fi diff --git a/.phan/config.php b/.phan/config.php index ef42493cc..bd77d0505 100644 --- a/.phan/config.php +++ b/.phan/config.php @@ -2,6 +2,8 @@ $cfg = require __DIR__ . '/../vendor/mediawiki/mediawiki-phan-config/src/config.php'; +$cfg['minimum_target_php_version'] = '8.1'; + $cfg['directory_list'] = array_merge( $cfg['directory_list'], [ '../../extensions/Variables', diff --git a/CHANGELOG.md b/CHANGELOG.md index 472ba899e..39673cf5d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -838,3 +838,22 @@ Many thanks to GreenReaper on GitHub for reporting and finding issues with core * Replaced the deprecated `ExtVariables::VERSION` with using `ExtensionRegistry` to check if the Variables extension is installed. * Replaced usages of `intval()` with `(int)` in all remaining places within this extension. This was started in version 3.5.0 and completed in this version. * Replaced usages of `boolval()` with `(bool)` throughout the entire extension. + +# Version 3.6.2 +* Fixed Heading's attribute setters (hlistattr, hitemattr may be null). +* Restored partial support for `linkstoexternal` and introduced replacement via `linkstoexternaldomain` and `linkstoexternalpath`. +* Fixed type mismatch between what is returned by `getLinkList` (list of arrays that contained non-serializable TitleValue) and what is expected by ParserOutput. + +# Version 3.6.3 +* Applied some performance improvements to LST from downstream (which added the new configuration option `$wgDplSettings['recursivePreprocess']`). +* Now shows raw query exception if the request is not made. +* Fixed CI compatibility with PHP 8.1 (which upstream MediaWiki master now requires). +* Added REL1_44 to CI. +* Fixed tests, replacing `ParserOutput::getText` with `ParserOutput::getContentHolderText`. +* Removed `Query::getTableNames` and associated properties, replacing calls with `$this->dbr->tableName`. +* Fixed compatability with upstream backported changes to use raw table names where necessary (by passing the second parameter of `$this->dbr->tableName` as `'raw'` where needed). + +# Version 3.6.4 +* Fixed a PHP warning in `nottitleregexp` (uninitialised array/key). +* Removed some unused parameters, methods, and variables. +* SECURITY: Fixed leakage of hidden/suppressed usernames ([GHSA-7pgw-q3qp-6pgq](https://github.com/Universal-Omega/DynamicPageList3/security/advisories/GHSA-7pgw-q3qp-6pgq)). diff --git a/README.md b/README.md index 7ab50abe9..809ba0759 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,8 @@ These are DPL3's configuration settings and along with their default values. To | $wgDplSettings['maxCategoryCount'] | 4 | Maximum number of categories to allow in queries. | | $wgDplSettings['minCategoryCount'] | 0 | Minimum number of categories to allow in queries. | | $wgDplSettings['maxResultCount'] | 500 | Maximum number of results to return from a query. | -| $wgDplSettings['recursiveTagParse'] | false | Do recursive tag parsing on parser tags converting tags and functions such as magic words like {{PAGENAME}}. This is similar to the {{#dpl}} parser function call, but may not work exactly the same in all cases. | +| $wgDplSettings['recursiveTagParse'] | false | Do recursive tag parsing on parser tags converting tags and functions such as magic words like {{PAGENAME}}. This is similar to the {{#dpl}} parser function call, but may not work exactly the same in all cases. | +| $wgDplSettings['recursivePreprocess'] | false | Use `Parser::recursivePreprocess()` to improve performance by preserving the internal cache, reducing redundant template parsing. | | $wgDplSettings['runFromProtectedPagesOnly'] | false | Set this to true to allow DPL3 to run from protected pages only. This is recommend if wiki administrators are having issues with malicious users creating computationally intensive queries. | | $wgDplSettings['handleSectionTag'] | false | Set this to true to have DPL3 handle
tags outside of the parser tags provided by DPL3. | | $wgDplSettings['maxQueryTime'] | 10000 | Maximum allowed time for database queries in milliseconds. | diff --git a/composer.json b/composer.json index 442b62819..ccbde3bf3 100644 --- a/composer.json +++ b/composer.json @@ -8,8 +8,8 @@ "composer/installers": ">=1.0.1" }, "require-dev": { - "mediawiki/mediawiki-codesniffer": "46.0.0", - "mediawiki/mediawiki-phan-config": "0.15.1", + "mediawiki/mediawiki-codesniffer": "47.0.0", + "mediawiki/mediawiki-phan-config": "0.16.0", "mediawiki/minus-x": "1.1.3", "php-parallel-lint/php-console-highlighter": "1.0.0", "php-parallel-lint/php-parallel-lint": "1.4.0" diff --git a/extension.json b/extension.json index 0125ce1cc..d82d4efc9 100644 --- a/extension.json +++ b/extension.json @@ -1,6 +1,6 @@ { "name": "DynamicPageList3", - "version": "3.6.1", + "version": "3.6.4", "author": [ "'''Universal Omega'''", "Alexia E. Smith", @@ -58,6 +58,7 @@ "minCategoryCount": 0, "maxResultCount": 500, "recursiveTagParse": false, + "recursivePreprocess": false, "runFromProtectedPagesOnly": false, "handleSectionTag": false, "alwaysCacheResults": false, diff --git a/i18n/de.json b/i18n/de.json index 63c9f0f0e..2cc1ddbb2 100644 --- a/i18n/de.json +++ b/i18n/de.json @@ -5,6 +5,7 @@ "Justman10000", "Magiczocker", "MarkusRost", + "Talex42", "TomatoCake" ] }, diff --git a/includes/Article.php b/includes/Article.php index 454d66d79..eb0aa60a8 100644 --- a/includes/Article.php +++ b/includes/Article.php @@ -4,6 +4,7 @@ use MediaWiki\Context\RequestContext; use MediaWiki\MediaWikiServices; +use MediaWiki\Revision\RevisionRecord; use MediaWiki\Title\Title; use MediaWiki\User\ActorStore; use stdClass; @@ -211,8 +212,11 @@ public static function newFromRow( $article = new self( $title, $pageNamespace ); $revActorName = ActorStore::UNKNOWN_USER_NAME; - if ( isset( $row->rev_actor ) && $row->rev_actor !== '0' ) { - $revActorName = $userFactory->newFromActorId( $row->rev_actor )->getName(); + if ( isset( $row->rev_actor ) && (int)$row->rev_actor !== 0 ) { + $revUser = $userFactory->newFromActorId( $row->rev_actor ); + $revUserDeleted = $row->rev_deleted & RevisionRecord::DELETED_USER; + $revActorName = $revUser->isHidden() || $revUserDeleted ? + wfMessage( 'rev-deleted-user' )->escaped() : $revUser->getName(); } $titleText = $title->getText(); @@ -342,9 +346,10 @@ public static function newFromRow( // CONTRIBUTION, CONTRIBUTOR if ( $parameters->getParameter( 'addcontribution' ) ) { $article->mContribution = $row->contribution; - - $article->mContributor = $userFactory->newFromActorId( $row->contributor )->getName(); - + $contribUser = $userFactory->newFromActorId( $row->contributor ); + $contribUserDeleted = $row->contrib_deleted & RevisionRecord::DELETED_USER; + $article->mContributor = $contribUser->isHidden() || $contribUserDeleted ? + wfMessage( 'rev-deleted-user' )->escaped() : $contribUser->getName(); $article->mContrib = substr( '*****************', 0, (int)round( log( $row->contribution ) ) ); } diff --git a/includes/Config.php b/includes/Config.php index bd92e5f50..c3e95026e 100644 --- a/includes/Config.php +++ b/includes/Config.php @@ -2,7 +2,7 @@ namespace MediaWiki\Extension\DynamicPageList3; -use ConfigException; +use MediaWiki\Config\ConfigException; class Config { /** diff --git a/includes/ExternalDomainPatternParser.php b/includes/ExternalDomainPatternParser.php index e5d15d878..8c37b47cc 100644 --- a/includes/ExternalDomainPatternParser.php +++ b/includes/ExternalDomainPatternParser.php @@ -2,8 +2,6 @@ namespace MediaWiki\Extension\DynamicPageList3; -use MediaWiki\Extension\DynamicPageList3\Tests\DPLExternalDomainPatternParserTest; - trait ExternalDomainPatternParser { /** * We provide: @@ -11,17 +9,17 @@ trait ExternalDomainPatternParser { * * partial support for wildcard usage when it is not separated by `.` (eg. `%fandom.com would match starwars.fandom-suffix.com) * * protocols followed by the `://` are supported, like `http://` or `https://` (`mailto:` on the other hand is not supported) * - * @See DPLExternalDomainPatternParserTest for example cases + * @see DPLExternalDomainPatternParserTest for example cases */ private function parseDomainPattern( string $pattern ): string { $protocol = false; // Protocol is specified. Strip it if ( str_contains( $pattern, '://' ) ) { - [$protocol, $pattern] = explode( '://', $pattern ); + [ $protocol, $pattern ] = explode( '://', $pattern ); } // Previous step will strip protocol if it was specified - [$domainPattern, ] = explode( '/', $pattern, 2 ); + [ $domainPattern, ] = explode( '/', $pattern, 2 ); $parts = explode( '.', $domainPattern ); $reversed = array_reverse( $parts ); foreach ( $reversed as &$part ) { @@ -30,7 +28,7 @@ private function parseDomainPattern( string $pattern ): string { } if ( str_starts_with( $part, '%' ) ) { $part .= '%'; - } else if ( str_ends_with( $part, '%' ) ) { + } elseif ( str_ends_with( $part, '%' ) ) { $part = '%' . $part; } } diff --git a/includes/Heading/Heading.php b/includes/Heading/Heading.php index c1a49d6e5..bb07fed10 100644 --- a/includes/Heading/Heading.php +++ b/includes/Heading/Heading.php @@ -177,8 +177,6 @@ public function format( $articles, Lister $lister ) { $rowSize = $this->getParameters()->getParameter( 'rowsize' ); $rowColFormat = $this->getParameters()->getParameter( 'rowcolformat' ); - $count = 0; - $headings = Article::getHeadings(); $output = ''; @@ -212,7 +210,6 @@ public function format( $articles, Lister $lister ) { $output .= $this->getListStart(); $nstart = 0; $greml = $nsize; - $g = 0; $offset = 0; foreach ( $headings as $headingCount ) { $headingStart = $nstart - $offset; @@ -247,8 +244,6 @@ public function format( $articles, Lister $lister ) { $output .= "\n|-\n|\n"; } - ++$g; - if ( $nstart + $nsize > $count ) { $nsize = $count - $nstart; } diff --git a/includes/Hooks.php b/includes/Hooks.php index 519977f78..39a2e6197 100644 --- a/includes/Hooks.php +++ b/includes/Hooks.php @@ -200,7 +200,7 @@ public static function dplTag( $input, array $args, Parser $parser, PPFrame $fra * The callback function wrapper for converting the input text to HTML output * * @param string $input - * @param array $args + * @param array $args @phan-unused-param * @param Parser $parser * @param PPFrame $frame * @return string @@ -308,7 +308,7 @@ public static function dplNumParserFunction( $parser, $text = '' ) { $parser->addTrackingCategory( 'dplnum-parserfunc-tracking-category' ); $num = str_replace( ' ', ' ', $text ); - $num = str_replace( ' ', ' ', $text ); + $num = str_replace( ' ', ' ', $num ); $num = preg_replace( '/([0-9])([.])([0-9][0-9]?[^0-9,])/', '\1,\3', $num ); $num = preg_replace( '/([0-9.]+),([0-9][0-9][0-9])\s*Mrd/', '\1\2 000000 ', $num ); $num = preg_replace( '/([0-9.]+),([0-9][0-9])\s*Mrd/', '\1\2 0000000 ', $num ); @@ -420,7 +420,7 @@ public static function dplChapterParserFunction( ) { $parser->addTrackingCategory( 'dplchapter-parserfunc-tracking-category' ); $output = LST::extractHeadingFromText( - $parser, $page, '?title?', $text, $heading, '', + $parser, $page, $text, $heading, '', $sectionHeading, true, $maxLength, $link, $trim ); return $output[0]; @@ -514,8 +514,7 @@ public static function dplMatrixParserFunction( foreach ( $targets as $to => $toName ) { $targets[$to] = "[[$to|$toName]]"; - - foreach ( $sources as $from => $fromName ) { + foreach ( $sources as $from => $_ ) { if ( array_key_exists( $to, $m[$from] ) ) { $targets[$to] .= "\n|$yes"; } else { @@ -534,8 +533,7 @@ public static function dplMatrixParserFunction( foreach ( $sources as $from => $fromName ) { $sources[$from] = "[[$from|$fromName]]"; - - foreach ( $targets as $to => $toName ) { + foreach ( $targets as $to => $_ ) { if ( array_key_exists( $to, $m[$from] ) ) { $sources[$from] .= "\n|$yes"; } else { @@ -581,7 +579,7 @@ public static function getDebugLevel() { * Reset everything; some categories may have been fixed, however via fixcategory= * * @param Parser $parser - * @param string $text + * @param string $text @phan-unused-param */ public static function endReset( $parser, $text ) { if ( !self::$createdLinks['resetdone'] ) { @@ -622,7 +620,7 @@ public static function endEliminate( $parser, &$text ) { if ( self::$createdLinks ) { if ( array_key_exists( 0, self::$createdLinks ) ) { $parserLinks = $parser->getOutput()->mLinks; - foreach ( $parserLinks as $nsp => $link ) { + foreach ( $parserLinks as $nsp => $_ ) { if ( !array_key_exists( $nsp, self::$createdLinks[0] ) ) { continue; } @@ -641,7 +639,7 @@ public static function endEliminate( $parser, &$text ) { if ( array_key_exists( 1, self::$createdLinks ) ) { $parserTemplates = $parser->getOutput()->mTemplates; - foreach ( $parserTemplates as $nsp => $tpl ) { + foreach ( $parserTemplates as $nsp => $_ ) { if ( !array_key_exists( $nsp, self::$createdLinks[1] ) ) { continue; } diff --git a/includes/LST.php b/includes/LST.php index c8a257298..a304a6378 100644 --- a/includes/LST.php +++ b/includes/LST.php @@ -29,8 +29,13 @@ use MediaWiki\Extension\DynamicPageList3\Lister\Lister; use MediaWiki\MediaWikiServices; +use MediaWiki\Page\PageReference; use MediaWiki\Parser\Parser; +use MediaWiki\Parser\ParserOptions; +use MediaWiki\Parser\StripState; use MediaWiki\Title\Title; +use ReflectionClass; +use ReflectionException; class LST { @@ -91,7 +96,6 @@ public static function close( $parser, $part1 ) { * @param Parser $parser * @param string $text * @param string $part1 - * @param int $skiphead * @param bool $recursionCheck * @param int $maxLength * @param string $link @@ -103,7 +107,6 @@ private static function parse( $parser, $text, $part1, - $skiphead = 0, $recursionCheck = true, $maxLength = -1, $link = '', @@ -149,13 +152,11 @@ private static function parse( * Generate a regex to match the section(s) we're interested in. * * @param string $sec - * @param string $to * @param bool &$any * @return string */ - private static function createSectionPattern( $sec, $to, &$any ) { + private static function createSectionPattern( $sec, &$any ) { $any = false; - $to_sec = ( $to == '' ) ? $sec : $to; if ( $sec[0] == '*' ) { $any = true; @@ -168,16 +169,6 @@ private static function createSectionPattern( $sec, $to, &$any ) { $sec = preg_quote( $sec, '/' ); } - if ( $to_sec[0] == '*' ) { - if ( $to_sec == '**' ) { - $to_sec = '[^\/>"' . "']+"; - } else { - $to_sec = str_replace( '/', '\/', substr( $to_sec, 1 ) ); - } - } else { - $to_sec = preg_quote( $to_sec, '/' ); - } - $ws = "(?:\s+[^>]+)?"; return "//s"; } - /** - * Count headings in skipped text. - * - * Count skipped headings, so parser can skip them, to - * prevent wrong heading links. - * - * @param string $text - * @param int $limit Cutoff point in the text to stop searching - * @return int Number of matches - */ - private static function countHeadings( $text, $limit ) { - $pat = '^(={1,6}).+\1\s*$()'; - - $count = 0; - $offset = 0; - $m = []; - - while ( preg_match( "/$pat/im", $text, $m, PREG_OFFSET_CAPTURE, $offset ) ) { - if ( $m[2][1] > $limit ) { - break; - } - - $count++; - $offset = $m[2][1]; - } - - return $count; - } - /** * Fetches content of target page if valid and found, otherwise * produces wikitext of a link to the target page. @@ -249,7 +211,6 @@ public static function text( $parser, $page, &$title, &$text ) { * @param Parser $parser * @param string $page * @param string $sec - * @param string $to * @param bool $recursionCheck * @param bool $trim * @param array $skipPattern @@ -259,7 +220,6 @@ public static function includeSection( $parser, $page = '', $sec = '', - $to = '', $recursionCheck = true, $trim = false, $skipPattern = [] @@ -272,14 +232,14 @@ public static function includeSection( } $any = false; - $pat = self::createSectionPattern( $sec, $to, $any ); + $pat = self::createSectionPattern( $sec, $any ); preg_match_all( $pat, $text, $m, PREG_PATTERN_ORDER ); foreach ( $m[2] as $nr => $piece ) { $piece = self::parse( $parser, $piece, "#lst:{$page}|{$sec}", - 0, $recursionCheck, -1, '', $trim, $skipPattern + $recursionCheck, -1, '', $trim, $skipPattern ); if ( $any ) { @@ -450,15 +410,13 @@ public static function includeHeading( if ( self::text( $parser, $page, $title, $text ) == false ) { $output[0] = $text; - return $output; } // throw away comments $text = preg_replace( '//s', '', $text ); - return self::extractHeadingFromText( - $parser, $page, $title, $text, + $parser, $page, $text, $sec, $to, $sectionHeading, $recursionCheck, $maxLength, $link, $trim, $skipPattern @@ -470,7 +428,6 @@ public static function includeHeading( * * @param Parser $parser * @param string $page - * @param Title|string $title * @param string $text * @param string $sec * @param string $to @@ -485,7 +442,6 @@ public static function includeHeading( public static function extractHeadingFromText( $parser, $page, - $title, $text, $sec, $to, @@ -570,7 +526,7 @@ public static function extractHeadingFromText( $piece = substr( $text, 0, $m[1][1] - 1 ); $output[0] = self::parse( $parser, $piece, "#lsth:{$page}|{$sec}", - 0, $recursionCheck, $maxLength, + $recursionCheck, $maxLength, $link, $trim, $skipPattern ); @@ -594,7 +550,7 @@ public static function extractHeadingFromText( } } - if ( !isset( $end_off ) ) { + if ( ( $end_off ?? null ) === null ) { if ( $nr != 0 ) { $pat = '^(={1,6})\s*[^\s\n=][^\n=]*\s*\1\s*$'; } else { @@ -609,11 +565,7 @@ public static function extractHeadingFromText( } } - $nhead = self::countHeadings( $text, $begin_off ); - - wfDebug( "LSTH: head offset = $nhead" ); - - if ( !empty( $end_off ) ) { + if ( $end_off ?? false ) { if ( $end_off == -1 ) { return $output; } @@ -650,7 +602,7 @@ public static function extractHeadingFromText( // output n-th section and done $output[0] = self::parse( $parser, $piece, "#lsth:{$page}|{$sec}", - $nhead, $recursionCheck, $maxLength, + $recursionCheck, $maxLength, $link, $trim, $skipPattern ); break; @@ -661,7 +613,7 @@ public static function extractHeadingFromText( // output last section and done $output[0] = self::parse( $parser, $piece, "#lsth:{$page}|{$sec}", - $nhead, $recursionCheck, $maxLength, + $recursionCheck, $maxLength, $link, $trim, $skipPattern ); break; @@ -670,7 +622,7 @@ public static function extractHeadingFromText( // output section by name and continue search for another section with the same name $output[$n++] = self::parse( $parser, $piece, "#lsth:{$page}|{$sec}", - $nhead, $recursionCheck, $maxLength, + $recursionCheck, $maxLength, $link, $trim, $skipPattern ); } @@ -823,7 +775,7 @@ public static function includeTemplate( // loop for all template invocations $firstCall = true; - foreach ( $tCalls as $iii => $tCall ) { + foreach ( $tCalls as $tCall ) { if ( $n == -2 ) { $n++; continue; @@ -875,7 +827,10 @@ public static function includeTemplate( ) ) ) . '}}'; - $output[++$n] = self::callParserPreprocess( $parser, $argChain, $parser->getPage(), $parser->getOptions() ); + + $output[++$n] = self::callParserPreprocess( + $parser, $argChain, $parser->getPage(), $parser->getOptions() + ); } break; } @@ -1051,26 +1006,22 @@ public static function spaceOrUnderscore( $pattern ) { * * Using Parser::recursivePreprocess() prevents the cache clear, and thus repetitive calls reuse the * previously generated template DOM which brings a decent performance improvement when called multiple times. - * - * @see https://fandom.atlassian.net/browse/PLATFORM-8725 - * - * @param Parser $parser - * @param string $text - * @param ?\MediaWiki\Page\PageReference $page - * @param \ParserOptions $options - * @return string */ - protected static function callParserPreprocess( Parser $parser, $text, $page, $options ): string { - global $wgDplUseRecursivePreprocess; - if ( $wgDplUseRecursivePreprocess ) { + protected static function callParserPreprocess( + Parser $parser, + string $text, + ?PageReference $page, + ParserOptions $options + ): string { + if ( Config::getSetting( 'recursivePreprocess' ) ) { self::softResetParser( $parser ); $parser->setOutputType( OT_PREPROCESS ); - $text = $parser->recursivePreprocess( $text ); + $text = $parser->recursivePreprocess( $text ); return $text; - } else { - return $parser->preprocess( $text, $page, $options ); } + + return $parser->preprocess( $text, $page, $options ); } /** @@ -1078,7 +1029,7 @@ protected static function callParserPreprocess( Parser $parser, $text, $page, $o */ private static function softResetParser( Parser $parser ): void { self::setParserProperties( $parser, [ - 'mStripState' => new \StripState( $parser ), + 'mStripState' => new StripState( $parser ), 'mIncludeSizes' => [ 'post-expand' => 0, 'arg' => 0, @@ -1094,11 +1045,12 @@ private static function setParserProperties( Parser $parser, array $properties ) foreach ( $properties as $property => $value ) { if ( !array_key_exists( $property, $reflectionCache ) ) { try { - $reflectionCache[$property] = ( new \ReflectionClass( Parser::class ) )->getProperty( $property ); - } catch ( \ReflectionException ) { + $reflectionCache[$property] = ( new ReflectionClass( Parser::class ) )->getProperty( $property ); + } catch ( ReflectionException ) { $reflectionCache[$property] = null; } } + if ( $reflectionCache[$property] ) { $reflectionCache[$property]->setValue( $parser, $value ); } diff --git a/includes/Lister/CategoryList.php b/includes/Lister/CategoryList.php index bd6c12b84..e77611b30 100644 --- a/includes/Lister/CategoryList.php +++ b/includes/Lister/CategoryList.php @@ -50,8 +50,8 @@ public function formatList( $articles, $start, $count ) { /** * Format a single item. * - * @param Article $article - * @param string|null $pageText + * @param Article $article @phan-unused-param + * @param string|null $pageText @phan-unused-param * @return string */ public function formatItem( Article $article, $pageText = null ) { diff --git a/includes/Lister/Lister.php b/includes/Lister/Lister.php index d0c562ae3..844922102 100644 --- a/includes/Lister/Lister.php +++ b/includes/Lister/Lister.php @@ -1322,7 +1322,7 @@ public function transcludePage( Article $article, &$filteredCount ) { // include labeled sections from the page $secPieces = LST::includeSection( $this->parser, $article->mTitle->getPrefixedText(), - $sSecLabel, '', false, $this->getTrimIncluded(), + $sSecLabel, false, $this->getTrimIncluded(), $skipPattern ?? [] ); $secPiece[$s] = implode( diff --git a/includes/Lister/UserFormatList.php b/includes/Lister/UserFormatList.php index 21b6255e5..9ea5eb262 100644 --- a/includes/Lister/UserFormatList.php +++ b/includes/Lister/UserFormatList.php @@ -122,7 +122,7 @@ public function formatList( $articles, $start, $count ) { $this->sort( $rowsKey, $sortColumn ); $newItems = []; - foreach ( $rowsKey as $index => $val ) { + foreach ( $rowsKey as $index => $_ ) { $newItems[] = $items[$index]; } diff --git a/includes/Parameters.php b/includes/Parameters.php index fb41ef964..1ca85cfc0 100644 --- a/includes/Parameters.php +++ b/includes/Parameters.php @@ -242,7 +242,7 @@ public static function sortByPriority( $parameters ) { ]; $_first = []; - foreach ( $priority as $parameter => $order ) { + foreach ( $priority as $parameter => $_ ) { if ( isset( $parameters[$parameter] ) ) { $_first[$parameter] = $parameters[$parameter]; unset( $parameters[$parameter] ); @@ -991,7 +991,7 @@ public function _titlematch( $option ) { public function _nottitleregexp( $option ) { $data = $this->getParameter( 'nottitle' ); - if ( !is_array( $data['regexp'] ) ) { + if ( !is_array( $data['regexp'] ?? null ) ) { $data['regexp'] = []; } @@ -1411,7 +1411,7 @@ public function _reset( $option ) { $values = array_diff( $values, [ 'all', 'none' ] ); $reset = array_flip( $values ); - foreach ( $reset as $value => $key ) { + foreach ( $reset as $value => $_ ) { $reset[$value] = $boolean; } } else { @@ -1455,7 +1455,7 @@ public function _eliminate( $option ) { $values = array_diff( $values, [ 'all', 'none' ] ); $eliminate = array_flip( $values ); - foreach ( $eliminate as $value => $key ) { + foreach ( $eliminate as $value => $_ ) { $eliminate[$value] = $boolean; } } else { diff --git a/includes/Parse.php b/includes/Parse.php index 1c23c0be9..935b4c062 100644 --- a/includes/Parse.php +++ b/includes/Parse.php @@ -29,13 +29,6 @@ class Parse { */ private $logger = null; - /** - * Array of prequoted table names. - * - * @var string[] - */ - private $tableNames = []; - /** * Header Output * @@ -87,7 +80,6 @@ class Parse { public function __construct() { $this->parameters = new Parameters(); $this->logger = new Logger(); - $this->tableNames = Query::getTableNames(); $this->request = RequestContext::getMain()->getRequest(); } @@ -721,8 +713,8 @@ private function doQueryErrorChecks() { $totalCategories = 0; if ( is_array( $this->parameters->getParameter( 'category' ) ) ) { - foreach ( $this->parameters->getParameter( 'category' ) as $comparisonType => $operatorTypes ) { - foreach ( $operatorTypes as $operatorType => $categoryGroups ) { + foreach ( $this->parameters->getParameter( 'category' ) as $operatorTypes ) { + foreach ( $operatorTypes as $categoryGroups ) { foreach ( $categoryGroups as $categories ) { if ( is_array( $categories ) ) { $totalCategories += count( $categories ); @@ -733,8 +725,8 @@ private function doQueryErrorChecks() { } if ( is_array( $this->parameters->getParameter( 'notcategory' ) ) ) { - foreach ( $this->parameters->getParameter( 'notcategory' ) as $comparisonType => $operatorTypes ) { - foreach ( $operatorTypes as $operatorType => $categories ) { + foreach ( $this->parameters->getParameter( 'notcategory' ) as $operatorTypes ) { + foreach ( $operatorTypes as $categories ) { if ( is_array( $categories ) ) { $totalCategories += count( $categories ); } @@ -1177,8 +1169,7 @@ private function cardSuitSort( $articles ) { asort( $sortKeys ); $sortedArticles = []; - - foreach ( $sortKeys as $oldKey => $newKey ) { + foreach ( $sortKeys as $oldKey => $_ ) { $sortedArticles[] = $articles[$oldKey]; } diff --git a/includes/Query.php b/includes/Query.php index 9b78c392d..af2f4273f 100644 --- a/includes/Query.php +++ b/includes/Query.php @@ -16,10 +16,11 @@ use Wikimedia\ObjectCache\WANObjectCache; use Wikimedia\Rdbms\Database; use Wikimedia\Rdbms\IDatabase; -use Wikimedia\Rdbms\Platform\ISQLPlatform; class Query { + use ExternalDomainPatternParser; + /** * Parameters Object * @@ -34,13 +35,6 @@ class Query { */ private $dbr; - /** - * Array of prefixed and escaped table names. - * - * @var array - */ - private $tableNames = []; - /** * Parameters that have already been processed. * @@ -159,8 +153,6 @@ class Query { public function __construct( Parameters $parameters ) { $this->parameters = $parameters; - $this->tableNames = self::getTableNames(); - $this->dbr = MediaWikiServices::getInstance()->getDBLoadBalancer()->getConnection( DB_REPLICA, 'dpl' ); $this->userFactory = MediaWikiServices::getInstance()->getUserFactory(); @@ -199,12 +191,12 @@ public function buildAndSelect( bool $calcRows = false, $profilingContext = '' ) if ( !$this->parameters->getParameter( 'openreferences' ) ) { // Add things that are always part of the query. - $this->addTable( 'page', $this->tableNames['page'] ); + $this->addTable( 'page', $this->dbr->tableName( 'page', 'raw' ) ); $this->addSelect( [ - 'page_namespace' => $this->tableNames['page'] . '.page_namespace', - 'page_id' => $this->tableNames['page'] . '.page_id', - 'page_title' => $this->tableNames['page'] . '.page_title' + 'page_namespace' => $this->dbr->tableName( 'page' ) . '.page_namespace', + 'page_id' => $this->dbr->tableName( 'page' ) . '.page_id', + 'page_title' => $this->dbr->tableName( 'page' ) . '.page_title', ] ); } @@ -213,7 +205,7 @@ public function buildAndSelect( bool $calcRows = false, $profilingContext = '' ) if ( is_array( $wgNonincludableNamespaces ) && count( $wgNonincludableNamespaces ) ) { $this->addNotWhere( [ - $this->tableNames['page'] . '.page_namespace' => $wgNonincludableNamespaces + $this->dbr->tableName( 'page' ) . '.page_namespace' => $wgNonincludableNamespaces, ] ); } @@ -236,62 +228,61 @@ public function buildAndSelect( bool $calcRows = false, $profilingContext = '' ) ] ); - $tables = [ - 'ic' => 'imagelinks' - ]; + $this->addTable( 'imagelinks', 'ic' ); } else { if ( $this->parameters->getParameter( 'openreferences' ) === 'missing' ) { $this->addSelect( [ - 'page_namespace', - 'page_id', - 'page_title', - 'lt_namespace', - 'lt_title', + 'page_namespace' => $this->dbr->tableName( 'page' ) . '.page_namespace', + 'page_id' => $this->dbr->tableName( 'page' ) . '.page_id', + 'page_title' => $this->dbr->tableName( 'page' ) . '.page_title', + 'lt_namespace' => $this->dbr->tableName( 'linktarget' ) . '.lt_namespace', + 'lt_title' => $this->dbr->tableName( 'linktarget' ) . '.lt_title', ] ); - $this->addWhere( [ 'page_namespace' => null ] ); + $this->addWhere( [ $this->dbr->tableName( 'page' ) . '.page_namespace' => null ] ); } else { $this->addSelect( [ - // this fixes "Undefined property: stdClass::$page_id" - 'page_id', - 'lt_namespace', - 'lt_title', + 'page_id' => $this->dbr->tableName( 'page' ) . '.page_id', + 'lt_namespace' => $this->dbr->tableName( 'linktarget' ) . '.lt_namespace', + 'lt_title' => $this->dbr->tableName( 'linktarget' ) . '.lt_title', ] ); } $this->addWhere( - "{$this->tableNames['pagelinks']}.pl_target_id = {$this->tableNames['linktarget']}.lt_id" + "{$this->dbr->tableName( 'pagelinks' )}.pl_target_id = " . + "{$this->dbr->tableName( 'linktarget' )}.lt_id" ); $this->addJoin( - 'page', + $this->dbr->tableName( 'page', 'raw' ), [ 'LEFT JOIN', [ - 'page_namespace = lt_namespace', - 'page_title = lt_title', + "{$this->dbr->tableName( 'page' )}.page_namespace = " . + "{$this->dbr->tableName( 'linktarget' )}.lt_namespace", + "{$this->dbr->tableName( 'page' )}.page_title = " . + "{$this->dbr->tableName( 'linktarget' )}.lt_title", ], ] ); - $tables = [ - 'page', - 'pagelinks', - 'linktarget', - ]; + $this->addTables( [ + 'page' => $this->dbr->tableName( 'page', 'raw' ), + 'pagelinks' => $this->dbr->tableName( 'pagelinks', 'raw' ), + 'linktarget' => $this->dbr->tableName( 'linktarget', 'raw' ), + ] ); } } else { - $tables = $this->tables; if ( count( $this->groupBy ) ) { $options['GROUP BY'] = $this->groupBy; } if ( count( $this->orderBy ) ) { $options['ORDER BY'] = $this->orderBy; - foreach ( $options['ORDER BY'] as $key => $value ) { + foreach ( $options['ORDER BY'] as $key => $_ ) { $options['ORDER BY'][$key] .= ' ' . $this->direction; } } @@ -299,7 +290,7 @@ public function buildAndSelect( bool $calcRows = false, $profilingContext = '' ) if ( $this->parameters->getParameter( 'goal' ) == 'categories' ) { $categoriesGoal = true; $fields = [ - $this->tableNames['page'] . '.page_id' + $this->dbr->tableName( 'page' ) . '.page_id' ]; $options[] = 'DISTINCT'; @@ -316,11 +307,10 @@ public function buildAndSelect( bool $calcRows = false, $profilingContext = '' ) $fields = $this->select; } - $queryError = false; try { if ( $categoriesGoal ) { $res = $this->dbr->select( - $tables, + $this->tables, $fields, $this->where, __METHOD__, @@ -351,7 +341,7 @@ public function buildAndSelect( bool $calcRows = false, $profilingContext = '' ) ); } else { $query = $this->dbr->selectSQLText( - $tables, + $this->tables, $fields, $this->where, __METHOD__, @@ -364,8 +354,12 @@ public function buildAndSelect( bool $calcRows = false, $profilingContext = '' ) $this->sqlQuery = $query; } } catch ( Exception $e ) { + $errorMessage = $this->dbr->lastError(); + if ( $errorMessage == '' ) { + $errorMessage = strval( $e ); + } throw new LogicException( __METHOD__ . ': ' . wfMessage( - 'dpl_query_error', Hooks::getVersion(), $this->dbr->lastError() + 'dpl_query_error', Hooks::getVersion(), $errorMessage )->text() ); } @@ -381,6 +375,7 @@ public function buildAndSelect( bool $calcRows = false, $profilingContext = '' ) if ( $profilingContext ) { $qname .= ' - ' . $profilingContext; } + $tables = $this->tables; $where = $this->where; $join = $this->join; $dbr = $this->dbr; @@ -439,36 +434,6 @@ public function getSqlQuery() { return $this->sqlQuery; } - /** - * Return prefixed and quoted tables that are needed. - * - * @return array - */ - public static function getTableNames() { - $dbr = MediaWikiServices::getInstance()->getDBLoadBalancer()->getConnection( DB_REPLICA, 'dpl' ); - - $tables = [ - 'categorylinks', - 'dpl_clview', - 'externallinks', - 'flaggedpages', - 'imagelinks', - 'linktarget', - 'page', - 'pagelinks', - 'recentchanges', - 'revision', - 'templatelinks' - ]; - - $tableNames = []; - foreach ( $tables as $table ) { - $tableNames[$table] = $dbr->tableName( $table ); - } - - return $tableNames; - } - /** * Add a table to the output. * @@ -486,12 +451,11 @@ public function addTable( $table, $alias ) { } if ( !isset( $this->tables[$alias] ) ) { - $this->tables[$alias] = $this->dbr->tableName( $table ); - + $this->tables[$alias] = $table; return true; - } else { - return false; } + + return false; } /** @@ -816,16 +780,16 @@ private function convertTimestamp( $inputDate ) { /** * Set SQL for 'addauthor' parameter. * - * @param mixed $option + * @param mixed $option @phan-unused-param */ private function _addauthor( $option ) { // Addauthor can not be used with addlasteditor. if ( !isset( $this->parametersProcessed['addlasteditor'] ) || !$this->parametersProcessed['addlasteditor'] ) { $this->addTable( 'revision', 'rev' ); $this->addWhere( [ - $this->tableNames['page'] . '.page_id = rev.rev_page', + $this->dbr->tableName( 'page' ) . '.page_id = rev.rev_page', 'rev.rev_timestamp = (SELECT MIN(rev_aux_min.rev_timestamp) FROM ' . - $this->tableNames['revision'] . + $this->dbr->tableName( 'revision' ) . ' AS rev_aux_min WHERE rev_aux_min.rev_page = rev.rev_page)' ] ); @@ -836,7 +800,7 @@ private function _addauthor( $option ) { /** * Set SQL for 'addcategories' parameter. * - * @param mixed $option + * @param mixed $option @phan-unused-param */ private function _addcategories( $option ) { $this->addTable( 'categorylinks', 'cl_gc' ); @@ -854,13 +818,13 @@ private function _addcategories( $option ) { ] ); - $this->addGroupBy( $this->tableNames['page'] . '.page_id' ); + $this->addGroupBy( $this->dbr->tableName( 'page' ) . '.page_id' ); } /** * Set SQL for 'addcontribution' parameter. * - * @param mixed $option + * @param mixed $option @phan-unused-param */ private function _addcontribution( $option ) { $this->addTable( 'recentchanges', 'rc' ); @@ -868,13 +832,14 @@ private function _addcontribution( $option ) { $this->addSelect( [ 'contribution' => 'SUM(ABS(rc.rc_new_len - rc.rc_old_len))', - 'contributor' => 'rc.rc_actor' + 'contributor' => 'rc.rc_actor', + 'contrib_deleted' => 'rc.rc_deleted', ] ); $this->addWhere( [ - $this->tableNames['page'] . '.page_id = rc.rc_cur_id' + $this->dbr->tableName( 'page' ) . '.page_id = rc.rc_cur_id' ] ); @@ -884,7 +849,7 @@ private function _addcontribution( $option ) { /** * Set SQL for 'addeditdate' parameter. * - * @param mixed $option + * @param mixed $option @phan-unused-param */ private function _addeditdate( $option ) { $this->addTable( 'revision', 'rev' ); @@ -892,7 +857,7 @@ private function _addeditdate( $option ) { $this->addWhere( [ - $this->tableNames['page'] . '.page_id = rev.rev_page', + $this->dbr->tableName( 'page' ) . '.page_id = rev.rev_page', ] ); } @@ -900,7 +865,7 @@ private function _addeditdate( $option ) { /** * Set SQL for 'addfirstcategorydate' parameter. * - * @param mixed $option + * @param mixed $option @phan-unused-param */ private function _addfirstcategorydate( $option ) { // @TODO: This should be programmatically determining which @@ -915,7 +880,7 @@ private function _addfirstcategorydate( $option ) { /** * Set SQL for 'addlasteditor' parameter. * - * @param mixed $option + * @param mixed $option @phan-unused-param */ private function _addlasteditor( $option ) { // Addlasteditor can not be used with addauthor. @@ -923,9 +888,9 @@ private function _addlasteditor( $option ) { $this->addTable( 'revision', 'rev' ); $this->addWhere( [ - $this->tableNames['page'] . '.page_id = rev.rev_page', + $this->dbr->tableName( 'page' ) . '.page_id = rev.rev_page', 'rev.rev_timestamp = (SELECT MAX(rev_aux_max.rev_timestamp) FROM ' . - $this->tableNames['revision'] . ' AS rev_aux_max WHERE rev_aux_max.rev_page = rev.rev_page)' + $this->dbr->tableName( 'revision' ) . ' AS rev_aux_max WHERE rev_aux_max.rev_page = rev.rev_page)' ] ); $this->_adduser( null, 'rev' ); @@ -935,7 +900,7 @@ private function _addlasteditor( $option ) { /** * Set SQL for 'addpagecounter' parameter. * - * @param mixed $option + * @param mixed $option @phan-unused-param */ private function _addpagecounter( $option ) { if ( ExtensionRegistry::getInstance()->isLoaded( 'HitCounters' ) ) { @@ -951,7 +916,7 @@ private function _addpagecounter( $option ) { 'hit_counter', [ 'LEFT JOIN', - 'hit_counter.page_id = ' . $this->tableNames['page'] . '.page_id' + 'hit_counter.page_id = ' . $this->dbr->tableName( 'page' ) . '.page_id' ] ); } @@ -961,12 +926,12 @@ private function _addpagecounter( $option ) { /** * Set SQL for 'addpagesize' parameter. * - * @param mixed $option + * @param mixed $option @phan-unused-param */ private function _addpagesize( $option ) { $this->addSelect( [ - 'page_len' => "{$this->tableNames['page']}.page_len" + 'page_len' => "{$this->dbr->tableName( 'page' )}.page_len" ] ); } @@ -974,12 +939,12 @@ private function _addpagesize( $option ) { /** * Set SQL for 'addpagetoucheddate' parameter. * - * @param mixed $option + * @param mixed $option @phan-unused-param */ private function _addpagetoucheddate( $option ) { $this->addSelect( [ - 'page_touched' => "{$this->tableNames['page']}.page_touched" + 'page_touched' => "{$this->dbr->tableName( 'page' )}.page_touched" ] ); } @@ -987,7 +952,7 @@ private function _addpagetoucheddate( $option ) { /** * Set SQL for 'adduser' parameter. * - * @param mixed $option + * @param mixed $option @phan-unused-param * @param string $tableAlias */ private function _adduser( $option, $tableAlias = '' ) { @@ -998,6 +963,7 @@ private function _adduser( $option, $tableAlias = '' ) { $this->addSelect( [ $tableAlias . 'rev_actor', + $tableAlias . 'rev_deleted', ] ); } @@ -1021,7 +987,7 @@ private function _allrevisionsbefore( $option ) { $this->addWhere( [ - $this->tableNames['page'] . '.page_id = rev.rev_page', + $this->dbr->tableName( 'page' ) . '.page_id = rev.rev_page', 'rev.rev_timestamp < ' . $this->convertTimestamp( $option ) ] ); @@ -1046,7 +1012,7 @@ private function _allrevisionssince( $option ) { $this->addWhere( [ - $this->tableNames['page'] . '.page_id = rev.rev_page', + $this->dbr->tableName( 'page' ) . '.page_id = rev.rev_page', 'rev.rev_timestamp >= ' . $this->convertTimestamp( $option ) ] ); @@ -1059,9 +1025,9 @@ private function _allrevisionssince( $option ) { */ private function _articlecategory( $option ) { $this->addWhere( - $this->tableNames['page'] . '.page_title IN (SELECT p2.page_title FROM ' . - $this->tableNames['page'] . ' p2 INNER JOIN ' . - $this->tableNames['categorylinks'] . ' clstc ON (clstc.cl_from = p2.page_id AND clstc.cl_to = ' . + $this->dbr->tableName( 'page' ) . '.page_title IN (SELECT p2.page_title FROM ' . + $this->dbr->tableName( 'page' ) . ' p2 INNER JOIN ' . + $this->dbr->tableName( 'categorylinks' ) . ' clstc ON (clstc.cl_from = p2.page_id AND clstc.cl_to = ' . $this->dbr->addQuotes( $option ) . ') WHERE p2.page_namespace = 0)' ); } @@ -1075,16 +1041,16 @@ private function _categoriesminmax( $option ) { if ( is_numeric( $option[0] ) ) { $this->addWhere( (int)$option[0] . ' <= (SELECT count(*) FROM ' . - $this->tableNames['categorylinks'] . ' WHERE ' . - $this->tableNames['categorylinks'] . '.cl_from=page_id)' + $this->dbr->tableName( 'categorylinks' ) . ' WHERE ' . + $this->dbr->tableName( 'categorylinks' ) . '.cl_from=page_id)' ); } if ( isset( $option[1] ) && is_numeric( $option[1] ) ) { $this->addWhere( (int)$option[1] . ' >= (SELECT count(*) FROM ' . - $this->tableNames['categorylinks'] . ' WHERE ' . - $this->tableNames['categorylinks'] . '.cl_from=page_id)' + $this->dbr->tableName( 'categorylinks' ) . ' WHERE ' . + $this->dbr->tableName( 'categorylinks' ) . '.cl_from=page_id)' ); } } @@ -1113,7 +1079,7 @@ private function _category( $option ) { $this->addJoin( $tableAlias, [ 'INNER JOIN', - "{$this->tableNames['page']}.page_id = {$tableAlias}.cl_from AND " . + "{$this->dbr->tableName( 'page' )}.page_id = {$tableAlias}.cl_from AND " . "$tableAlias.cl_to {$comparisonType} " . $this->dbr->addQuotes( str_replace( ' ', '_', $category ) ) ] @@ -1124,7 +1090,7 @@ private function _category( $option ) { $tableAlias = "cl{$i}"; $this->addTable( $tableName, $tableAlias ); - $joinOn = "{$this->tableNames['page']}.page_id = {$tableAlias}.cl_from AND ("; + $joinOn = "{$this->dbr->tableName( 'page' )}.page_id = {$tableAlias}.cl_from AND ("; $ors = []; foreach ( $categories as $category ) { @@ -1165,7 +1131,7 @@ private function _notcategory( $option ) { $this->addJoin( $tableAlias, [ 'LEFT OUTER JOIN', - "{$this->tableNames['page']}.page_id = {$tableAlias}.cl_from AND " . + "{$this->dbr->tableName( 'page' )}.page_id = {$tableAlias}.cl_from AND " . "{$tableAlias}.cl_to {$operatorType}" . $this->dbr->addQuotes( str_replace( ' ', '_', $category ) ) ] @@ -1186,15 +1152,19 @@ private function _notcategory( $option ) { * @param mixed $option */ private function _createdby( $option ) { + $user = $this->userFactory->newFromName( $option ); + if ( $user->isHidden() ) { + return; + } + $this->addTable( 'revision', 'creation_rev' ); $this->_adduser( null, 'creation_rev' ); $this->addWhere( [ - $this->dbr->addQuotes( - $this->userFactory->newFromName( $option )->getActorId() - ) . ' = creation_rev.rev_actor', + $this->dbr->addQuotes( $user->getActorId() ) . ' = creation_rev.rev_actor', 'creation_rev.rev_page = page_id', - 'creation_rev.rev_parent_id = 0' + 'creation_rev.rev_deleted = 0', + 'creation_rev.rev_parent_id = 0', ] ); } @@ -1228,15 +1198,15 @@ private function _firstrevisionsince( $option ) { // tell the query optimizer not to look at rows that the following subquery will filter out anyway $this->addWhere( [ - $this->tableNames['page'] . '.page_id = rev.rev_page', + $this->dbr->tableName( 'page' ) . '.page_id = rev.rev_page', 'rev.rev_timestamp >= ' . $this->dbr->addQuotes( $option ) ] ); $this->addWhere( [ - $this->tableNames['page'] . '.page_id = rev.rev_page', + $this->dbr->tableName( 'page' ) . '.page_id = rev.rev_page', 'rev.rev_timestamp = (SELECT MIN(rev_aux_snc.rev_timestamp) FROM ' . - $this->tableNames['revision'] . + $this->dbr->tableName( 'revision' ) . ' AS rev_aux_snc WHERE rev_aux_snc.rev_page=rev.rev_page AND rev_aux_snc.rev_timestamp >= ' . $this->convertTimestamp( $option ) . ')' ] ); @@ -1257,7 +1227,7 @@ private function _goal( $option ) { /** * Set SQL for 'hiddencategories' parameter. * - * @param mixed $option + * @param mixed $option @phan-unused-param */ private function _hiddencategories( $option ) { // @TODO: Unfinished functionality! Never implemented by original author. @@ -1280,8 +1250,8 @@ private function _imagecontainer( $option ) { if ( !$this->parameters->getParameter( 'openreferences' ) ) { $where = [ - "{$this->tableNames['page']}.page_namespace = " . NS_FILE, - "{$this->tableNames['page']}.page_title = ic.il_to" + "{$this->dbr->tableName( 'page' )}.page_namespace = " . NS_FILE, + "{$this->dbr->tableName( 'page' )}.page_title = ic.il_to" ]; } @@ -1320,7 +1290,7 @@ private function _imageused( $option ) { ] ); - $where[] = $this->tableNames['page'] . '.page_id = il.il_from'; + $where[] = $this->dbr->tableName( 'page' ) . '.page_id = il.il_from'; $ors = []; foreach ( $option as $linkGroup ) { @@ -1344,12 +1314,17 @@ private function _imageused( $option ) { * @param mixed $option */ private function _lastmodifiedby( $option ) { + $user = $this->userFactory->newFromName( $option ); + if ( $user->isHidden() ) { + return; + } + $this->addWhere( - $this->dbr->addQuotes( - $this->userFactory->newFromName( $option )->getActorId() - ) . ' = (SELECT rev_actor FROM ' . $this->tableNames['revision'] . - ' WHERE ' . $this->tableNames['revision'] . '.rev_page=page_id ORDER BY ' . - $this->tableNames['revision'] . '.rev_timestamp DESC LIMIT 1)' + $this->dbr->addQuotes( $user->getActorId() ) . + ' = (SELECT rev_actor FROM ' . $this->dbr->tableName( 'revision' ) . + ' WHERE ' . $this->dbr->tableName( 'revision' ) . '.rev_page = page_id' . + ' AND ' . $this->dbr->tableName( 'revision' ) . '.rev_deleted = 0' . + ' ORDER BY ' . $this->dbr->tableName( 'revision' ) . '.rev_timestamp DESC LIMIT 1)' ); } @@ -1365,15 +1340,15 @@ private function _lastrevisionbefore( $option ) { // tell the query optimizer not to look at rows that the following subquery will filter out anyway $this->addWhere( [ - $this->tableNames['page'] . '.page_id = rev.rev_page', + $this->dbr->tableName( 'page' ) . '.page_id = rev.rev_page', 'rev.rev_timestamp < ' . $this->convertTimestamp( $option ) ] ); $this->addWhere( [ - $this->tableNames['page'] . '.page_id = rev.rev_page', + $this->dbr->tableName( 'page' ) . '.page_id = rev.rev_page', 'rev.rev_timestamp = (SELECT MAX(rev_aux_bef.rev_timestamp) FROM ' . - $this->tableNames['revision'] . + $this->dbr->tableName( 'revision' ) . ' AS rev_aux_bef WHERE rev_aux_bef.rev_page=rev.rev_page AND rev_aux_bef.rev_timestamp < ' . $this->convertTimestamp( $option ) . ')' ] ); @@ -1411,8 +1386,8 @@ private function _linksfrom( $option ) { } $where = [ - $this->tableNames['page'] . '.page_namespace = lt.lt_namespace', - $this->tableNames['page'] . '.page_title = lt.lt_title', + $this->dbr->tableName( 'page' ) . '.page_namespace = lt.lt_namespace', + $this->dbr->tableName( 'page' ) . '.page_title = lt.lt_title', 'lt.lt_id = plf.pl_target_id', 'pagesrc.page_id = plf.pl_from' ]; @@ -1448,7 +1423,7 @@ private function _linksto( $option ) { foreach ( $option as $index => $linkGroup ) { if ( $index == 0 ) { - $where = $this->tableNames['page'] . '.page_id=pl.pl_from AND '; + $where = $this->dbr->tableName( 'page' ) . '.page_id=pl.pl_from AND '; $ors = []; foreach ( $linkGroup as $link ) { @@ -1472,17 +1447,17 @@ private function _linksto( $option ) { $where .= '(' . implode( ' OR ', $ors ) . ')'; } else { - $where = 'EXISTS(select pl_from FROM ' . $this->tableNames['pagelinks'] . ', ' . - $this->tableNames['linktarget'] . ' WHERE (' . - $this->tableNames['pagelinks'] . '.pl_from=page_id AND '; + $where = 'EXISTS(select pl_from FROM ' . $this->dbr->tableName( 'pagelinks' ) . ', ' . + $this->dbr->tableName( 'linktarget' ) . ' WHERE (' . + $this->dbr->tableName( 'pagelinks' ) . '.pl_from=page_id AND '; - $where .= $this->tableNames['pagelinks'] . '.pl_target_id = ' . - $this->tableNames['linktarget'] . '.lt_id AND '; + $where .= $this->dbr->tableName( 'pagelinks' ) . '.pl_target_id = ' . + $this->dbr->tableName( 'linktarget' ) . '.lt_id AND '; $ors = []; foreach ( $linkGroup as $link ) { - $_or = '(' . $this->tableNames['linktarget'] . '.lt_namespace=' . (int)$link->getNamespace(); + $_or = "({$this->dbr->tableName( 'linktarget' )}.lt_namespace = {$link->getNamespace()}"; if ( strpos( $link->getDBkey(), '%' ) >= 0 ) { $operator = 'LIKE'; } else { @@ -1490,10 +1465,10 @@ private function _linksto( $option ) { } if ( $this->parameters->getParameter( 'ignorecase' ) ) { - $_or .= ' AND LOWER(CAST(' . $this->tableNames['linktarget'] . '.lt_title AS char)) ' . + $_or .= " AND LOWER(CAST({$this->dbr->tableName( 'linktarget' )}.lt_title AS char)) " . $operator . ' LOWER(' . $this->dbr->addQuotes( $link->getDBkey() ) . ')'; } else { - $_or .= ' AND ' . $this->tableNames['linktarget'] . '.lt_title ' . + $_or .= ' AND ' . $this->dbr->tableName( 'linktarget' ) . '.lt_title ' . $operator . ' ' . $this->dbr->addQuotes( $link->getDBkey() ); } @@ -1527,8 +1502,8 @@ private function _notlinksfrom( $option ) { $where = '(' . implode( ' AND ', $ands ) . ')'; } else { $where = 'CONCAT(page_namespace,page_title) NOT IN (SELECT CONCAT(lt.lt_namespace,lt.lt_title) FROM ' . - $this->tableNames['pagelinks'] . ' pl JOIN ' . - $this->tableNames['linktarget'] . ' lt ON pl.pl_target_id = lt.lt_id WHERE '; + $this->dbr->tableName( 'pagelinks' ) . ' pl JOIN ' . + $this->dbr->tableName( 'linktarget' ) . ' lt ON pl.pl_target_id = lt.lt_id WHERE '; $ors = []; @@ -1551,9 +1526,9 @@ private function _notlinksfrom( $option ) { */ private function _notlinksto( $option ) { if ( count( $option ) ) { - $where = $this->tableNames['page'] . '.page_id NOT IN (SELECT pl.pl_from FROM ' . - $this->tableNames['pagelinks'] . ' pl JOIN ' . - $this->tableNames['linktarget'] . ' lt ON pl.pl_target_id = lt.lt_id WHERE '; + $where = $this->dbr->tableName( 'page' ) . '.page_id NOT IN (SELECT pl.pl_from FROM ' . + $this->dbr->tableName( 'pagelinks' ) . ' pl JOIN ' . + $this->dbr->tableName( 'linktarget' ) . ' lt ON pl.pl_target_id = lt.lt_id WHERE '; $ors = []; @@ -1621,16 +1596,18 @@ private function _linkstoexternaldomain( $option ) { $domainPatterns ); - $where = "{$this->tableNames['page']}.page_id=el.el_from AND ({$this->dbr->makeList( $ors, ISQLPlatform::LIST_OR )})"; + $where = "{$this->dbr->tableName( 'page' )}.page_id=el.el_from " . + " AND ({$this->dbr->makeList( $ors, IDatabase::LIST_OR )})"; } else { + $linksTable = $this->dbr->tableName( 'externallinks' ); $ors = array_map( - fn ( $pattern ) => "{$this->tableNames['externallinks']}.el_to_domain_index LIKE {$this->dbr->addQuotes( $pattern )}", + fn ( $pattern ) => "$linksTable.el_to_domain_index LIKE {$this->dbr->addQuotes( $pattern )}", $domainPatterns ); - $where = "EXISTS(SELECT el_from FROM {$this->tableNames['externallinks']} " . - " WHERE ({$this->tableNames['externallinks']}.el_from=page_id " . - " AND ({$this->dbr->makeList( $ors, ISQLPlatform::LIST_OR )})))"; + $where = "EXISTS(SELECT el_from FROM $linksTable " . + " WHERE ($linksTable.el_from=page_id " . + " AND ({$this->dbr->makeList( $ors, IDatabase::LIST_OR )})))"; } $this->addWhere( $where ); @@ -1662,16 +1639,18 @@ private function _linkstoexternalpath( $option ) { $paths ); - $where = "{$this->tableNames['page']}.page_id=el.el_from AND ({$this->dbr->makeList( $ors, ISQLPlatform::LIST_OR )})"; + $where = "{$this->dbr->tableName( 'page' )}.page_id=el.el_from " . + " AND ({$this->dbr->makeList( $ors, IDatabase::LIST_OR )})"; } else { + $linksTable = $this->dbr->tableName( 'externallinks' ); $ors = array_map( - fn ( $path ) => "{$this->tableNames['externallinks']}.el_to_path LIKE {$this->dbr->addQuotes( $path )}", + fn ( $path ) => "$linksTable.el_to_path LIKE {$this->dbr->addQuotes( $path )}", $paths ); - $where = "EXISTS(SELECT el_from FROM {$this->tableNames['externallinks']} " . - " WHERE ({$this->tableNames['externallinks']}.el_from=page_id " . - " AND ({$this->dbr->makeList( $ors, ISQLPlatform::LIST_OR )})))"; + $where = "EXISTS(SELECT el_from FROM $linksTable " . + " WHERE ($linksTable.el_from=page_id " . + " AND ({$this->dbr->makeList( $ors, IDatabase::LIST_OR )})))"; } $this->addWhere( $where ); @@ -1685,8 +1664,8 @@ private function _linkstoexternalpath( $option ) { */ private function _maxrevisions( $option ) { $this->addWhere( - "((SELECT count(rev_aux3.rev_page) FROM {$this->tableNames['revision']}" . - " AS rev_aux3 WHERE rev_aux3.rev_page = {$this->tableNames['page']}.page_id) <= {$option})" + "((SELECT count(rev_aux3.rev_page) FROM {$this->dbr->tableName( 'revision' )}" . + " AS rev_aux3 WHERE rev_aux3.rev_page = {$this->dbr->tableName( 'page' )}.page_id) <= {$option})" ); } @@ -1697,8 +1676,8 @@ private function _maxrevisions( $option ) { */ private function _minrevisions( $option ) { $this->addWhere( - "((SELECT count(rev_aux2.rev_page) FROM {$this->tableNames['revision']}" . - " AS rev_aux2 WHERE rev_aux2.rev_page = {$this->tableNames['page']}.page_id) >= {$option})" + "((SELECT count(rev_aux2.rev_page) FROM {$this->dbr->tableName( 'revision' )}" . + " AS rev_aux2 WHERE rev_aux2.rev_page = {$this->dbr->tableName( 'page' )}.page_id) >= {$option})" ); } @@ -1708,12 +1687,16 @@ private function _minrevisions( $option ) { * @param mixed $option */ private function _modifiedby( $option ) { + $user = $this->userFactory->newFromName( $option ); + if ( $user->isHidden() ) { + return; + } + $this->addTable( 'revision', 'change_rev' ); $this->addWhere( - $this->dbr->addQuotes( - $this->userFactory->newFromName( $option )->getActorId() - ) . ' = change_rev.rev_actor AND change_rev.rev_page = page_id' + $this->dbr->addQuotes( $user->getActorId() ) . + ' = change_rev.rev_actor AND change_rev.rev_deleted = 0 AND change_rev.rev_page = page_id' ); } @@ -1727,13 +1710,13 @@ private function _namespace( $option ) { if ( $this->parameters->getParameter( 'openreferences' ) ) { $this->addWhere( [ - "{$this->tableNames['linktarget']}.lt_namespace" => $option + "{$this->dbr->tableName( 'linktarget' )}.lt_namespace" => $option ] ); } else { $this->addWhere( [ - "{$this->tableNames['page']}.page_namespace" => $option + "{$this->dbr->tableName( 'page' )}.page_namespace" => $option ] ); } @@ -1746,13 +1729,17 @@ private function _namespace( $option ) { * @param mixed $option */ private function _notcreatedby( $option ) { + $user = $this->userFactory->newFromName( $option ); + if ( $user->isHidden() ) { + return; + } + $this->addTable( 'revision', 'no_creation_rev' ); $this->addWhere( - $this->dbr->addQuotes( - $this->userFactory->newFromName( $option )->getActorId() - ) . ' != no_creation_rev.rev_actor AND no_creation_rev.rev_page = ' . - 'page_id AND no_creation_rev.rev_parent_id = 0' + $this->dbr->addQuotes( $user->getActorId() ) . + ' != no_creation_rev.rev_actor AND no_creation_rev.rev_deleted = 0 ' . + 'AND no_creation_rev.rev_page = page_id AND no_creation_rev.rev_parent_id = 0' ); } @@ -1762,11 +1749,17 @@ private function _notcreatedby( $option ) { * @param mixed $option */ private function _notlastmodifiedby( $option ) { - $this->addWhere( $this->dbr->addQuotes( - $this->userFactory->newFromName( $option )->getActorId() - ) . ' != (SELECT rev_actor FROM ' . $this->tableNames['revision'] . - ' WHERE ' . $this->tableNames['revision'] . '.rev_page=page_id ORDER BY ' . - $this->tableNames['revision'] . '.rev_timestamp DESC LIMIT 1)' + $user = $this->userFactory->newFromName( $option ); + if ( $user->isHidden() ) { + return; + } + + $this->addWhere( + $this->dbr->addQuotes( $user->getActorId() ) . + ' != (SELECT rev_actor FROM ' . $this->dbr->tableName( 'revision' ) . + ' WHERE ' . $this->dbr->tableName( 'revision' ) . '.rev_page = page_id' . + ' AND ' . $this->dbr->tableName( 'revision' ) . '.rev_deleted = 0' . + ' ORDER BY ' . $this->dbr->tableName( 'revision' ) . '.rev_timestamp DESC LIMIT 1)' ); } @@ -1776,12 +1769,19 @@ private function _notlastmodifiedby( $option ) { * @param mixed $option */ private function _notmodifiedby( $option ) { - $this->addWhere( 'NOT EXISTS (SELECT 1 FROM ' . - $this->tableNames['revision'] . ' WHERE ' . $this->tableNames['revision'] . - '.rev_page=page_id AND ' . $this->tableNames['revision'] . '.rev_actor = ' . - $this->dbr->addQuotes( - $this->userFactory->newFromName( $option )->getActorId() - ) . ' LIMIT 1)' + $user = $this->userFactory->newFromName( $option ); + if ( $user->isHidden() ) { + return; + } + + $actorID = $this->dbr->addQuotes( $user->getActorId() ); + $this->addWhere( + 'NOT EXISTS (SELECT 1 FROM ' . + $this->dbr->tableName( 'revision' ) . + ' WHERE ' . $this->dbr->tableName( 'revision' ) . '.rev_page = page_id' . + ' AND ' . $this->dbr->tableName( 'revision' ) . '.rev_actor = ' . $actorID . + ' AND ' . $this->dbr->tableName( 'revision' ) . '.rev_deleted = 0' . + ' LIMIT 1)' ); } @@ -1795,13 +1795,13 @@ private function _notnamespace( $option ) { if ( $this->parameters->getParameter( 'openreferences' ) ) { $this->addNotWhere( [ - "{$this->tableNames['linktarget']}.lt_namespace" => $option + "{$this->dbr->tableName( 'linktarget' )}.lt_namespace" => $option ] ); } else { $this->addNotWhere( [ - "{$this->tableNames['page']}.page_namespace" => $option + "{$this->dbr->tableName( 'page' )}.page_namespace" => $option ] ); } @@ -1887,7 +1887,7 @@ private function _ordermethod( $option ) { // count( Config::getSetting( 'allowedNamespaces' ) ), true ); $namespaces = array_slice( $namespaces, 3, count( $namespaces ), true ); - $_namespaceIdToText = "CASE {$this->tableNames['page']}.page_namespace"; + $_namespaceIdToText = "CASE {$this->dbr->tableName( 'page' )}.page_namespace"; foreach ( $namespaces as $id => $name ) { $_namespaceIdToText .= ' WHEN ' . (int)$id . ' THEN ' . $this->dbr->addQuotes( $name . ':' ); @@ -1966,7 +1966,7 @@ private function _ordermethod( $option ) { 'hit_counter', [ 'LEFT JOIN', - 'hit_counter.page_id = ' . $this->tableNames['page'] . '.page_id' + 'hit_counter.page_id = ' . $this->dbr->tableName( 'page' ) . '.page_id' ] ); } @@ -1987,9 +1987,9 @@ private function _ordermethod( $option ) { if ( !$this->revisionAuxWhereAdded ) { $this->addWhere( [ - "{$this->tableNames['page']}.page_id = rev.rev_page", + "{$this->dbr->tableName( 'page' )}.page_id = rev.rev_page", "rev.rev_timestamp = (SELECT MIN(rev_aux.rev_timestamp) FROM " . - "{$this->tableNames['revision']} AS rev_aux WHERE rev_aux.rev_page=rev.rev_page)" + "{$this->dbr->tableName( 'revision' )} AS rev_aux WHERE rev_aux.rev_page=rev.rev_page)" ] ); } @@ -2000,7 +2000,7 @@ private function _ordermethod( $option ) { $this->addOrderBy( 'page_touched' ); $this->addSelect( [ - 'page_touched' => "{$this->tableNames['page']}.page_touched" + 'page_touched' => "{$this->dbr->tableName( 'page' )}.page_touched" ] ); } else { @@ -2009,18 +2009,18 @@ private function _ordermethod( $option ) { $this->addSelect( [ 'rev.rev_timestamp' ] ); if ( !$this->revisionAuxWhereAdded ) { - $this->addWhere( "{$this->tableNames['page']}.page_id = rev.rev_page" ); + $this->addWhere( "{$this->dbr->tableName( 'page' )}.page_id = rev.rev_page" ); if ( $this->parameters->getParameter( 'minoredits' ) == 'exclude' ) { $this->addWhere( 'rev.rev_timestamp = (SELECT MAX(rev_aux.rev_timestamp) FROM ' . - $this->tableNames['revision'] . + $this->dbr->tableName( 'revision' ) . ' AS rev_aux WHERE rev_aux.rev_page = rev.rev_page AND rev_aux.rev_minor_edit = 0)' ); } else { $this->addWhere( 'rev.rev_timestamp = (SELECT MAX(rev_aux.rev_timestamp) FROM ' . - $this->tableNames['revision'] . + $this->dbr->tableName( 'revision' ) . ' AS rev_aux WHERE rev_aux.rev_page = rev.rev_page)' ); } @@ -2041,7 +2041,7 @@ private function _ordermethod( $option ) { $this->addOrderBy( 'page_touched' ); $this->addSelect( [ - 'page_touched' => "{$this->tableNames['page']}.page_touched" + 'page_touched' => "{$this->dbr->tableName( 'page' )}.page_touched" ] ); break; @@ -2055,7 +2055,7 @@ private function _ordermethod( $option ) { // the usual way (full page name, underscores replaced with spaces). // UTF-8 created problems with non-utf-8 MySQL databases $replaceConcat = "REPLACE(CONCAT({$_namespaceIdToText}, " . - $this->tableNames['page'] . ".page_title), '_', ' ')"; + $this->dbr->tableName( 'page' ) . ".page_title), '_', ' ')"; $category = (array)$this->parameters->getParameter( 'category' ); $notCategory = (array)$this->parameters->getParameter( 'notcategory' ); @@ -2091,7 +2091,7 @@ private function _ordermethod( $option ) { $this->addSelect( [ - 'sortkey' => "{$this->tableNames['page']}.page_title " . $this->getCollateSQL() + 'sortkey' => "{$this->dbr->tableName( 'page' )}.page_title " . $this->getCollateSQL() ] ); break; @@ -2107,9 +2107,9 @@ private function _ordermethod( $option ) { // Generate sortkey like for category links. // UTF-8 created problems with non-utf-8 MySQL databases. $this->addSelect( [ - 'sortkey' => "REPLACE(CONCAT(IF(" . $this->tableNames['page'] . + 'sortkey' => "REPLACE(CONCAT(IF(" . $this->dbr->tableName( 'page' ) . ".page_namespace = 0, '', CONCAT(" . $_namespaceIdToText . ", ':')), " . - $this->tableNames['page'] . ".page_title), '_', ' ') " . + $this->dbr->tableName( 'page' ) . ".page_title), '_', ' ') " . $this->getCollateSQL() ] ); } @@ -2137,14 +2137,14 @@ private function _redirects( $option ) { case 'only': $this->addWhere( [ - $this->tableNames['page'] . '.page_is_redirect' => 1 + $this->dbr->tableName( 'page' ) . '.page_is_redirect' => 1 ] ); break; case 'exclude': $this->addWhere( [ - $this->tableNames['page'] . '.page_is_redirect' => 0 + $this->dbr->tableName( 'page' ) . '.page_is_redirect' => 0 ] ); break; @@ -2237,10 +2237,10 @@ private function _title( $option ) { } } else { if ( $this->parameters->getParameter( 'ignorecase' ) ) { - $_or = "LOWER(CAST({$this->tableNames['page']}.page_title AS char)) {$comparisonType}" . + $_or = "LOWER(CAST({$this->dbr->tableName( 'page' )}.page_title AS char)) {$comparisonType}" . strtolower( $this->dbr->addQuotes( $title ) ); } else { - $_or = "{$this->tableNames['page']}.page_title {$comparisonType}" . + $_or = "{$this->dbr->tableName( 'page' )}.page_title {$comparisonType}" . $this->dbr->addQuotes( $title ); } } @@ -2272,10 +2272,10 @@ private function _nottitle( $option ) { } } else { if ( $this->parameters->getParameter( 'ignorecase' ) ) { - $_or = "LOWER(CAST({$this->tableNames['page']}.page_title AS char)) {$comparisonType}" . + $_or = "LOWER(CAST({$this->dbr->tableName( 'page' )}.page_title AS char)) {$comparisonType}" . strtolower( $this->dbr->addQuotes( $title ) ); } else { - $_or = "{$this->tableNames['page']}.page_title {$comparisonType}" . + $_or = "{$this->dbr->tableName( 'page' )}.page_title {$comparisonType}" . $this->dbr->addQuotes( $title ); } } @@ -2310,7 +2310,7 @@ private function _titlegt( $option ) { if ( $this->parameters->getParameter( 'openreferences' ) ) { $where = "(lt_title {$operator} {$option})"; } else { - $where = "({$this->tableNames['page']}.page_title {$operator} {$option})"; + $where = "({$this->dbr->tableName( 'page' )}.page_title {$operator} {$option})"; } $this->addWhere( $where ); @@ -2338,7 +2338,7 @@ private function _titlelt( $option ) { if ( $this->parameters->getParameter( 'openreferences' ) ) { $where = "(lt_title {$operator} {$option})"; } else { - $where = "({$this->tableNames['page']}.page_title {$operator} {$option})"; + $where = "({$this->dbr->tableName( 'page' )}.page_title {$operator} {$option})"; } $this->addWhere( $where ); @@ -2370,8 +2370,8 @@ private function _usedby( $option ) { [ $nsField, $titleField ] = $linksMigration->getTitleFields( 'templatelinks' ); $this->addSelect( [ - 'tpl_sel_title' => "{$this->tableNames['page']}.page_title", - 'tpl_sel_ns' => "{$this->tableNames['page']}.page_namespace" + 'tpl_sel_title' => "{$this->dbr->tableName( 'page' )}.page_title", + 'tpl_sel_ns' => "{$this->dbr->tableName( 'page' )}.page_namespace" ] ); $this->addJoin( @@ -2404,7 +2404,7 @@ private function _uses( $option ) { 'templatelinks' => 'tl', ] ); - $where = $this->tableNames['page'] . '.page_id=tl.tl_from AND lt.lt_id = tl.tl_target_id AND ('; + $where = $this->dbr->tableName( 'page' ) . '.page_id=tl.tl_from AND lt.lt_id = tl.tl_target_id AND ('; $ors = []; $linksMigration = MediaWikiServices::getInstance()->getLinksMigration(); @@ -2436,12 +2436,12 @@ private function _uses( $option ) { */ private function _notuses( $option ) { if ( count( $option ) > 0 ) { - $where = $this->tableNames['page'] . '.page_id NOT IN (SELECT ' . - $this->tableNames['templatelinks'] . '.tl_from FROM ' . - $this->tableNames['templatelinks'] . ' INNER JOIN ' . - $this->tableNames['linktarget'] . ' ON ' . - $this->tableNames['linktarget'] . '.lt_id = ' . - $this->tableNames['templatelinks'] . '.tl_target_id WHERE ('; + $where = $this->dbr->tableName( 'page' ) . '.page_id NOT IN (SELECT ' . + $this->dbr->tableName( 'templatelinks' ) . '.tl_from FROM ' . + $this->dbr->tableName( 'templatelinks' ) . ' INNER JOIN ' . + $this->dbr->tableName( 'linktarget' ) . ' ON ' . + $this->dbr->tableName( 'linktarget' ) . '.lt_id = ' . + $this->dbr->tableName( 'templatelinks' ) . '.tl_target_id WHERE ('; $ors = []; @@ -2450,14 +2450,14 @@ private function _notuses( $option ) { foreach ( $option as $linkGroup ) { foreach ( $linkGroup as $link ) { - $_or = '(' . $this->tableNames['linktarget'] . '.' . $nsField . '=' . (int)$link->getNamespace(); + $_or = "({$this->dbr->tableName( 'linktarget' )}.$nsField = {$link->getNamespace()}"; if ( $this->parameters->getParameter( 'ignorecase' ) ) { - $_or .= ' AND LOWER(CAST(' . $this->tableNames['linktarget'] . '.' . + $_or .= ' AND LOWER(CAST(' . $this->dbr->tableName( 'linktarget' ) . '.' . $titleField . ' AS char)) = LOWER(' . $this->dbr->addQuotes( $link->getDBkey() ) . '))'; } else { - $_or .= ' AND ' . $this->tableNames['linktarget'] . '.' . + $_or .= ' AND ' . $this->dbr->tableName( 'linktarget' ) . '.' . $titleField . ' = ' . $this->dbr->addQuotes( $link->getDBkey() ) . ')'; } $ors[] = $_or; diff --git a/includes/UpdateArticle.php b/includes/UpdateArticle.php index 0f1a4eaa7..01eea0d24 100644 --- a/includes/UpdateArticle.php +++ b/includes/UpdateArticle.php @@ -47,7 +47,6 @@ public static function updateArticleByRule( $title, $text, $rulesText ) { $afterparm = []; $format = []; $preview = []; - $save = []; $tooltip = []; $optional = []; @@ -180,10 +179,6 @@ public static function updateArticleByRule( $title, $text, $rulesText ) { $preview[] = $arg; } - if ( $cmd[0] == 'save' ) { - $save[] = $arg; - } - if ( $cmd[0] == 'summary' ) { $summary = $arg; } @@ -256,7 +251,7 @@ public static function updateArticleByRule( $title, $text, $rulesText ) { // construct an edit form containing all template invocations $form = "
\n"; - foreach ( $tpv as $call => $tplValues ) { + foreach ( $tpv as $call => $_ ) { $form .= "\n"; foreach ( $parameter as $nr => $parm ) { // try to extract legend from the docs of the template diff --git a/tests/phpunit/DPLExternalDomainPatternParserTest.php b/tests/phpunit/DPLExternalDomainPatternParserTest.php index 1356dc7ca..46360bcd3 100644 --- a/tests/phpunit/DPLExternalDomainPatternParserTest.php +++ b/tests/phpunit/DPLExternalDomainPatternParserTest.php @@ -1,23 +1,28 @@ parseDomainPattern( $domain ); $this->assertSame( $expected, $actual ); } - public static function getDomainPattern(): array { + public function provideDomainPattern(): array { return [ // Full domain with extra path and without any wildcards [ 'http://www.fandom.com/test123/test?test=%', 'http://com.fandom.www.' ], @@ -42,15 +47,15 @@ public static function getDomainPattern(): array { } /** - * This test documents cases that are not correctly supported + * This test documents cases that are NOT correctly supported + * @dataProvider provideUnsupportedDomainPattern */ - #[DataProvider( 'getUnsupportedDomainPattern' )] public function testUnsupportedDomainPatterns( string $domain, string $expected ): void { $actual = $this->parseDomainPattern( $domain ); $this->assertSame( $expected, $actual ); } - public static function getUnsupportedDomainPattern(): array { + public function provideUnsupportedDomainPattern(): array { return [ // We are not supporting `_` as a `.` [ 'http://www.fandom_com', 'http://fandom_com.www.' ], diff --git a/tests/phpunit/DPLIntegrationTestCase.php b/tests/phpunit/DPLIntegrationTestCase.php index a4342e608..895d22146 100644 --- a/tests/phpunit/DPLIntegrationTestCase.php +++ b/tests/phpunit/DPLIntegrationTestCase.php @@ -146,7 +146,6 @@ protected function runDPLQuery( array $params ): string { ); $parserOutput = $parser->parse( $invocation, $title, $parserOptions ); - - return $parserOutput->getText(); + return $parserOutput->getContentHolderText(); } }