32 'NamespaceProtection',
35 'SemiprotectedRestrictionLevels',
120 return $restrictions[$action] ?? [];
133 if ( !$this->areRestrictionsLoaded( $page ) ) {
134 $this->loadRestrictions( $page );
136 return $this->cache[CacheKeyHelper::getKeyForPage( $page )][
'restrictions'] ?? [];
151 if ( !$this->areRestrictionsLoaded( $page ) ) {
152 $this->loadRestrictions( $page );
154 return $this->cache[CacheKeyHelper::getKeyForPage( $page )][
'expiry'][$action] ??
null;
174 $protection = $this->getCreateProtectionInternal( $page );
177 if ( $protection[
'permission'] ==
'sysop' ) {
178 $protection[
'permission'] =
'editprotected';
180 if ( $protection[
'permission'] ==
'autoconfirmed' ) {
181 $protection[
'permission'] =
'editsemiprotected';
196 $dbw = $this->loadBalancer->getConnectionRef(
DB_PRIMARY );
202 $this->cache[CacheKeyHelper::getKeyForPage( $page )][
'create_protection'] =
null;
216 $restrictions = $this->getRestrictions( $page, $action );
217 $semi = $this->options->get(
'SemiprotectedRestrictionLevels' );
218 if ( !$restrictions || !$semi ) {
224 foreach ( array_keys( $semi,
'editsemiprotected' ) as $key ) {
225 $semi[$key] =
'autoconfirmed';
227 foreach ( array_keys( $restrictions,
'editsemiprotected' ) as $key ) {
228 $restrictions[$key] =
'autoconfirmed';
231 return !array_diff( $restrictions, $semi );
250 $applicableTypes = $this->listApplicableRestrictionTypes( $page );
252 if ( $action ===
'' ) {
253 foreach ( $applicableTypes as
$type ) {
254 if ( $this->isProtected( $page,
$type ) ) {
261 if ( !in_array( $action, $applicableTypes ) ) {
265 return (
bool)array_diff(
267 $this->getRestrictions( $page, $action ),
268 $this->options->get(
'RestrictionLevels' )
283 return $this->getCascadeProtectionSourcesInternal( $page,
true );
299 $types = $this->listAllRestrictionTypes( $page->
exists() );
303 $types = array_values( array_diff( $types, [
'upload' ] ) );
306 if ( $this->hookContainer->isRegistered(
'TitleGetRestrictionTypes' ) ) {
307 $this->hookRunner->onTitleGetRestrictionTypes(
308 Title::castFromPageIdentity( $page ), $types );
322 $types = $this->options->get(
'RestrictionTypes' );
325 return array_values( array_diff( $types, [
'create' ] ) );
329 return array_values( array_intersect( $types, [
'create',
'upload' ] ) );
344 PageIdentity $page,
int $flags = IDBAccessObject::READ_NORMAL, ?
string $oldRestrictions =
null
352 $readLatest = DBAccessObjectUtils::hasFlags( $flags, IDBAccessObject::READ_LATEST );
354 if ( $this->areRestrictionsLoaded( $page ) && !$readLatest ) {
358 $cacheEntry = &$this->cache[CacheKeyHelper::getKeyForPage( $page )];
360 $cacheEntry[
'restrictions'] = [];
364 $page = $this->pageStore->getPageByReference( $page, $flags ) ?? $page;
366 $id = $page->
getId();
369 $loadRestrictionsFromDb =
static function ( IDatabase
$dbr ) use ( $fname, $id ) {
370 return iterator_to_array(
373 [
'pr_type',
'pr_expiry',
'pr_level',
'pr_cascade' ],
374 [
'pr_page' => $id ],
382 $rows = $loadRestrictionsFromDb(
$dbr );
384 $this->linkCache->addLinkObj( $page );
385 $latestRev = $this->linkCache->getGoodLinkFieldObj( $page,
'revision' );
386 $rows = $this->wanCache->getWithSetCallback(
388 $this->wanCache->makeKey(
'page-restrictions',
'v1', $id, $latestRev ),
389 $this->wanCache::TTL_DAY,
390 function ( $curValue, &$ttl, array &$setOpts ) use ( $loadRestrictionsFromDb ) {
392 $setOpts += Database::getCacheSetOptions(
$dbr );
393 if ( $this->loadBalancer->hasOrMadeRecentPrimaryChanges() ) {
395 $ttl = WANObjectCache::TTL_UNCACHEABLE;
398 return $loadRestrictionsFromDb(
$dbr );
403 $this->loadRestrictionsFromRows( $page, $rows, $oldRestrictions );
405 $titleProtection = $this->getCreateProtectionInternal( $page );
407 if ( $titleProtection ) {
409 $expiry = $titleProtection[
'expiry'];
411 if ( !$expiry || $expiry > $now ) {
413 $cacheEntry[
'expiry'][
'create'] = $expiry ?:
null;
414 $cacheEntry[
'restrictions'][
'create'] =
415 explode(
',', trim( $titleProtection[
'permission'] ) );
418 $cacheEntry[
'create_protection'] =
null;
421 $cacheEntry[
'expiry'][
'create'] =
'infinity';
437 PageIdentity $page, array $rows, ?
string $oldRestrictions =
null
441 $cacheEntry = &$this->cache[CacheKeyHelper::getKeyForPage( $page )];
443 $restrictionTypes = $this->listApplicableRestrictionTypes( $page );
445 foreach ( $restrictionTypes as
$type ) {
446 $cacheEntry[
'restrictions'][
$type] = [];
447 $cacheEntry[
'expiry'][
$type] =
'infinity';
450 $cacheEntry[
'cascade'] =
false;
455 $cacheEntry[
'oldRestrictions'] = $oldRestrictions ?? $cacheEntry[
'oldRestrictions'] ??
null;
457 if ( $cacheEntry[
'oldRestrictions'] ===
null ) {
458 $this->linkCache->addLinkObj( $page );
459 $cachedOldRestrictions = $this->linkCache->getGoodLinkFieldObj( $page,
'restrictions' );
460 if ( $cachedOldRestrictions !==
null ) {
461 $cacheEntry[
'oldRestrictions'] = $cachedOldRestrictions;
465 if ( $cacheEntry[
'oldRestrictions'] ) {
466 $cacheEntry[
'restrictions'] =
467 $this->convertOldRestrictions( $cacheEntry[
'oldRestrictions'] );
479 foreach ( $rows as $row ) {
481 if ( !in_array( $row->pr_type, $restrictionTypes ) ) {
486 $expiry =
$dbr->decodeExpiry( $row->pr_expiry );
491 if ( !$expiry || $expiry > $now ) {
492 $cacheEntry[
'expiry'][$row->pr_type] = $expiry ?:
null;
493 $cacheEntry[
'restrictions'][$row->pr_type]
494 = explode(
',', trim( $row->pr_level ) );
495 if ( $row->pr_cascade ) {
496 $cacheEntry[
'cascade'] =
true;
513 foreach ( explode(
':', trim( $oldRestrictions ) ) as $restrict ) {
514 $restrictionPair = explode(
'=', trim( $restrict ) );
515 if ( count( $restrictionPair ) == 1 ) {
517 $ret[
'edit'] = explode(
',', trim( $restrictionPair[0] ) );
518 $ret[
'move'] = explode(
',', trim( $restrictionPair[0] ) );
520 $restriction = trim( $restrictionPair[1] );
521 if ( $restriction !=
'' ) {
522 $ret[$restrictionPair[0]] = explode(
',', $restriction );
541 if ( !$page->canExist() ) {
550 $cacheEntry = &$this->cache[CacheKeyHelper::getKeyForPage( $page )];
552 if ( !$cacheEntry || !array_key_exists(
'create_protection', $cacheEntry ) ) {
554 $commentQuery = $this->commentStore->getJoin(
'pt_reason' );
555 $row =
$dbr->selectRow(
556 [
'protected_titles' ] + $commentQuery[
'tables'],
557 [
'pt_user',
'pt_expiry',
'pt_create_perm' ] + $commentQuery[
'fields'],
561 $commentQuery[
'joins']
565 $cacheEntry[
'create_protection'] = [
566 'user' => $row->pt_user,
567 'expiry' =>
$dbr->decodeExpiry( $row->pt_expiry ),
568 'permission' => $row->pt_create_perm,
569 'reason' => $this->commentStore->getComment(
'pt_reason', $row )->text,
572 $cacheEntry[
'create_protection'] =
null;
577 return $cacheEntry[
'create_protection'];
593 return $this->getCascadeProtectionSourcesInternal( $page,
false );
607 $cacheEntry = &$this->cache[CacheKeyHelper::getKeyForPage( $page )];
609 if ( !$shortCircuit && isset( $cacheEntry[
'cascade_sources'] ) ) {
610 return $cacheEntry[
'cascade_sources'];
611 } elseif ( $shortCircuit && isset( $cacheEntry[
'has_cascading'] ) ) {
612 return $cacheEntry[
'has_cascading'];
618 $tables = [
'imagelinks',
'page_restrictions' ];
625 $tables = [
'templatelinks',
'page_restrictions' ];
634 if ( $shortCircuit ) {
635 $cols = [
'pr_expiry' ];
637 $cols = [
'pr_page',
'page_namespace',
'page_title',
638 'pr_expiry',
'pr_type',
'pr_level' ];
639 $where_clauses[] =
'page_id=pr_page';
644 $res =
$dbr->select( $tables, $cols, $where_clauses, __METHOD__ );
647 $pageRestrictions = [];
650 foreach (
$res as $row ) {
651 $expiry =
$dbr->decodeExpiry( $row->pr_expiry );
652 if ( $expiry > $now ) {
653 if ( $shortCircuit ) {
654 $cacheEntry[
'has_cascading'] =
true;
659 $row->page_namespace, $row->page_title, PageIdentity::LOCAL );
663 if ( !isset( $pageRestrictions[$row->pr_type] ) ) {
664 $pageRestrictions[$row->pr_type] = [];
667 if ( !in_array( $row->pr_level, $pageRestrictions[$row->pr_type] ) ) {
668 $pageRestrictions[$row->pr_type][] = $row->pr_level;
673 $cacheEntry[
'has_cascading'] = (bool)$sources;
675 if ( $shortCircuit ) {
679 $cacheEntry[
'cascade_sources'] = [ $sources, $pageRestrictions ];
680 return [ $sources, $pageRestrictions ];
691 return isset( $this->cache[CacheKeyHelper::getKeyForPage( $page )][
'restrictions'] );
703 return isset( $this->cache[CacheKeyHelper::getKeyForPage( $page )][
'cascade_sources'] );
715 if ( !$this->areRestrictionsLoaded( $page ) ) {
716 $this->loadRestrictions( $page );
718 return $this->cache[CacheKeyHelper::getKeyForPage( $page )][
'cascade'] ??
false;
731 unset( $this->cache[CacheKeyHelper::getKeyForPage( $page )] );
747 $this->cache[CacheKeyHelper::getKeyForPage( $page )][
'oldRestrictions'] =
wfTimestampNow()
Convenience function; returns MediaWiki timestamp for the present time.
if(ini_get('mbstring.func_overload')) if(!defined('MW_ENTRY_POINT'))
Pre-config setup: Before loading LocalSettings.php.
Helper class for DAO classes.
Cache for article titles (prefixed DB keys) and ids linked from one source.
Immutable value object representing a page identity.
Represents a title within MediaWiki.
Multi-datacenter aware caching interface.
Interface for database access objects.
Interface for objects (potentially) representing an editable wiki page.
getId( $wikiId=self::LOCAL)
Returns the page ID.
canExist()
Checks whether this PageIdentity represents a "proper" page, meaning that it could exist as an editab...
exists()
Checks if the page currently exists.