* @note Consider using a TitleValue object instead. TitleValue is more lightweight
* and does not rely on global state or the database.
*/
-class Title implements LinkTarget {
+class Title implements LinkTarget, IDBAccessObject {
/** @var MapCacheLRU */
static private $titleCache = null;
public function getFragmentForURL() {
if ( !$this->hasFragment() ) {
return '';
- } elseif ( $this->isExternal()
- && !self::getInterwikiLookup()->fetch( $this->mInterwiki )->isLocal()
- ) {
- return '#' . Sanitizer::escapeIdForExternalInterwiki( $this->mFragment );
+ } elseif ( $this->isExternal() ) {
+ // Note: If the interwiki is unknown, it's treated as a namespace on the local wiki,
+ // so we treat it like a local interwiki.
+ $interwiki = self::getInterwikiLookup()->fetch( $this->mInterwiki );
+ if ( $interwiki && !$interwiki->isLocal() ) {
+ return '#' . Sanitizer::escapeIdForExternalInterwiki( $this->mFragment );
+ }
}
+
return '#' . Sanitizer::escapeIdForLink( $this->mFragment );
}
* protocol-relative, the URL will be expanded to http://
*
* @see self::getLocalURL for the arguments.
- * @param string $query
- * @param string|bool $query2
+ * @param string|string[] $query
+ * @param string|bool $query2 Deprecated
* @return string The URL
*/
public function getInternalURL( $query = '', $query2 = false ) {
* NOTE: Unlike getInternalURL(), the canonical URL includes the fragment
*
* @see self::getLocalURL for the arguments.
- * @param string $query
- * @param string|bool $query2
+ * @param string|string[] $query
+ * @param string|bool $query2 Deprecated
* @return string The URL
* @since 1.18
*/
// will get the action where the restriction is the same. This may result
// in actions being blocked that shouldn't be.
if ( Action::exists( $action ) ) {
+ // Clone the title to prevent mutations to this object which is done
+ // by Title::loadFromRow() in WikiPage::loadFromRow().
+ $page = WikiPage::factory( clone $this );
+ // Creating an action will perform several database queries to ensure that
+ // the action has not been overridden by the content type.
// @todo FIXME: Pass the relevant context into this function.
- $action = Action::factory( $action, WikiPage::factory( $this ), RequestContext::getMain() );
+ $action = Action::factory( $action, $page, RequestContext::getMain() );
} else {
$action = null;
}
* indicating who can move or edit the page from the page table, (pre 1.10) rows.
* Edit and move sections are separated by a colon
* Example: "edit=autoconfirmed,sysop:move=sysop"
- * @param bool $readLatest When true, skip replicas and read from the master DB.
*/
- public function loadRestrictionsFromRows(
- $rows, $oldFashionedRestrictions = null, $readLatest = false
- ) {
- $whichDb = $readLatest ? DB_MASTER : DB_REPLICA;
- $dbr = wfGetDB( $whichDb );
+ public function loadRestrictionsFromRows( $rows, $oldFashionedRestrictions = null ) {
+ // This function will only read rows from a table that we migrated away
+ // from before adding READ_LATEST support to loadRestrictions, so we
+ // don't need to support reading from DB_MASTER here.
+ $dbr = wfGetDB( DB_REPLICA );
$restrictionTypes = $this->getRestrictionTypes();
* indicating who can move or edit the page from the page table, (pre 1.10) rows.
* Edit and move sections are separated by a colon
* Example: "edit=autoconfirmed,sysop:move=sysop"
- * @param bool $readLatest When true, skip replicas and read from the master DB.
+ * @param int $flags A bit field. If self::READ_LATEST is set, skip replicas and read
+ * from the master DB.
*/
- public function loadRestrictions( $oldFashionedRestrictions = null, $readLatest = false ) {
+ public function loadRestrictions( $oldFashionedRestrictions = null, $flags = 0 ) {
+ $readLatest = DBAccessObjectUtils::hasFlags( $flags, self::READ_LATEST );
if ( $this->mRestrictionsLoaded && !$readLatest ) {
return;
}
+ // TODO: should probably pass $flags into getArticleID, but it seems hacky
+ // to mix READ_LATEST and GAID_FOR_UPDATE, even if they have the same value.
+ // Maybe deprecate GAID_FOR_UPDATE now that we implement IDBAccessObject?
$id = $this->getArticleID();
if ( $id ) {
- $cache = ObjectCache::getMainWANInstance();
$fname = __METHOD__;
- $rows = $cache->getWithSetCallback(
- // Page protections always leave a new null revision
- $cache->makeKey( 'page-restrictions', $id, $this->getLatestRevID(), $readLatest ),
- $cache::TTL_DAY,
- function ( $curValue, &$ttl, array &$setOpts ) use ( $fname, $readLatest ) {
- $whichDb = $readLatest ? DB_MASTER : DB_REPLICA;
- $dbr = wfGetDB( $whichDb );
-
- $setOpts += Database::getCacheSetOptions( $dbr );
-
- return iterator_to_array(
- $dbr->select(
- 'page_restrictions',
- [ 'pr_type', 'pr_expiry', 'pr_level', 'pr_cascade' ],
- [ 'pr_page' => $this->getArticleID() ],
- $fname
- )
- );
- }
- );
+ $loadRestrictionsFromDb = function ( Database $dbr ) use ( $fname, $id ) {
+ return iterator_to_array(
+ $dbr->select(
+ 'page_restrictions',
+ [ 'pr_type', 'pr_expiry', 'pr_level', 'pr_cascade' ],
+ [ 'pr_page' => $id ],
+ $fname
+ )
+ );
+ };
+
+ if ( $readLatest ) {
+ $dbr = wfGetDB( DB_MASTER );
+ $rows = $loadRestrictionsFromDb( $dbr );
+ } else {
+ $cache = ObjectCache::getMainWANInstance();
+ $rows = $cache->getWithSetCallback(
+ // Page protections always leave a new null revision
+ $cache->makeKey( 'page-restrictions', $id, $this->getLatestRevID() ),
+ $cache::TTL_DAY,
+ function ( $curValue, &$ttl, array &$setOpts ) use ( $loadRestrictionsFromDb ) {
+ $dbr = wfGetDB( DB_REPLICA );
+
+ $setOpts += Database::getCacheSetOptions( $dbr );
+
+ return $loadRestrictionsFromDb( $dbr );
+ }
+ );
+ }
- $this->loadRestrictionsFromRows( $rows, $oldFashionedRestrictions, $readLatest );
+ $this->loadRestrictionsFromRows( $rows, $oldFashionedRestrictions );
} else {
$title_protection = $this->getTitleProtectionInternal();