Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
82.22% covered (warning)
82.22%
37 / 45
83.33% covered (warning)
83.33%
5 / 6
CRAP
0.00% covered (danger)
0.00%
0 / 1
TitleDef
82.22% covered (warning)
82.22%
37 / 45
83.33% covered (warning)
83.33%
5 / 6
19.82
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%
11 / 11
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    public function __construct( Callbacks $callbacks, TitleFactory $titleFactory ) {
47        parent::__construct( $callbacks );
48        $this->titleFactory = $titleFactory;
49    }
50
51    /**
52     * @inheritDoc
53     * @return string|LinkTarget Depending on the PARAM_RETURN_OBJECT setting.
54     */
55    public function validate( $name, $value, array $settings, array $options ) {
56        $mustExist = !empty( $settings[self::PARAM_MUST_EXIST] );
57        $returnObject = !empty( $settings[self::PARAM_RETURN_OBJECT] );
58
59        $this->failIfNotString( $name, $value, $settings, $options );
60
61        $title = $this->titleFactory->newFromText( $value );
62
63        if ( !$title ) {
64            // Message used: paramvalidator-badtitle
65            $this->failure( 'badtitle', $name, $value, $settings, $options );
66        } elseif ( $mustExist && !$title->exists() ) {
67            // Message used: paramvalidator-missingtitle
68            $this->failure( 'missingtitle', $name, $value, $settings, $options );
69        }
70
71        if ( $returnObject ) {
72            return $title->getTitleValue();
73        } else {
74            return $title->getPrefixedText();
75        }
76    }
77
78    /** @inheritDoc */
79    public function stringifyValue( $name, $value, array $settings, array $options ) {
80        if ( $value instanceof LinkTarget ) {
81            return $this->titleFactory->newFromLinkTarget( $value )->getPrefixedText();
82        }
83        return parent::stringifyValue( $name, $value, $settings, $options );
84    }
85
86    /** @inheritDoc */
87    public function checkSettings( string $name, $settings, array $options, array $ret ): array {
88        $ret = parent::checkSettings( $name, $settings, $options, $ret );
89
90        $ret['allowedKeys'] = array_merge( $ret['allowedKeys'], [
91            self::PARAM_MUST_EXIST, self::PARAM_RETURN_OBJECT,
92        ] );
93
94        if ( !is_bool( $settings[self::PARAM_MUST_EXIST] ?? false ) ) {
95            $ret['issues'][self::PARAM_MUST_EXIST] = 'PARAM_MUST_EXIST must be boolean, got '
96                . gettype( $settings[self::PARAM_MUST_EXIST] );
97        }
98
99        if ( !is_bool( $settings[self::PARAM_RETURN_OBJECT] ?? false ) ) {
100            $ret['issues'][self::PARAM_RETURN_OBJECT] = 'PARAM_RETURN_OBJECT must be boolean, got '
101                . gettype( $settings[self::PARAM_RETURN_OBJECT] );
102        }
103
104        if ( !empty( $settings[ParamValidator::PARAM_ISMULTI] ) &&
105            !empty( $settings[self::PARAM_RETURN_OBJECT] ) &&
106            (
107                ( $settings[ParamValidator::PARAM_ISMULTI_LIMIT1] ?? 100 ) > 10 ||
108                ( $settings[ParamValidator::PARAM_ISMULTI_LIMIT2] ?? 100 ) > 10
109            )
110        ) {
111            $ret['issues'][] = 'Multi-valued title-type parameters with PARAM_RETURN_OBJECT '
112                . 'should set low values (<= 10) for PARAM_ISMULTI_LIMIT1 and PARAM_ISMULTI_LIMIT2.'
113                . ' (Note that "<= 10" is arbitrary. If something hits this, we can investigate a real limit '
114                . 'once we have a real use case to look at.)';
115        }
116
117        return $ret;
118    }
119
120    /** @inheritDoc */
121    public function getParamInfo( $name, array $settings, array $options ) {
122        $info = parent::getParamInfo( $name, $settings, $options );
123
124        $info['mustExist'] = !empty( $settings[self::PARAM_MUST_EXIST] );
125
126        return $info;
127    }
128
129    /** @inheritDoc */
130    public function getHelpInfo( $name, array $settings, array $options ) {
131        $info = parent::getParamInfo( $name, $settings, $options );
132
133        $info[ParamValidator::PARAM_TYPE] = MessageValue::new( 'paramvalidator-help-type-title' );
134
135        $mustExist = !empty( $settings[self::PARAM_MUST_EXIST] );
136        $info[self::PARAM_MUST_EXIST] = $mustExist
137            ? MessageValue::new( 'paramvalidator-help-type-title-must-exist' )
138            : MessageValue::new( 'paramvalidator-help-type-title-no-must-exist' );
139
140        return $info;
141    }
142
143}