128 return $restrictions[
$action] ?? [];
141 if ( !$this->areRestrictionsLoaded( $page ) ) {
142 $this->loadRestrictions( $page );
159 if ( !$this->areRestrictionsLoaded( $page ) ) {
160 $this->loadRestrictions( $page );
162 return $this->cache[CacheKeyHelper::getKeyForPage( $page )][
'expiry'][$action] ??
null;
182 $protection = $this->getCreateProtectionInternal( $page );
185 if ( $protection[
'permission'] ==
'sysop' ) {
186 $protection[
'permission'] =
'editprotected';
188 if ( $protection[
'permission'] ==
'autoconfirmed' ) {
189 $protection[
'permission'] =
'editsemiprotected';
204 $dbw = $this->loadBalancer->getConnectionRef(
DB_PRIMARY );
210 $this->cache[CacheKeyHelper::getKeyForPage( $page )][
'create_protection'] =
null;
224 $restrictions = $this->getRestrictions( $page, $action );
225 $semi = $this->options->get( MainConfigNames::SemiprotectedRestrictionLevels );
226 if ( !$restrictions || !$semi ) {
232 foreach ( array_keys( $semi,
'editsemiprotected' ) as $key ) {
233 $semi[$key] =
'autoconfirmed';
235 foreach ( array_keys( $restrictions,
'editsemiprotected' ) as $key ) {
236 $restrictions[$key] =
'autoconfirmed';
239 return !array_diff( $restrictions, $semi );
258 $applicableTypes = $this->listApplicableRestrictionTypes( $page );
260 if ( $action ===
'' ) {
261 foreach ( $applicableTypes as
$type ) {
262 if ( $this->isProtected( $page,
$type ) ) {
269 if ( !in_array( $action, $applicableTypes ) ) {
273 return (
bool)array_diff(
275 $this->getRestrictions( $page, $action ),
276 $this->options->get( MainConfigNames::RestrictionLevels )
291 return $this->getCascadeProtectionSourcesInternal( $page,
true );
307 $types = $this->listAllRestrictionTypes( $page->
exists() );
311 $types = array_values( array_diff( $types, [
'upload' ] ) );
314 if ( $this->hookContainer->isRegistered(
'TitleGetRestrictionTypes' ) ) {
315 $this->hookRunner->onTitleGetRestrictionTypes(
334 return array_values( array_diff( $types, [
'create' ] ) );
338 return array_values( array_intersect( $types, [
'create',
'upload' ] ) );
350 PageIdentity $page,
int $flags = IDBAccessObject::READ_NORMAL
360 if ( $this->areRestrictionsLoaded( $page ) && !$readLatest ) {
364 $cacheEntry = &$this->cache[CacheKeyHelper::getKeyForPage( $page )];
366 $cacheEntry[
'restrictions'] = [];
370 $page = $this->pageStore->getPageByReference( $page, $flags ) ?? $page;
372 $id = $page->
getId();
375 $loadRestrictionsFromDb =
static function ( IDatabase
$dbr ) use ( $fname, $id ) {
376 return iterator_to_array(
379 [
'pr_type',
'pr_expiry',
'pr_level',
'pr_cascade' ],
380 [
'pr_page' => $id ],
388 $rows = $loadRestrictionsFromDb(
$dbr );
390 $this->linkCache->addLinkObj( $page );
391 $latestRev = $this->linkCache->getGoodLinkFieldObj( $page,
'revision' );
392 $rows = $this->wanCache->getWithSetCallback(
394 $this->wanCache->makeKey(
'page-restrictions',
'v1', $id, $latestRev ),
395 $this->wanCache::TTL_DAY,
396 function ( $curValue, &$ttl, array &$setOpts ) use ( $loadRestrictionsFromDb ) {
398 $setOpts += Database::getCacheSetOptions(
$dbr );
399 if ( $this->loadBalancer->hasOrMadeRecentPrimaryChanges() ) {
401 $ttl = WANObjectCache::TTL_UNCACHEABLE;
404 return $loadRestrictionsFromDb(
$dbr );
409 $this->loadRestrictionsFromRows( $page, $rows );
411 $titleProtection = $this->getCreateProtectionInternal( $page );
413 if ( $titleProtection ) {
415 $expiry = $titleProtection[
'expiry'];
417 if ( !$expiry || $expiry > $now ) {
419 $cacheEntry[
'expiry'][
'create'] = $expiry ?:
null;
420 $cacheEntry[
'restrictions'][
'create'] =
421 explode(
',', trim( $titleProtection[
'permission'] ) );
424 $cacheEntry[
'create_protection'] =
null;
427 $cacheEntry[
'expiry'][
'create'] =
'infinity';
444 $cacheEntry = &$this->cache[CacheKeyHelper::getKeyForPage( $page )];
446 $restrictionTypes = $this->listApplicableRestrictionTypes( $page );
448 foreach ( $restrictionTypes as
$type ) {
449 $cacheEntry[
'restrictions'][
$type] = [];
450 $cacheEntry[
'expiry'][
$type] =
'infinity';
453 $cacheEntry[
'cascade'] =
false;
463 foreach ( $rows as $row ) {
465 if ( !in_array( $row->pr_type, $restrictionTypes ) ) {
470 $expiry =
$dbr->decodeExpiry( $row->pr_expiry );
475 if ( !$expiry || $expiry > $now ) {
476 $cacheEntry[
'expiry'][$row->pr_type] = $expiry ?:
null;
477 $cacheEntry[
'restrictions'][$row->pr_type]
478 = explode(
',', trim( $row->pr_level ) );
479 if ( $row->pr_cascade ) {
480 $cacheEntry[
'cascade'] =
true;
498 if ( !$page->canExist() ) {
507 $cacheEntry = &$this->cache[CacheKeyHelper::getKeyForPage( $page )];
509 if ( !$cacheEntry || !array_key_exists(
'create_protection', $cacheEntry ) ) {
511 $commentQuery = $this->commentStore->getJoin(
'pt_reason' );
512 $row =
$dbr->selectRow(
513 [
'protected_titles' ] + $commentQuery[
'tables'],
514 [
'pt_user',
'pt_expiry',
'pt_create_perm' ] + $commentQuery[
'fields'],
518 $commentQuery[
'joins']
522 $cacheEntry[
'create_protection'] = [
523 'user' => $row->pt_user,
524 'expiry' =>
$dbr->decodeExpiry( $row->pt_expiry ),
525 'permission' => $row->pt_create_perm,
526 'reason' => $this->commentStore->getComment(
'pt_reason', $row )->text,
529 $cacheEntry[
'create_protection'] =
null;
534 return $cacheEntry[
'create_protection'];
550 return $this->getCascadeProtectionSourcesInternal( $page,
false );
564 $cacheEntry = &$this->cache[CacheKeyHelper::getKeyForPage( $page )];
566 if ( !$shortCircuit && isset( $cacheEntry[
'cascade_sources'] ) ) {
567 return $cacheEntry[
'cascade_sources'];
568 } elseif ( $shortCircuit && isset( $cacheEntry[
'has_cascading'] ) ) {
569 return $cacheEntry[
'has_cascading'];
575 $tables = [
'imagelinks',
'page_restrictions' ];
582 $tables = [
'templatelinks',
'page_restrictions' ];
583 $where_clauses = $this->linksMigration->getLinksConditions(
587 $where_clauses[] =
'tl_from=pr_page';
588 $where_clauses[
'pr_cascade'] = 1;
591 if ( $shortCircuit ) {
592 $cols = [
'pr_expiry' ];
594 $cols = [
'pr_page',
'page_namespace',
'page_title',
595 'pr_expiry',
'pr_type',
'pr_level' ];
596 $where_clauses[] =
'page_id=pr_page';
601 $res =
$dbr->select( $tables, $cols, $where_clauses, __METHOD__ );
604 $pageRestrictions = [];
607 foreach (
$res as $row ) {
608 $expiry =
$dbr->decodeExpiry( $row->pr_expiry );
609 if ( $expiry > $now ) {
610 if ( $shortCircuit ) {
611 $cacheEntry[
'has_cascading'] =
true;
616 $row->page_namespace, $row->page_title, PageIdentity::LOCAL );
620 if ( !isset( $pageRestrictions[$row->pr_type] ) ) {
621 $pageRestrictions[$row->pr_type] = [];
624 if ( !in_array( $row->pr_level, $pageRestrictions[$row->pr_type] ) ) {
625 $pageRestrictions[$row->pr_type][] = $row->pr_level;
630 $cacheEntry[
'has_cascading'] = (bool)$sources;
632 if ( $shortCircuit ) {
636 $cacheEntry[
'cascade_sources'] = [ $sources, $pageRestrictions ];
637 return [ $sources, $pageRestrictions ];
648 return isset( $this->cache[CacheKeyHelper::getKeyForPage( $page )][
'restrictions'] );
660 return isset( $this->cache[CacheKeyHelper::getKeyForPage( $page )][
'cascade_sources'] );
672 if ( !$this->areRestrictionsLoaded( $page ) ) {
673 $this->loadRestrictions( $page );
675 return $this->cache[CacheKeyHelper::getKeyForPage( $page )][
'cascade'] ??
false;
688 unset( $this->cache[CacheKeyHelper::getKeyForPage( $page )] );
wfTimestampNow()
Convenience function; returns MediaWiki timestamp for the present time.
if(!defined('MW_SETUP_CALLBACK'))
The persistent session ID (if any) loaded at startup.
Helper class for DAO classes.
static hasFlags( $bitfield, $flags)
Cache for article titles (prefixed DB keys) and ids linked from one source.
A class containing constants representing the names of configuration variables.
const NamespaceProtection
Name constant for the NamespaceProtection setting, for use with Config::get()
const RestrictionTypes
Name constant for the RestrictionTypes setting, for use with Config::get()
const SemiprotectedRestrictionLevels
Name constant for the SemiprotectedRestrictionLevels setting, for use with Config::get()
const RestrictionLevels
Name constant for the RestrictionLevels setting, for use with Config::get()
Immutable value object representing a page identity.
Represents a page (or page fragment) title within MediaWiki.
static newFromPage(PageReference $page)
Create a TitleValue from a local PageReference.
Represents a title within MediaWiki.
static castFromPageIdentity(?PageIdentity $pageIdentity)
Return a Title for a given PageIdentity.
Multi-datacenter aware caching interface.
Interface for database access objects.
Interface for objects (potentially) representing an editable wiki page.
exists()
Checks if the page currently exists.
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...