Add wfDeprecated() call to MimeMagic::singleton()
[lhc/web/wiklou.git] / includes / Title.php
index 0687a15..829be44 100644 (file)
@@ -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;
                }
@@ -754,6 +776,7 @@ class Title implements LinkTarget {
         * @return string Escaped string
         */
        static function escapeFragmentForURL( $fragment ) {
+               wfDeprecated( __METHOD__, '1.30' );
                # Note that we don't urlencode the fragment.  urlencoded Unicode
                # fragments appear not to work in IE (at least up to 7) or in at least
                # one version of Opera 9.x.  The W3C validator, for one, doesn't seem
@@ -777,6 +800,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
@@ -1356,7 +1409,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() {
@@ -1366,6 +1419,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();
                }
        }
@@ -1742,7 +1798,7 @@ class Title implements LinkTarget {
         * @see self::getLocalURL for the arguments.
         * @param array|string $query
         * @param string $proto Protocol type to use in URL
-        * @return String. A url suitable to use in an HTTP location header.
+        * @return string A url suitable to use in an HTTP location header.
         */
        public function getFullUrlForRedirect( $query = '', $proto = PROTO_CURRENT ) {
                $target = $this;
@@ -1920,6 +1976,8 @@ class Title implements LinkTarget {
         * NOTE: Unlike getInternalURL(), the canonical URL includes the fragment
         *
         * @see self::getLocalURL for the arguments.
+        * @param string $query
+        * @param string|bool $query2
         * @return string The URL
         * @since 1.18
         */
@@ -3570,19 +3628,20 @@ class Title implements LinkTarget {
                $blNamespace = "{$prefix}_namespace";
                $blTitle = "{$prefix}_title";
 
+               $pageQuery = WikiPage::getQueryInfo();
                $res = $db->select(
-                       [ $table, 'page' ],
+                       [ $table, 'nestpage' => $pageQuery['tables'] ],
                        array_merge(
                                [ $blNamespace, $blTitle ],
-                               WikiPage::selectFields()
+                               $pageQuery['fields']
                        ),
                        [ "{$prefix}_from" => $id ],
                        __METHOD__,
                        $options,
-                       [ 'page' => [
+                       [ 'nestpage' => [
                                'LEFT JOIN',
                                [ "page_namespace=$blNamespace", "page_title=$blTitle" ]
-                       ] ]
+                       ] ] + $pageQuery['joins']
                );
 
                $retVal = [];
@@ -4135,13 +4194,15 @@ class Title implements LinkTarget {
                $pageId = $this->getArticleID( $flags );
                if ( $pageId ) {
                        $db = ( $flags & self::GAID_FOR_UPDATE ) ? wfGetDB( DB_MASTER ) : wfGetDB( DB_REPLICA );
-                       $row = $db->selectRow( 'revision', Revision::selectFields(),
+                       $revQuery = Revision::getQueryInfo();
+                       $row = $db->selectRow( $revQuery['tables'], $revQuery['fields'],
                                [ 'rev_page' => $pageId ],
                                __METHOD__,
                                [
                                        'ORDER BY' => 'rev_timestamp ASC, rev_id ASC',
-                                       'IGNORE INDEX' => 'rev_timestamp', // See T159319
-                               ]
+                                       'IGNORE INDEX' => [ 'revision' => 'rev_timestamp' ], // See T159319
+                               ],
+                               $revQuery['joins']
                        );
                        if ( $row ) {
                                return new Revision( $row );
@@ -4561,9 +4622,11 @@ class Title implements LinkTarget {
         * on the number of links. Typically called on create and delete.
         */
        public function touchLinks() {
-               DeferredUpdates::addUpdate( new HTMLCacheUpdate( $this, 'pagelinks' ) );
+               DeferredUpdates::addUpdate( new HTMLCacheUpdate( $this, 'pagelinks', 'page-touch' ) );
                if ( $this->getNamespace() == NS_CATEGORY ) {
-                       DeferredUpdates::addUpdate( new HTMLCacheUpdate( $this, 'categorylinks' ) );
+                       DeferredUpdates::addUpdate(
+                               new HTMLCacheUpdate( $this, 'categorylinks', 'category-touch' )
+                       );
                }
        }