1<?php 2 3namespace MediaWiki\ParamValidator\TypeDef; 4 5use MediaWiki\Linker\LinkTarget; 6use 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 $this->failure( 'badtitle', $name, $value, $settings, $options ); 67 } elseif ( $mustExist && !$title->exists() ) { 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} 144