MediaWiki  master
WatchAction.php
Go to the documentation of this file.
1 <?php
26 
32 class WatchAction extends FormAction {
33 
35  protected $watchlistExpiry;
36 
38  protected $expiryFormFieldName = 'expiry';
39 
41  protected $watchedItem = false;
42 
44  private $watchlistManager;
45 
54  public function __construct(
55  Article $article,
57  WatchlistManager $watchlistManager,
58  WatchedItemStore $watchedItemStore
59  ) {
60  parent::__construct( $article, $context );
61  $this->watchlistExpiry = $this->getContext()->getConfig()->get( MainConfigNames::WatchlistExpiry );
62  if ( $this->watchlistExpiry ) {
63  // The watchedItem is only used in this action's form if $wgWatchlistExpiry is enabled.
64  $this->watchedItem = $watchedItemStore->getWatchedItem(
65  $this->getUser(),
66  $this->getTitle()
67  );
68  }
69  $this->watchlistManager = $watchlistManager;
70  }
71 
72  public function getName() {
73  return 'watch';
74  }
75 
76  public function requiresUnblock() {
77  return false;
78  }
79 
80  protected function getDescription() {
81  return '';
82  }
83 
84  public function onSubmit( $data ) {
85  // Even though we're never unwatching here, use WatchlistManager::setWatch()
86  // because it also checks for changed expiry.
87  $result = $this->watchlistManager->setWatch(
88  true,
89  $this->getAuthority(),
90  $this->getTitle(),
91  $this->getRequest()->getVal( 'wp' . $this->expiryFormFieldName )
92  );
93 
94  return Status::wrap( $result );
95  }
96 
97  protected function checkCanExecute( User $user ) {
98  if ( !$user->isNamed() ) {
99  throw new UserNotLoggedIn( 'watchlistanontext', 'watchnologin' );
100  }
101 
102  parent::checkCanExecute( $user );
103  }
104 
105  protected function usesOOUI() {
106  return true;
107  }
108 
109  protected function getFormFields() {
110  // If watchlist expiry is not enabled, return a simple confirmation message.
111  if ( !$this->watchlistExpiry ) {
112  return [
113  'intro' => [
114  'type' => 'info',
115  'raw' => true,
116  'default' => $this->msg( 'confirm-watch-top' )->parse(),
117  ],
118  ];
119  }
120 
121  // Otherwise, use a select-list of expiries.
122  $expiryOptions = static::getExpiryOptions( $this->getContext(), $this->watchedItem );
123  return [
124  $this->expiryFormFieldName => [
125  'type' => 'select',
126  'label-message' => 'confirm-watch-label',
127  'options' => $expiryOptions['options'],
128  'default' => $expiryOptions['default'],
129  ]
130  ];
131  }
132 
145  public static function getExpiryOptions( MessageLocalizer $msgLocalizer, $watchedItem ) {
146  $expiryOptions = self::getExpiryOptionsFromMessage( $msgLocalizer );
147  $default = in_array( 'infinite', $expiryOptions )
148  ? 'infinite'
149  : current( $expiryOptions );
150  if ( $watchedItem instanceof WatchedItem && $watchedItem->getExpiry() ) {
151  // If it's already being temporarily watched,
152  // add the existing expiry as the default option in the dropdown.
153  $default = $watchedItem->getExpiry( TS_ISO_8601 );
154  $daysLeft = $watchedItem->getExpiryInDaysText( $msgLocalizer, true );
155  $expiryOptions = array_merge( [ $daysLeft => $default ], $expiryOptions );
156  }
157  return [
158  'options' => $expiryOptions,
159  'default' => $default,
160  ];
161  }
162 
171  private static function getExpiryOptionsFromMessage(
172  MessageLocalizer $msgLocalizer, ?string $lang = null
173  ): array {
174  $expiryOptionsMsg = $msgLocalizer->msg( 'watchlist-expiry-options' );
175  $optionsText = !$lang ? $expiryOptionsMsg->text() : $expiryOptionsMsg->inLanguage( $lang )->text();
177  $optionsText
178  );
179 
180  $expiryOptions = [];
181  foreach ( $options as $label => $value ) {
182  if ( strtotime( $value ) || wfIsInfinity( $value ) ) {
183  $expiryOptions[$label] = $value;
184  }
185  }
186 
187  // If message options is invalid try to recover by returning
188  // english options (T267611)
189  if ( !$expiryOptions && $expiryOptionsMsg->getLanguage()->getCode() !== 'en' ) {
190  return self::getExpiryOptionsFromMessage( $msgLocalizer, 'en' );
191  }
192 
193  return $expiryOptions;
194  }
195 
196  protected function alterForm( HTMLForm $form ) {
197  $msg = $this->watchlistExpiry && $this->watchedItem ? 'updatewatchlist' : 'addwatch';
198  $form->setWrapperLegendMsg( $msg );
199  $submitMsg = $this->watchlistExpiry ? 'confirm-watch-button-expiry' : 'confirm-watch-button';
200  $form->setSubmitTextMsg( $submitMsg );
201  $form->setTokenSalt( 'watch' );
202  }
203 
216  public function onSuccess() {
217  $msgKey = $this->getTitle()->isTalkPage() ? 'addedwatchtext-talk' : 'addedwatchtext';
218  $expiryLabel = null;
219  $submittedExpiry = $this->getContext()->getRequest()->getText( 'wp' . $this->expiryFormFieldName );
220  if ( $submittedExpiry ) {
221  // We can't use $this->watcheditem to get the expiry because it's not been saved at this
222  // point in the request and so its values are those from before saving.
223  $expiry = ExpiryDef::normalizeExpiry( $submittedExpiry, TS_ISO_8601 );
224 
225  // If the expiry label isn't one of the predefined ones in the dropdown, calculate 'x days'.
226  $expiryDays = WatchedItem::calculateExpiryInDays( $expiry );
227  $defaultLabels = static::getExpiryOptions( $this->getContext(), false )['options'];
228  $localizedExpiry = array_search( $submittedExpiry, $defaultLabels );
229  $expiryLabel = $expiryDays && $localizedExpiry === false
230  ? $this->getContext()->msg( 'days', $expiryDays )->text()
231  : $localizedExpiry;
232 
233  // Determine which message to use, depending on whether this is a talk page or not
234  // and whether an expiry was selected.
235  $isTalk = $this->getTitle()->isTalkPage();
236  if ( wfIsInfinity( $expiry ) ) {
237  $msgKey = $isTalk ? 'addedwatchindefinitelytext-talk' : 'addedwatchindefinitelytext';
238  } elseif ( $expiryDays > 0 ) {
239  $msgKey = $isTalk ? 'addedwatchexpirytext-talk' : 'addedwatchexpirytext';
240  } elseif ( $expiryDays < 1 ) {
241  $msgKey = $isTalk ? 'addedwatchexpiryhours-talk' : 'addedwatchexpiryhours';
242  }
243  }
244  $this->getOutput()->addWikiMsg( $msgKey, $this->getTitle()->getPrefixedText(), $expiryLabel );
245  }
246 
247  public function doesWrites() {
248  return true;
249  }
250 }
wfIsInfinity( $str)
Determine input string is represents as infinity.
getContext()
IContextSource null $context
IContextSource if specified; otherwise we'll use the Context from the Page.
Definition: Action.php:58
getTitle()
Shortcut to get the Title object from the page.
Definition: Action.php:221
getContext()
Get the IContextSource in use here.
Definition: Action.php:127
getUser()
Shortcut to get the User being used for this instance.
Definition: Action.php:161
msg( $key,... $params)
Get a Message object with context set Parameters are the same as wfMessage()
Definition: Action.php:233
getAuthority()
Shortcut to get the Authority executing this instance.
Definition: Action.php:171
getRequest()
Get the WebRequest being used for this instance.
Definition: Action.php:141
Legacy class representing an editable page and handling UI for some page actions.
Definition: Article.php:55
An action which shows a form and does something based on the input from the form.
Definition: FormAction.php:30
Object handling generic submission, CSRF protection, layout and other logic for UI forms in a reusabl...
Definition: HTMLForm.php:153
setSubmitTextMsg( $msg)
Set the text for the submit button to a message.
Definition: HTMLForm.php:1635
setWrapperLegendMsg( $msg)
Prompt the whole form to be wrapped in a "<fieldset>", with this message as its "<legend>" element.
Definition: HTMLForm.php:1840
setTokenSalt( $salt)
Set the salt for the edit token.
Definition: HTMLForm.php:1247
A class containing constants representing the names of configuration variables.
static wrap( $sv)
Succinct helper method to wrap a StatusValue.
Definition: Status.php:64
Redirect a user to the login page.
The User object encapsulates all of the user-specific settings (user_id, name, rights,...
Definition: User.php:71
isNamed()
Is the user a normal non-temporary registered user?
Definition: User.php:3559
Page addition to a user's watchlist.
Definition: WatchAction.php:32
static getExpiryOptions(MessageLocalizer $msgLocalizer, $watchedItem)
Get options and default for a watchlist expiry select list.
getDescription()
Returns the description that goes below the <h1> element.
Definition: WatchAction.php:80
string $expiryFormFieldName
Definition: WatchAction.php:38
bool $watchlistExpiry
The value of the $wgWatchlistExpiry configuration variable.
Definition: WatchAction.php:35
requiresUnblock()
Whether this action can still be executed by a blocked user.
Definition: WatchAction.php:76
getFormFields()
Get an HTMLForm descriptor array.
usesOOUI()
Whether the form should use OOUI.
__construct(Article $article, IContextSource $context, WatchlistManager $watchlistManager, WatchedItemStore $watchedItemStore)
Only public since 1.21.
Definition: WatchAction.php:54
alterForm(HTMLForm $form)
Play with the HTMLForm if you need to more substantially.
false WatchedItem $watchedItem
Definition: WatchAction.php:41
checkCanExecute(User $user)
Checks if the given user (identified by an object) can perform this action.
Definition: WatchAction.php:97
onSuccess()
Show one of 8 possible success messages.
onSubmit( $data)
Process the form on POST submission.
Definition: WatchAction.php:84
getName()
Return the name of the action this object responds to.
Definition: WatchAction.php:72
Storage layer class for WatchedItems.
getWatchedItem(UserIdentity $user, $target)
Representation of a pair of user and title for watchlist entries.
Definition: WatchedItem.php:36
getExpiryInDaysText(MessageLocalizer $msgLocalizer, $isDropdownOption=false)
Get days remaining until a watched item expires as a text.
getExpiry(?int $style=TS_MW)
When the watched item will expire.
static calculateExpiryInDays(?string $expiry)
Get the number of days remaining until the given expiry time.
Type definition for expiry timestamps.
Definition: ExpiryDef.php:17
static parseOptionsMessage(string $msg)
Parse labels and values out of a comma- and colon-separated list of options, such as is used for expi...
Definition: XmlSelect.php:148
Interface for objects which can provide a MediaWiki context on request.
Interface for localizing messages in MediaWiki.
if(!isset( $args[0])) $lang