X-Git-Url: https://git.heureux-cyclage.org/?a=blobdiff_plain;f=includes%2FTitle.php;h=8cfeb882a0f67e181dfc890a45d30ec772f8559d;hb=f629d095f0469dc9fa29143a8efdc498ee634730;hp=05f85fa47d44737818071293ffeb056fb8552224;hpb=a8ec960e9d910acbcd0d50efad3bd73e3ae812aa;p=lhc%2Fweb%2Fwiklou.git diff --git a/includes/Title.php b/includes/Title.php index 05f85fa47d..8cfeb882a0 100644 --- a/includes/Title.php +++ b/includes/Title.php @@ -253,6 +253,9 @@ class Title implements LinkTarget { * Create a new Title from text, such as what one would find in a link. De- * codes any HTML entities in the text. * + * Title objects returned by this method are guaranteed to be valid, and + * thus return true from the isValid() method. + * * @param string|int|null $text The link text; spaces, prefixes, and an * initial ':' indicating the main namespace are accepted. * @param int $defaultNamespace The namespace to use if none is specified @@ -284,6 +287,9 @@ class Title implements LinkTarget { * * The exception subclasses encode detailed information about why the title is invalid. * + * Title objects returned by this method are guaranteed to be valid, and + * thus return true from the isValid() method. + * * @see Title::newFromText * * @since 1.25 @@ -500,10 +506,19 @@ class Title implements LinkTarget { /** * Create a new Title from a namespace index and a DB key. - * It's assumed that $ns and $title are *valid*, for instance when - * they came directly from the database or a special page name. - * For convenience, spaces are converted to underscores so that - * eg user_text fields can be used directly. + * + * It's assumed that $ns and $title are safe, for instance when + * they came directly from the database or a special page name, + * not from user input. + * + * No validation is applied. For convenience, spaces are normalized + * to underscores, so that e.g. user_text fields can be used directly. + * + * @note This method may return Title objects that are "invalid" + * according to the isValid() method. This is usually caused by + * configuration changes: e.g. a namespace that was once defined is + * no longer configured, or a character that was once allowed in + * titles is now forbidden. * * @param int $ns The namespace of the article * @param string $title The unprefixed database key form @@ -529,6 +544,10 @@ class Title implements LinkTarget { * The parameters will be checked for validity, which is a bit slower * than makeTitle() but safer for user-provided data. * + * Title objects returned by makeTitleSafe() are guaranteed to be valid, + * that is, they return true from the isValid() method. If no valid Title + * can be constructed from the input, this method returns null. + * * @param int $ns The namespace of the article * @param string $title Database key form * @param string $fragment The link fragment (after the "#") @@ -536,6 +555,9 @@ class Title implements LinkTarget { * @return Title|null The new object, or null on an error */ public static function makeTitleSafe( $ns, $title, $fragment = '', $interwiki = '' ) { + // NOTE: ideally, this would just call makeTitle() and then isValid(), + // but presently, that means more overhead on a potential performance hotspot. + if ( !MWNamespace::exists( $ns ) ) { return null; } @@ -777,6 +799,36 @@ class Title implements LinkTarget { } } + /** + * Returns true if the title is valid, false if it is invalid. + * + * Valid titles can be round-tripped via makeTitleSafe() and newFromText(). + * Invalid titles may get returned from makeTitle(), and it may be useful to + * allow them to exist, e.g. in order to process log entries about pages in + * namespaces that belong to extensions that are no longer installed. + * + * @note This method is relatively expensive. When constructing Title + * objects that need to be valid, use an instantiator method that is guaranteed + * to return valid titles, such as makeTitleSafe() or newFromText(). + * + * @return bool + */ + public function isValid() { + $ns = $this->getNamespace(); + + if ( !MWNamespace::exists( $ns ) ) { + return false; + } + + try { + $parser = MediaWikiServices::getInstance()->getTitleParser(); + $parser->parseTitle( $this->getDBkey(), $ns ); + return true; + } catch ( MalformedTitleException $ex ) { + return false; + } + } + /** * Determine whether the object refers to a page within * this project (either this wiki or a wiki with a local @@ -1036,6 +1088,7 @@ class Title implements LinkTarget { * Can this title have a corresponding talk page? * * @see MWNamespace::hasTalkNamespace + * @since 1.30 * * @return bool True if this title either is a talk page or can have a talk page associated. */ @@ -1324,7 +1377,7 @@ class Title implements LinkTarget { * * @since 1.30 * - * @return Title The object for the talk page, + * @return Title|null The object for the talk page, * or null if no associated talk page can exist, according to canHaveTalkPage(). */ public function getTalkPageIfDefined() { @@ -1355,7 +1408,7 @@ class Title implements LinkTarget { * get the talk page, if it is a subject page get the talk page * * @since 1.25 - * @throws MWException + * @throws MWException If the page doesn't have an other page * @return Title */ public function getOtherPage() { @@ -1365,6 +1418,9 @@ class Title implements LinkTarget { if ( $this->isTalkPage() ) { return $this->getSubjectPage(); } else { + if ( !$this->canHaveTalkPage() ) { + throw new MWException( "{$this->getPrefixedText()} does not have an other page" ); + } return $this->getTalkPage(); } } @@ -2669,24 +2725,33 @@ class Title implements LinkTarget { if ( $this->mTitleProtection === null ) { $dbr = wfGetDB( DB_REPLICA ); + $commentStore = new CommentStore( 'pt_reason' ); + $commentQuery = $commentStore->getJoin(); $res = $dbr->select( - 'protected_titles', + [ 'protected_titles' ] + $commentQuery['tables'], [ 'user' => 'pt_user', - 'reason' => 'pt_reason', 'expiry' => 'pt_expiry', 'permission' => 'pt_create_perm' - ], + ] + $commentQuery['fields'], [ 'pt_namespace' => $this->getNamespace(), 'pt_title' => $this->getDBkey() ], - __METHOD__ + __METHOD__, + [], + $commentQuery['joins'] ); // fetchRow returns false if there are no rows. $row = $dbr->fetchRow( $res ); if ( $row ) { - $row['expiry'] = $dbr->decodeExpiry( $row['expiry'] ); + $this->mTitleProtection = [ + 'user' => $row['user'], + 'expiry' => $dbr->decodeExpiry( $row['expiry'] ), + 'permission' => $row['permission'], + 'reason' => $commentStore->getComment( $row )->text, + ]; + } else { + $this->mTitleProtection = false; } - $this->mTitleProtection = $row; } return $this->mTitleProtection; }