/** * Do some database updates after deletion * * @param int $id The page_id value of the page being deleted * @param Content|null $content Optional page content to be used when determining * the required updates. This may be needed because $this->getContent() * may already return null when the page proper was deleted. * @param Revision|null $revision The latest page revision */ public function doDeleteUpdates($id, Content $content = null, Revision $revision = null) { try { $countable = $this->isCountable(); } catch (Exception $ex) { // fallback for deleting broken pages for which we cannot load the content for // some reason. Note that doDeleteArticleReal() already logged this problem. $countable = false; } // Update site status DeferredUpdates::addUpdate(new SiteStatsUpdate(0, 1, -(int) $countable, -1)); // Delete pagelinks, update secondary indexes, etc $updates = $this->getDeletionUpdates($content); foreach ($updates as $update) { DeferredUpdates::addUpdate($update); } // Reparse any pages transcluding this page LinksUpdate::queueRecursiveJobsForTable($this->mTitle, 'templatelinks'); // Reparse any pages including this image if ($this->mTitle->getNamespace() == NS_FILE) { LinksUpdate::queueRecursiveJobsForTable($this->mTitle, 'imagelinks'); } // Clear caches WikiPage::onArticleDelete($this->mTitle); ResourceLoaderWikiModule::invalidateModuleCache($this->mTitle, $revision, null, wfWikiID()); // Reset this object and the Title object $this->loadFromRow(false, self::READ_LATEST); // Search engine DeferredUpdates::addUpdate(new SearchUpdate($id, $this->mTitle)); }
/** * Updates page_touched for this page; called from LinksUpdate.php * * @param string $purgeTime [optional] TS_MW timestamp * @return bool True if the update succeeded */ public function invalidateCache($purgeTime = null) { if (wfReadOnly()) { return false; } elseif ($this->mArticleID === 0) { return true; // avoid gap locking if we know it's not there } $dbw = wfGetDB(DB_MASTER); $dbw->onTransactionPreCommitOrIdle(function () { ResourceLoaderWikiModule::invalidateModuleCache($this, null, null, wfWikiID()); }); $conds = $this->pageCond(); DeferredUpdates::addUpdate(new AutoCommitUpdate($dbw, __METHOD__, function (IDatabase $dbw, $fname) use($conds, $purgeTime) { $dbTimestamp = $dbw->timestamp($purgeTime ?: time()); $dbw->update('page', ['page_touched' => $dbTimestamp], $conds + ['page_touched < ' . $dbw->addQuotes($dbTimestamp)], $fname); MediaWikiServices::getInstance()->getLinkCache()->invalidateTitle($this); }), DeferredUpdates::PRESEND); return true; }
/** * @covers ResourceLoaderWikiModule::getGroup * @dataProvider provideGetGroup */ public function testGetGroup($params, $expected) { $module = new ResourceLoaderWikiModule($params); $this->assertEquals($expected, $module->getGroup()); }
protected function getResourceName($title, $titleText, $options) { if (isset($options['originalName'])) { return $options['originalName']; } if ($title instanceof GlobalTitle) { $name = "[city_id=" . $title->getCityId() . "]:"; $name .= isset($options['title']) ? $options['title'] : $titleText; return $name; } else { return parent::getResourceName($title, $titleText, $options); } }
/** * Call this to freeze the module queue and JS config and create a formatter. * * Depending on the Skin, this may get lazy-initialised in either headElement() or * getBottomScripts(). See SkinTemplate::prepareQuickTemplate(). Calling this too early may * cause unexpected side-effects since disallowUserJs() may be called at any time to change * the module filters retroactively. Skins and extension hooks may also add modules until very * late in the request lifecycle. * * @return ResourceLoaderClientHtml */ public function getRlClient() { if (!$this->rlClient) { $context = $this->getRlClientContext(); $rl = $this->getResourceLoader(); $this->addModules(['user.options', 'user.tokens']); $this->addModuleStyles(['site.styles', 'noscript', 'user.styles', 'user.cssprefs']); $this->getSkin()->setupSkinUserCss($this); // Prepare exempt modules for buildExemptModules() $exemptGroups = ['site' => [], 'noscript' => [], 'private' => [], 'user' => []]; $exemptStates = []; $moduleStyles = $this->getModuleStyles(true); // Preload getTitleInfo for isKnownEmpty calls below and in ResourceLoaderClientHtml // Separate user-specific batch for improved cache-hit ratio. $userBatch = ['user.styles', 'user']; $siteBatch = array_diff($moduleStyles, $userBatch); $dbr = wfGetDB(DB_REPLICA); ResourceLoaderWikiModule::preloadTitleInfo($context, $dbr, $siteBatch); ResourceLoaderWikiModule::preloadTitleInfo($context, $dbr, $userBatch); // Filter out modules handled by buildExemptModules() $moduleStyles = array_filter($moduleStyles, function ($name) use($rl, $context, &$exemptGroups, &$exemptStates) { $module = $rl->getModule($name); if ($module) { if ($name === 'user.styles' && $this->isUserCssPreview()) { $exemptStates[$name] = 'ready'; // Special case in buildExemptModules() return false; } $group = $module->getGroup(); if (isset($exemptGroups[$group])) { $exemptStates[$name] = 'ready'; if (!$module->isKnownEmpty($context)) { // E.g. Don't output empty <styles> $exemptGroups[$group][] = $name; } return false; } } return true; }); $this->rlExemptStyleModules = $exemptGroups; $isUserModuleFiltered = !$this->filterModules(['user']); // If this page filters out 'user', makeResourceLoaderLink will drop it. // Avoid indefinite "loading" state or untrue "ready" state (T145368). if (!$isUserModuleFiltered) { // Manually handled by getBottomScripts() $userModule = $rl->getModule('user'); $userState = $userModule->isKnownEmpty($context) && !$this->isUserJsPreview() ? 'ready' : 'loading'; $this->rlUserModuleState = $exemptStates['user'] = $userState; } $rlClient = new ResourceLoaderClientHtml($context, $this->getTarget()); $rlClient->setConfig($this->getJSVars()); $rlClient->setModules($this->getModules(true)); $rlClient->setModuleStyles($moduleStyles); $rlClient->setModuleScripts($this->getModuleScripts(true)); $rlClient->setExemptStates($exemptStates); $this->rlClient = $rlClient; } return $this->rlClient; }
/** * Load information stored in the database about modules. * * This method grabs modules dependencies from the database and updates modules * objects. * * This is not inside the module code because it is much faster to * request all of the information at once than it is to have each module * requests its own information. This sacrifice of modularity yields a substantial * performance improvement. * * @param array $moduleNames List of module names to preload information for * @param ResourceLoaderContext $context Context to load the information within */ public function preloadModuleInfo(array $moduleNames, ResourceLoaderContext $context) { if (!$moduleNames) { // Or else Database*::select() will explode, plus it's cheaper! return; } $dbr = wfGetDB(DB_REPLICA); $skin = $context->getSkin(); $lang = $context->getLanguage(); // Batched version of ResourceLoaderModule::getFileDependencies $vary = "{$skin}|{$lang}"; $res = $dbr->select('module_deps', ['md_module', 'md_deps'], ['md_module' => $moduleNames, 'md_skin' => $vary], __METHOD__); // Prime in-object cache for file dependencies $modulesWithDeps = []; foreach ($res as $row) { $module = $this->getModule($row->md_module); if ($module) { $module->setFileDependencies($context, ResourceLoaderModule::expandRelativePaths(FormatJson::decode($row->md_deps, true))); $modulesWithDeps[] = $row->md_module; } } // Register the absence of a dependency row too foreach (array_diff($moduleNames, $modulesWithDeps) as $name) { $module = $this->getModule($name); if ($module) { $this->getModule($name)->setFileDependencies($context, []); } } // Batched version of ResourceLoaderWikiModule::getTitleInfo ResourceLoaderWikiModule::preloadTitleInfo($context, $dbr, $moduleNames); // Prime in-object cache for message blobs for modules with messages $modules = []; foreach ($moduleNames as $name) { $module = $this->getModule($name); if ($module && $module->getMessages()) { $modules[$name] = $module; } } $store = $this->getMessageBlobStore(); $blobs = $store->getBlobs($modules, $lang); foreach ($blobs as $name => $blob) { $modules[$name]->setMessageBlob($blob, $lang); } }