Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
83.33% covered (warning)
83.33%
45 / 54
91.67% covered (success)
91.67%
11 / 12
CRAP
0.00% covered (danger)
0.00%
0 / 1
TitleValue
84.91% covered (warning)
84.91%
45 / 53
91.67% covered (success)
91.67%
11 / 12
25.98
0.00% covered (danger)
0.00%
0 / 1
 tryNew
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
3
 newFromPage
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 newFromLinkTarget
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
6
 castPageToLinkTarget
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
3
 __construct
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
1
 assertValidSpec
100.00% covered (success)
100.00%
15 / 15
100.00% covered (success)
100.00%
1 / 1
6
 getNamespace
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getFragment
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getDBkey
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 createFragmentTarget
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
1
 getInterwiki
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 __toString
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
3
1<?php
2/**
3 * Representation of a page title within MediaWiki.
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 * http://www.gnu.org/copyleft/gpl.html
19 *
20 * @file
21 * @author Daniel Kinzler
22 */
23
24namespace MediaWiki\Title;
25
26use InvalidArgumentException;
27use MediaWiki\Linker\LinkTarget;
28use MediaWiki\Page\PageReference;
29use Stringable;
30use Wikimedia\Assert\Assert;
31use Wikimedia\Assert\ParameterAssertionException;
32use Wikimedia\Assert\ParameterTypeException;
33use Wikimedia\Parsoid\Core\LinkTarget as ParsoidLinkTarget;
34use Wikimedia\Parsoid\Core\LinkTargetTrait;
35
36/**
37 * Represents the target of a wiki link.
38 *
39 * @note In contrast to Title, this is designed to be a plain value object. That is,
40 * it is immutable, does not use global state, and causes no side effects.
41 *
42 * @newable
43 *
44 * @see https://www.mediawiki.org/wiki/Manual:Modeling_pages
45 * @since 1.23
46 */
47class TitleValue implements Stringable, LinkTarget {
48    use LinkTargetTrait;
49
50    /** @var int */
51    private $namespace;
52
53    /** @var string */
54    private $dbkey;
55
56    /** @var string */
57    private $fragment;
58
59    /** @var string */
60    private $interwiki;
61
62    /**
63     * Text form including namespace/interwiki, initialised on demand
64     *
65     * Only public to share cache with TitleFormatter
66     *
67     * @internal
68     * @var string
69     */
70    public $prefixedText = null;
71
72    /**
73     * Constructs a TitleValue, or returns null if the parameters are not valid.
74     *
75     * @note This does not perform any normalization, and only basic validation.
76     * For full normalization and validation, use TitleParser::makeTitleValueSafe().
77     *
78     * @param int $namespace The namespace ID. This is not validated.
79     * @param string $title The page title in either DBkey or text form. No normalization is applied
80     *   beyond underscore/space conversion.
81     * @param string $fragment The fragment title. Use '' to represent the whole page.
82     *   No validation or normalization is applied.
83     * @param string $interwiki The interwiki component.
84     *   No validation or normalization is applied.
85     * @return TitleValue|null
86     */
87    public static function tryNew( $namespace, $title, $fragment = '', $interwiki = '' ) {
88        if ( !is_int( $namespace ) ) {
89            throw new ParameterTypeException( '$namespace', 'int' );
90        }
91
92        try {
93            return new static( $namespace, $title, $fragment, $interwiki );
94        } catch ( ParameterAssertionException $ex ) {
95            return null;
96        }
97    }
98
99    /**
100     * Create a TitleValue from a local PageReference.
101     *
102     * @note The PageReference may belong to another wiki. In that case, the resulting TitleValue
103     *       is also logically bound to that other wiki. No attempt is made to map the
104     *       PageReference wiki ID to an interwiki prefix for the TitleValue.
105     *
106     * @since 1.36
107     * @param PageReference $page
108     * @return TitleValue
109     */
110    public static function newFromPage( PageReference $page ): TitleValue {
111        return new TitleValue( $page->getNamespace(), $page->getDBkey() );
112    }
113
114    /**
115     * Create a TitleValue from a LinkTarget
116     * @param ParsoidLinkTarget $linkTarget
117     * @return TitleValue
118     * @since 1.42
119     */
120    public static function newFromLinkTarget( ParsoidLinkTarget $linkTarget ): TitleValue {
121        if ( $linkTarget instanceof TitleValue ) {
122            return $linkTarget;
123        }
124        return new TitleValue(
125            $linkTarget->getNamespace(),
126            $linkTarget->getDBkey(),
127            $linkTarget->getFragment(),
128            $linkTarget->getInterwiki()
129        );
130    }
131
132    /**
133     * Casts a PageReference to a LinkTarget.
134     *
135     * If $page is null, null is returned.
136     * If $page is also an instance of LinkTarget, $page is returned unchanged.
137     *
138     * @see newFromPage()
139     * @since 1.37
140     * @param PageReference|null $page
141     * @return LinkTarget|null
142     */
143    public static function castPageToLinkTarget( ?PageReference $page ): ?LinkTarget {
144        if ( !$page || $page instanceof LinkTarget ) {
145            return $page;
146        }
147
148        return self::newFromPage( $page );
149    }
150
151    /**
152     * Construct a TitleValue.
153     *
154     * @note TitleValue expects a valid namespace and name; typically, a TitleValue is constructed
155     * either from a database entry, or by a TitleParser. For constructing a TitleValue from user
156     * input or external sources, use a TitleParser.
157     *
158     * @stable to call
159     * @param int $namespace The namespace ID. This is not validated.
160     * @param string $title The page title in either DBkey or text form. No normalization is applied
161     *   beyond underscore/space conversion.
162     * @param string $fragment The fragment title. Use '' to represent the whole page.
163     *   No validation or normalization is applied.
164     * @param string $interwiki The interwiki component.
165     *   No validation or normalization is applied.
166     */
167    public function __construct( $namespace, $title, $fragment = '', $interwiki = '' ) {
168        self::assertValidSpec( $namespace, $title, $fragment, $interwiki );
169
170        $this->namespace = $namespace;
171        $this->dbkey = strtr( $title, ' ', '_' );
172        $this->fragment = $fragment;
173        $this->interwiki = $interwiki;
174    }
175
176    /**
177     * Assert that the given parameters could be used to construct a TitleValue object.
178     *
179     * Performs basic syntax and consistency checks. Does not perform full validation,
180     * use TitleParser::makeTitleValueSafe() for that.
181     *
182     * @param int $namespace
183     * @param string $title
184     * @param string $fragment
185     * @param string $interwiki
186     * @throws InvalidArgumentException if the combination of parameters is not valid for
187     *  constructing a TitleValue.
188     */
189    public static function assertValidSpec( $namespace, $title, $fragment = '', $interwiki = '' ) {
190        if ( !is_int( $namespace ) ) {
191            throw new ParameterTypeException( '$namespace', 'int' );
192        }
193        if ( !is_string( $title ) ) {
194            throw new ParameterTypeException( '$title', 'string' );
195        }
196        if ( !is_string( $fragment ) ) {
197            throw new ParameterTypeException( '$fragment', 'string' );
198        }
199        if ( !is_string( $interwiki ) ) {
200            throw new ParameterTypeException( '$interwiki', 'string' );
201        }
202
203        Assert::parameter( !preg_match( '/^[_ ]|[\r\n\t]|[_ ]$/', $title ), '$title',
204            "invalid name '$title'" );
205
206        // NOTE: As of MW 1.34, [[#]] is rendered as a valid link, pointing to the empty
207        // page title, effectively leading to the wiki's main page. This means that a completely
208        // empty TitleValue has to be considered valid, for consistency with Title.
209        // Also note that [[#foo]] is a valid on-page section links, and that [[acme:#foo]] is
210        // a valid interwiki link.
211        Assert::parameter(
212            $title !== '' || $namespace === NS_MAIN,
213            '$title',
214            'should not be empty unless namespace is main'
215        );
216    }
217
218    public function getNamespace(): int {
219        return $this->namespace;
220    }
221
222    public function getFragment(): string {
223        return $this->fragment;
224    }
225
226    public function getDBkey(): string {
227        return $this->dbkey;
228    }
229
230    public function createFragmentTarget( string $fragment ): self {
231        return new TitleValue(
232            $this->namespace,
233            $this->dbkey,
234            $fragment,
235            $this->interwiki
236        );
237    }
238
239    public function getInterwiki(): string {
240        return $this->interwiki;
241    }
242
243    /**
244     * Returns a string representation of the title, for logging. This is purely informative
245     * and must not be used programmatically. Use the appropriate TitleFormatter to generate
246     * the correct string representation for a given use.
247     *
248     * @since 1.23
249     * @return string
250     */
251    public function __toString(): string {
252        $name = $this->namespace . ':' . $this->dbkey;
253
254        if ( $this->fragment !== '' ) {
255            $name .= '#' . $this->fragment;
256        }
257
258        if ( $this->interwiki !== '' ) {
259            $name = $this->interwiki . ':' . $name;
260        }
261
262        return $name;
263    }
264}
265
266/** @deprecated class alias since 1.41 */
267class_alias( TitleValue::class, 'TitleValue' );