MediaWiki master
SpecialWatchlistLabels.php
Go to the documentation of this file.
1<?php
7namespace MediaWiki\Specials;
8
9use InvalidArgumentException;
19use MediaWiki\Watchlist\WatchlistSpecialPage;
20use StatusValue;
21use Wikimedia\Codex\Utility\Codex;
22
30
31 private const SUBPAGE_EDIT = 'edit';
32 private const PARAM_ID = 'wll_id';
33 private const PARAM_NAME = 'wll_name';
34
35 use WatchlistSpecialPage;
36
37 private ?WatchlistLabel $watchlistLabel = null;
38
40 public function __construct(
41 private WatchlistLabelStore $labelStore,
42 $name = 'WatchlistLabels',
43 $restriction = 'viewmywatchlist',
44 ) {
45 parent::__construct( $name, $restriction, false );
46 }
47
49 public function doesWrites() {
50 return true;
51 }
52
54 public function execute( $subPage ) {
55 $user = $this->getUser();
56 $right = $subPage === self::SUBPAGE_EDIT ? 'editmywatchlist' : 'viewmywatchlist';
57 if ( !$user->isRegistered()
58 || ( $user->isTemp() && !$user->isAllowed( $right ) )
59 ) {
60 // The message used here will be one of:
61 // * watchlistlabels-not-logged-in
62 // * watchlistlabels-not-logged-in-for-temp-user
63 throw new UserNotLoggedIn( 'watchlistlabels-not-logged-in' );
64 }
65 $this->checkPermissions();
66
67 $output = $this->getOutput();
68 $output->setPageTitleMsg( $this->msg( 'watchlistlabels-title' ) );
69 $this->addHelpLink( 'Help:Watchlist labels' );
70 if ( !$this->getConfig()->get( MainConfigNames::EnableWatchlistLabels ) ) {
71 $output->addHTML( Html::errorBox( $this->msg( 'watchlistlabels-not-enabled' )->escaped() ) );
72 return;
73 }
74 $output->addSubtitle( $this->getWatchlistOwnerHtml() );
75 if ( $subPage === self::SUBPAGE_EDIT ) {
76 $this->showForm();
77 } else {
78 $this->showTable();
79 }
80 }
81
85 private function showForm() {
86 $id = $this->getRequest()->getInt( self::PARAM_ID );
87 $descriptor = [
88 self::PARAM_NAME => [
89 'type' => 'text',
90 'name' => self::PARAM_NAME,
91 'label-message' => 'watchlistlabels-form-field-name',
92 'validation-callback' => [ $this, 'validateName' ],
93 'filter-callback' => [ $this, 'filterName' ],
94 'required' => true,
95 ],
96 ];
97 $msgSuffix = 'new';
98 if ( $id ) {
99 $this->watchlistLabel = $this->labelStore->loadById( $this->getUser(), $id );
100 if ( $this->watchlistLabel ) {
101 $descriptor[self::PARAM_NAME]['default'] = $this->watchlistLabel->getName();
102 $descriptor[self::PARAM_ID] = [
103 'type' => 'hidden',
104 'name' => self::PARAM_ID,
105 'default' => $this->watchlistLabel->getId(),
106 ];
107 $msgSuffix = 'edit';
108 }
109 }
110 $form = HTMLForm::factory( 'codex', $descriptor, $this->getContext() )
111 // Messages used here:
112 // - watchlistlabels-form-header-new
113 // - watchlistlabels-form-header-edit
114 ->setHeaderHtml( Html::element( 'h3', [], $this->msg( "watchlistlabels-form-header-$msgSuffix" )->text() ) )
115 ->showCancel( true )
116 ->setCancelTarget( $this->getPageTitle() )
117 // Messages used here:
118 // - watchlistlabels-form-submit-new
119 // - watchlistlabels-form-submit-edit
120 ->setSubmitTextMsg( "watchlistlabels-form-submit-$msgSuffix" )
121 ->setSubmitCallback( [ $this, 'onSubmit' ] );
122 $form->show();
123 }
124
134 public function filterName( $value, ?array $alldata, ?HTMLForm $form ) {
135 $label = new WatchlistLabel( $this->getUser(), $value ?? '' );
136 return $label->getName();
137 }
138
146 public function validateName( $value, ?array $alldata, ?HTMLForm $form ) {
147 $length = strlen( trim( $value ) );
148 if ( $length === 0 ) {
149 return Status::newFatal( $this->msg( 'watchlistlabels-form-name-too-short', $length ) );
150 }
151 if ( $length > 255 ) {
152 return Status::newFatal( $this->msg( 'watchlistlabels-form-name-too-long', $length ) );
153 }
154 $existingLabel = $this->labelStore->loadByName( $this->getUser(), $value );
155 $thisId = $alldata[self::PARAM_ID] ?? null;
156 if ( $existingLabel && $thisId && $existingLabel->getId() !== (int)$thisId ) {
157 return Status::newFatal( $this->msg( 'watchlistlabels-form-name-exists', $existingLabel->getName() ) );
158 }
159 return Status::newGood();
160 }
161
168 public function onSubmit( $data ): Status {
169 if ( !isset( $data[self::PARAM_NAME] ) ) {
170 throw new InvalidArgumentException( 'No name data submitted.' );
171 }
172 if ( !$this->watchlistLabel ) {
173 $this->watchlistLabel = new WatchlistLabel( $this->getUser(), $data[self::PARAM_NAME] );
174 } else {
175 $this->watchlistLabel->setName( $data[self::PARAM_NAME] );
176 }
177 $saved = $this->labelStore->save( $this->watchlistLabel );
178 if ( $saved->isOK() ) {
179 $this->getOutput()->redirect( $this->getPageTitle()->getLocalURL() );
180 }
181 return $saved;
182 }
183
187 private function showTable() {
188 $codex = new Codex();
189 $this->getOutput()->addModuleStyles( 'mediawiki.special.watchlistlabels' );
190
191 // Page title and description.
192 $this->getOutput()->addHTML(
193 Html::element( 'h3', [], $this->msg( 'watchlistlabels-table-title' )->text() )
194 . Html::element( 'p', [], $this->msg( 'watchlistlabels-table-description' )->text() ),
195 );
196
197 // Buttons in the table header.
198 $params = [
199 'href' => $this->getPageTitle( self::SUBPAGE_EDIT )->getLinkURL(),
200 // @todo Remove Codex classes when T406372 is resolved.
201 'class' => 'cdx-button cdx-button--fake-button cdx-button--fake-button--enabled'
202 . ' cdx-button--action-progressive cdx-button--weight-primary'
203 ];
204 $addNew = Html::element( 'a', $params, $this->msg( 'watchlistlabels-table-new-link' )->text() );
205
206 // Data.
207 $data = [];
208 $labels = $this->labelStore->loadAllForUser( $this->getUser() );
209 $labelCounts = $this->labelStore->countItems( array_keys( $labels ) );
210 $editIcon = Html::element( 'span', [ 'class' => 'cdx-button__icon mw-specialwatchlistlabels-icon--edit' ] );
211 foreach ( $labels as $label ) {
212 $id = $label->getId();
213 if ( !$id ) {
214 continue;
215 }
216 $url = $this->getPageTitle( self::SUBPAGE_EDIT )->getLocalURL( [ self::PARAM_ID => $id ] );
217 $params = [
218 'href' => $url,
219 'role' => 'button',
220 'class' => 'cdx-button cdx-button--fake-button cdx-button--fake-button--enabled'
221 . ' cdx-button--weight-quiet cdx-button--icon-only cdx-button--size-small',
222 'title' => $this->msg( 'watchlistlabels-table-edit' )->text(),
223 ];
224 $data[] = [
225 'name' => htmlspecialchars( $label->getName() ),
226 'count' => $this->getLanguage()->formatNum( $labelCounts[ $id ] ),
227 'edit' => Html::rawElement( 'a', $params, $editIcon ),
228 ];
229 }
230
231 // Put it all together in the table.
232 $table = $codex->table()
233 ->setAttributes( [ 'class' => 'mw-specialwatchlistlabels-table' ] )
234 ->setCaption( $this->msg( 'watchlistlabels-table-header' )->text() )
235 ->setHeaderContent( $addNew )
236 ->setColumns( [
237 [ 'id' => 'name', 'label' => $this->msg( 'watchlistlabels-table-col-name' )->escaped() ],
238 [ 'id' => 'count', 'label' => $this->msg( 'watchlistlabels-table-col-count' )->escaped() ],
239 [ 'id' => 'edit', 'label' => $this->msg( 'watchlistlabels-table-col-actions' )->escaped() ],
240 ] )
241 ->setData( $data )
242 ->setPaginate( false )
243 ->build();
244 $this->getOutput()->addHTML( $table->getHtml() );
245 }
246}
if(!defined('MW_SETUP_CALLBACK'))
Definition WebStart.php:68
Redirect a user to the login page or account creation page.
Object handling generic submission, CSRF protection, layout and other logic for UI forms in a reusabl...
Definition HTMLForm.php:195
This class is a collection of static functions that serve two purposes:
Definition Html.php:43
A class containing constants representing the names of configuration variables.
const EnableWatchlistLabels
Name constant for the EnableWatchlistLabels setting, for use with Config::get()
The Message class deals with fetching and processing of interface message into a variety of formats.
Definition Message.php:144
Parent class for all special pages.
getUser()
Shortcut to get the User executing this instance.
getPageTitle( $subpage=false)
Get a self-referential title object.
checkPermissions()
Checks if userCanExecute, and if not throws a PermissionsError.
getConfig()
Shortcut to get main config object.
getContext()
Gets the context this SpecialPage is executed in.
getRequest()
Get the WebRequest being used for this instance.
msg( $key,... $params)
Wrapper around wfMessage that sets the current context.
getOutput()
Get the OutputPage being used for this instance.
addHelpLink( $to, $overrideBaseUrl=false)
Adds help link with an icon via page indicators.
A special page for viewing a user's watchlist labels and performing CRUD operations on them.
validateName( $value, ?array $alldata, ?HTMLForm $form)
onSubmit( $data)
Handle the form submission, for saving new or existing labels.
execute( $subPage)
Default execute method Checks user permissions.This must be overridden by subclasses; it will be made...
__construct(private WatchlistLabelStore $labelStore, $name='WatchlistLabels', $restriction='viewmywatchlist',)
filterName( $value, ?array $alldata, ?HTMLForm $form)
Filter the 'name' field value.
doesWrites()
Indicates whether POST requests to this special page require write access to the wiki....
Generic operation result class Has warning/error list, boolean status and arbitrary value.
Definition Status.php:44
Service class for storage of watchlist labels.
Generic operation result class Has warning/error list, boolean status and arbitrary value.
element(SerializerNode $parent, SerializerNode $node, $contents)
array $params
The job parameters.
msg( $key,... $params)