Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
81.82% covered (warning)
81.82%
36 / 44
83.33% covered (warning)
83.33%
5 / 6
CRAP
0.00% covered (danger)
0.00%
0 / 1
TitleDef
81.82% covered (warning)
81.82%
36 / 44
83.33% covered (warning)
83.33%
5 / 6
19.95
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 validate
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
1 / 1
5
 stringifyValue
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 checkSettings
57.89% covered (warning)
57.89%
11 / 19
0.00% covered (danger)
0.00%
0 / 1
10.66
 getParamInfo
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 getHelpInfo
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
2
1<?php
2
3namespace MediaWiki\ParamValidator\TypeDef;
4
5use MediaWiki\Linker\LinkTarget;
6use MediaWiki\Title\TitleFactory;
7use Wikimedia\Message\MessageValue;
8use Wikimedia\ParamValidator\Callbacks;
9use Wikimedia\ParamValidator\ParamValidator;
10use Wikimedia\ParamValidator\TypeDef;
11
12/**
13 * Type definition for page titles.
14 *
15 * Failure codes:
16 * - 'badtitle': invalid title (e.g. containing disallowed characters). No data.
17 * - 'missingtitle': the page with this title does not exist (when PARAM_MUST_EXIST
18 *   was specified). No data.
19 *
20 * @since 1.36
21 */
22class TitleDef extends TypeDef {
23
24    /**
25     * (bool) Whether the page with the given title needs to exist.
26     *
27     * Defaults to false.
28     */
29    public const PARAM_MUST_EXIST = 'param-must-exist';
30
31    /**
32     * (bool) Whether to return a LinkTarget.
33     *
34     * If false, the validated title is returned as a string (in getPrefixedText() format).
35     * Default is false.
36     *
37     * Avoid setting true with PARAM_ISMULTI, as it may result in excessive DB
38     * lookups. If you do combine them, consider setting low values for
39     * PARAM_ISMULTI_LIMIT1 and PARAM_ISMULTI_LIMIT2 to mitigate it.
40     */
41    public const PARAM_RETURN_OBJECT = 'param-return-object';
42
43    /** @var TitleFactory */
44    private $titleFactory;
45
46    /**
47     * @param Callbacks $callbacks
48     * @param TitleFactory $titleFactory
49     */
50    public function __construct( Callbacks $callbacks, TitleFactory $titleFactory ) {
51        parent::__construct( $callbacks );
52        $this->titleFactory = $titleFactory;
53    }
54
55    /**
56     * @inheritDoc
57     * @return string|LinkTarget Depending on the PARAM_RETURN_OBJECT setting.
58     */
59    public function validate( $name, $value, array $settings, array $options ) {
60        $mustExist = !empty( $settings[self::PARAM_MUST_EXIST] );
61        $returnObject = !empty( $settings[self::PARAM_RETURN_OBJECT] );
62
63        $title = $this->titleFactory->newFromText( $value );
64
65        if ( !$title ) {
66            // Message used: paramvalidator-badtitle
67            $this->failure( 'badtitle', $name, $value, $settings, $options );
68        } elseif ( $mustExist && !$title->exists() ) {
69            // Message used: paramvalidator-missingtitle
70            $this->failure( 'missingtitle', $name, $value, $settings, $options );
71        }
72
73        if ( $returnObject ) {
74            return $title->getTitleValue();
75        } else {
76            return $title->getPrefixedText();
77        }
78    }
79
80    /** @inheritDoc */
81    public function stringifyValue( $name, $value, array $settings, array $options ) {
82        if ( $value instanceof LinkTarget ) {
83            return $this->titleFactory->newFromLinkTarget( $value )->getPrefixedText();
84        }
85        return parent::stringifyValue( $name, $value, $settings, $options );
86    }
87
88    /** @inheritDoc */
89    public function checkSettings( string $name, $settings, array $options, array $ret ): array {
90        $ret = parent::checkSettings( $name, $settings, $options, $ret );
91
92        $ret['allowedKeys'] = array_merge( $ret['allowedKeys'], [
93            self::PARAM_MUST_EXIST, self::PARAM_RETURN_OBJECT,
94        ] );
95
96        if ( !is_bool( $settings[self::PARAM_MUST_EXIST] ?? false ) ) {
97            $ret['issues'][self::PARAM_MUST_EXIST] = 'PARAM_MUST_EXIST must be boolean, got '
98                . gettype( $settings[self::PARAM_MUST_EXIST] );
99        }
100
101        if ( !is_bool( $settings[self::PARAM_RETURN_OBJECT] ?? false ) ) {
102            $ret['issues'][self::PARAM_RETURN_OBJECT] = 'PARAM_RETURN_OBJECT must be boolean, got '
103                . gettype( $settings[self::PARAM_RETURN_OBJECT] );
104        }
105
106        if ( !empty( $settings[ParamValidator::PARAM_ISMULTI] ) &&
107            !empty( $settings[self::PARAM_RETURN_OBJECT] ) &&
108            (
109                ( $settings[ParamValidator::PARAM_ISMULTI_LIMIT1] ?? 100 ) > 10 ||
110                ( $settings[ParamValidator::PARAM_ISMULTI_LIMIT2] ?? 100 ) > 10
111            )
112        ) {
113            $ret['issues'][] = 'Multi-valued title-type parameters with PARAM_RETURN_OBJECT '
114                . 'should set low values (<= 10) for PARAM_ISMULTI_LIMIT1 and PARAM_ISMULTI_LIMIT2.'
115                . ' (Note that "<= 10" is arbitrary. If something hits this, we can investigate a real limit '
116                . 'once we have a real use case to look at.)';
117        }
118
119        return $ret;
120    }
121
122    /** @inheritDoc */
123    public function getParamInfo( $name, array $settings, array $options ) {
124        $info = parent::getParamInfo( $name, $settings, $options );
125
126        $info['mustExist'] = !empty( $settings[self::PARAM_MUST_EXIST] );
127
128        return $info;
129    }
130
131    /** @inheritDoc */
132    public function getHelpInfo( $name, array $settings, array $options ) {
133        $info = parent::getParamInfo( $name, $settings, $options );
134
135        $info[ParamValidator::PARAM_TYPE] = MessageValue::new( 'paramvalidator-help-type-title' );
136
137        $mustExist = !empty( $settings[self::PARAM_MUST_EXIST] );
138        $info[self::PARAM_MUST_EXIST] = $mustExist
139            ? MessageValue::new( 'paramvalidator-help-type-title-must-exist' )
140            : MessageValue::new( 'paramvalidator-help-type-title-no-must-exist' );
141
142        return $info;
143    }
144
145}