1<?php 2/** 3 * This program is free software; you can redistribute it and/or modify 4 * it under the terms of the GNU General Public License as published by 5 * the Free Software Foundation; either version 2 of the License, or 6 * (at your option) any later version. 7 * 8 * This program is distributed in the hope that it will be useful, 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * GNU General Public License for more details. 12 * 13 * You should have received a copy of the GNU General Public License along 14 * with this program; if not, write to the Free Software Foundation, Inc., 15 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 16 * http://www.gnu.org/copyleft/gpl.html 17 * 18 * @file 19 */ 20 21namespace MediaWiki\Page; 22 23use MediaWiki\DAO\WikiAwareEntityTrait; 24use Wikimedia\Assert\Assert; 25use Wikimedia\Assert\ParameterAssertionException; 26use Wikimedia\NonSerializable\NonSerializableTrait; 27 28/** 29 * Immutable value object representing a page identity. 30 * 31 * Instances of this class are expected to always represent proper pages, that is, 32 * pages that can at least potentially exist as editable pages on the wiki. 33 * This class cannot represent Special pages, interwiki links, section links, etc. 34 * 35 * Code that deserializes instances of PageIdentityValue must ensure that the original 36 * meaning of the "local" Wiki ID is preserved: When an instance of PageIdentityValue 37 * is created with self::LOCAL as the Wiki ID on one wiki, gets serialized, 38 * stored, and later read and unserialized on another wiki, the value of the Wiki ID 39 * must be adjusted to refer to the original wiki. 40 * 41 * @since 1.36 42 */ 43class PageIdentityValue implements ProperPageIdentity { 44 45 /* Use JSON, but beware the note on serialization above. */ 46 use NonSerializableTrait; 47 use WikiAwareEntityTrait; 48 49 /** @var int */ 50 private $pageId; 51 52 /** @var int */ 53 private $namespace; 54 55 /** @var string */ 56 private $dbKey; 57 58 /** @var bool|string */ 59 private $wikiId; 60 61 /** 62 * @param int $pageId The ID of this page, or 0 if the page does not exist. 63 * @param int $namespace A valid namespace ID. Validation is the caller's responsibility! 64 * @param string $dbKey A valid DB key. Validation is the caller's responsibility! 65 * @param string|bool $wikiId The Id of the wiki this page belongs to, 66 * or self::LOCAL for the local wiki. 67 */ 68 public function __construct( int $pageId, int $namespace, string $dbKey, $wikiId ) { 69 Assert::parameter( $pageId >= 0, '$pageId', 'must not be negative' ); 70 Assert::parameter( $namespace >= 0, '$namespace', 'must not be negative' ); 71 $this->assertWikiIdParam( $wikiId ); 72 73 if ( $dbKey === '' ) { 74 throw new ParameterAssertionException( 75 '$dbKey', 76 'PageIdentityValue cannot be created for an empty title.' 77 ); 78 } 79 80 // Don't be mad about spaces. 81 $dbKey = str_replace( ' ', '_', $dbKey ); 82 83 // Not full validation, but catches commons issues: 84 if ( preg_match( '/[\s#|]/', $dbKey ) ) { 85 throw new ParameterAssertionException( 86 '$dbKey', 87 'PageIdentityValue contains a bad character: ' . $dbKey 88 ); 89 } 90 91 $this->pageId = $pageId; 92 $this->wikiId = $wikiId; 93 $this->namespace = $namespace; 94 $this->dbKey = $dbKey; 95 } 96 97 /** 98 * Get the ID of the wiki provided to the constructor. 99 * 100 * @return string|false 101 */ 102 public function getWikiId() { 103 return $this->wikiId; 104 } 105 106 /** 107 * The numerical page ID provided to the constructor. 108 * 109 * @param string|false $wikiId The wiki ID expected by the caller. 110 * Omit if expecting the local wiki. 111 * 112 * @return int 113 */ 114 public function getId( $wikiId = self::LOCAL ): int { 115 $this->assertWiki( $wikiId ); 116 return $this->pageId; 117 } 118 119 /** 120 * Returns whether the page currently exists. 121 * Returns true if getId() returns a value greater than zero. 122 * @return bool 123 */ 124 public function exists(): bool { 125 return $this->getId( $this->wikiId ) > 0; 126 } 127 128 /** 129 * @return bool always true 130 */ 131 public function canExist(): bool { 132 return true; 133 } 134 135 /** 136 * @inheritDoc 137 * 138 * @return int 139 */ 140 public function getNamespace(): int { 141 return $this->namespace; 142 } 143 144 /** 145 * @inheritDoc 146 * 147 * @return string 148 */ 149 public function getDBkey(): string { 150 return $this->dbKey; 151 } 152 153 /** 154 * Returns a string representation of the title, for logging. This is purely informative 155 * and must not be used programmatically. 156 * 157 * @return string 158 */ 159 public function __toString(): string { 160 $name = '#' . $this->pageId; 161 162 if ( $this->wikiId ) { 163 $name .= '@' . $this->wikiId; 164 } 165 166 return $name . ' [' . $this->namespace . ':' . $this->dbKey . ']'; 167 } 168 169 /** 170 * @param PageIdentity $other 171 * 172 * @return bool 173 */ 174 public function isSamePageAs( PageIdentity $other ) { 175 // NOTE: keep in sync with Title::isSamePageAs()! 176 // NOTE: keep in sync with WikiPage::isSamePageAs()! 177 178 $wikiId = $this->getWikiId(); 179 if ( $other->getWikiId() !== $wikiId 180 || $other->getId( $wikiId ) !== $this->getId( $wikiId ) ) { 181 return false; 182 } 183 184 if ( $this->getId( $wikiId ) === 0 ) { 185 if ( $other->getNamespace() !== $this->getNamespace() 186 || $other->getDBkey() !== $this->getDBkey() ) { 187 return false; 188 } 189 } 190 191 return true; 192 } 193 194} 195