Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
| Total | |
0.00% |
0 / 139 |
|
0.00% |
0 / 9 |
CRAP | |
0.00% |
0 / 1 |
| PFFormEditAction | |
0.00% |
0 / 139 |
|
0.00% |
0 / 9 |
1806 | |
0.00% |
0 / 1 |
| getName | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| show | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| execute | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| displayTab | |
0.00% |
0 / 45 |
|
0.00% |
0 / 1 |
342 | |||
| displayFormChooser | |
0.00% |
0 / 44 |
|
0.00% |
0 / 1 |
132 | |||
| getNumPagesPerForm | |
0.00% |
0 / 23 |
|
0.00% |
0 / 1 |
6 | |||
| printLinksToFormArray | |
0.00% |
0 / 9 |
|
0.00% |
0 / 1 |
20 | |||
| displayForm | |
0.00% |
0 / 14 |
|
0.00% |
0 / 1 |
12 | |||
| doesWrites | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| 1 | <?php |
| 2 | |
| 3 | use MediaWiki\Html\Html; |
| 4 | use MediaWiki\MediaWikiServices; |
| 5 | |
| 6 | /** |
| 7 | * Handles the formedit action. |
| 8 | * |
| 9 | * @author Yaron Koren |
| 10 | * @author Stephan Gambke |
| 11 | * @file |
| 12 | * @ingroup PF |
| 13 | */ |
| 14 | |
| 15 | class PFFormEditAction extends Action { |
| 16 | |
| 17 | /** |
| 18 | * Return the name of the action this object responds to |
| 19 | * @return string lowercase |
| 20 | */ |
| 21 | public function getName() { |
| 22 | return 'formedit'; |
| 23 | } |
| 24 | |
| 25 | /** |
| 26 | * The main action entry point. Do all output for display and send it to the context |
| 27 | * output. Do not use globals $wgOut, $wgRequest, etc, in implementations; use |
| 28 | * $this->getOutput(), etc. |
| 29 | * @throws ErrorPageError |
| 30 | * @return false |
| 31 | */ |
| 32 | public function show() { |
| 33 | return self::displayForm( $this, $this->getArticle() ); |
| 34 | } |
| 35 | |
| 36 | /** |
| 37 | * Execute the action in a silent fashion: do not display anything or release any errors. |
| 38 | * @return bool whether execution was successful |
| 39 | */ |
| 40 | public function execute() { |
| 41 | return true; |
| 42 | } |
| 43 | |
| 44 | /** |
| 45 | * Adds an "action" (i.e., a tab) to edit the current article with |
| 46 | * a form |
| 47 | * @param IContextSource $obj |
| 48 | * @param array &$links |
| 49 | */ |
| 50 | static function displayTab( $obj, &$links ) { |
| 51 | $title = $obj->getTitle(); |
| 52 | $user = $obj->getUser(); |
| 53 | |
| 54 | // Make sure that this is not a special page, and |
| 55 | // that the user is allowed to edit it |
| 56 | // - this function is almost never called on special pages, |
| 57 | // but before SMW is fully initialized, it's called on |
| 58 | // Special:SMWAdmin for some reason, which is why the |
| 59 | // special-page check is there. |
| 60 | if ( !isset( $title ) || |
| 61 | ( $title->getNamespace() == NS_SPECIAL ) ) { |
| 62 | return; |
| 63 | } |
| 64 | |
| 65 | $form_names = PFFormLinker::getDefaultFormsForPage( $title ); |
| 66 | if ( count( $form_names ) == 0 ) { |
| 67 | return; |
| 68 | } |
| 69 | |
| 70 | global $wgPageFormsRenameEditTabs, $wgPageFormsRenameMainEditTab; |
| 71 | |
| 72 | $content_actions = &$links['views']; |
| 73 | |
| 74 | $permissionManager = MediaWikiServices::getInstance()->getPermissionManager(); |
| 75 | $user_can_edit = $permissionManager->userCan( 'edit', $user, $title, $permissionManager::RIGOR_QUICK ); |
| 76 | |
| 77 | // Create the form edit tab, and apply whatever changes are |
| 78 | // specified by the edit-tab global variables. |
| 79 | if ( $wgPageFormsRenameEditTabs ) { |
| 80 | $form_edit_tab_msg = $user_can_edit ? 'edit' : 'pf_viewform'; |
| 81 | if ( array_key_exists( 'edit', $content_actions ) ) { |
| 82 | $msg = $user_can_edit ? 'pf_editsource' : 'viewsource'; |
| 83 | $content_actions['edit']['text'] = wfMessage( $msg )->text(); |
| 84 | } |
| 85 | } else { |
| 86 | if ( $user_can_edit ) { |
| 87 | $form_edit_tab_msg = $title->exists() ? 'formedit' : 'pf_formcreate'; |
| 88 | } else { |
| 89 | $form_edit_tab_msg = 'pf_viewform'; |
| 90 | } |
| 91 | // Check for renaming of main edit tab only if |
| 92 | // $wgPageFormsRenameEditTabs is off. |
| 93 | if ( $wgPageFormsRenameMainEditTab ) { |
| 94 | if ( array_key_exists( 'edit', $content_actions ) ) { |
| 95 | $msg = $user_can_edit ? 'pf_editsource' : 'viewsource'; |
| 96 | $content_actions['edit']['text'] = wfMessage( $msg )->text(); |
| 97 | } |
| 98 | } |
| 99 | } |
| 100 | |
| 101 | $class_name = ( $obj->getRequest()->getVal( 'action' ) == 'formedit' ) ? 'selected' : ''; |
| 102 | $form_edit_tab = [ |
| 103 | 'class' => $class_name, |
| 104 | 'text' => wfMessage( $form_edit_tab_msg )->text(), |
| 105 | 'href' => $title->getLocalURL( 'action=formedit' ) |
| 106 | ]; |
| 107 | |
| 108 | // Find the location of the 'edit' tab, and add 'edit |
| 109 | // with form' right before it. |
| 110 | // This is a "key-safe" splice - it preserves both the keys |
| 111 | // and the values of the array, by editing them separately |
| 112 | // and then rebuilding the array. Based on the example at |
| 113 | // http://us2.php.net/manual/en/function.array-splice.php#31234 |
| 114 | $tab_keys = array_keys( $content_actions ); |
| 115 | $tab_values = array_values( $content_actions ); |
| 116 | $edit_tab_location = array_search( 'edit', $tab_keys ); |
| 117 | |
| 118 | // If there's no 'edit' tab, look for the 'view source' tab |
| 119 | // instead. |
| 120 | if ( $edit_tab_location == null ) { |
| 121 | $edit_tab_location = array_search( 'viewsource', $tab_keys ); |
| 122 | } |
| 123 | |
| 124 | // This should rarely happen, but if there was no edit *or* |
| 125 | // view source tab, set the location index to -1, so the |
| 126 | // tab shows up near the end. |
| 127 | if ( $edit_tab_location == null ) { |
| 128 | $edit_tab_location = -1; |
| 129 | } |
| 130 | array_splice( $tab_keys, $edit_tab_location, 0, 'formedit' ); |
| 131 | array_splice( $tab_values, $edit_tab_location, 0, [ $form_edit_tab ] ); |
| 132 | $content_actions = []; |
| 133 | foreach ( $tab_keys as $i => $key ) { |
| 134 | $content_actions[$key] = $tab_values[$i]; |
| 135 | } |
| 136 | |
| 137 | if ( !$obj->getUser()->isAllowed( 'viewedittab' ) ) { |
| 138 | // The tab can have either of these two actions. |
| 139 | unset( $content_actions['edit'] ); |
| 140 | unset( $content_actions['viewsource'] ); |
| 141 | } |
| 142 | } |
| 143 | |
| 144 | static function displayFormChooser( $output, $title ) { |
| 145 | global $wgPageFormsMainFormsMinimum; |
| 146 | |
| 147 | $output->addModules( 'ext.pageforms.main.styles' ); |
| 148 | |
| 149 | $targetName = $title->getPrefixedText(); |
| 150 | $output->setPageTitle( wfMessage( "creating", $targetName )->text() ); |
| 151 | |
| 152 | try { |
| 153 | $formNames = PFUtils::getAllForms(); |
| 154 | } catch ( MWException $e ) { |
| 155 | $output->addHTML( Html::element( 'div', [ 'class' => 'error' ], $e->getMessage() ) ); |
| 156 | return; |
| 157 | } |
| 158 | |
| 159 | $output->addHTML( Html::element( 'p', null, wfMessage( 'pf-formedit-selectform' )->text() ) ); |
| 160 | $pagesPerForm = self::getNumPagesPerForm(); |
| 161 | $totalPages = 0; |
| 162 | foreach ( $pagesPerForm as $formName => $numPages ) { |
| 163 | $totalPages += $numPages; |
| 164 | } |
| 165 | // We define "popular forms" as those that are used to |
| 166 | // edit more than the specified amount of the wiki's |
| 167 | // form-editable pages. (Set by $wgPageFormsMainFormsMinimum, |
| 168 | // which by default is 1%.) |
| 169 | $popularForms = []; |
| 170 | foreach ( $pagesPerForm as $formName => $numPages ) { |
| 171 | if ( $numPages > $totalPages * $wgPageFormsMainFormsMinimum ) { |
| 172 | $popularForms[] = $formName; |
| 173 | } |
| 174 | } |
| 175 | $otherForms = []; |
| 176 | foreach ( $formNames as $i => $formName ) { |
| 177 | if ( !in_array( $formName, $popularForms ) ) { |
| 178 | $otherForms[] = $formName; |
| 179 | } |
| 180 | } |
| 181 | |
| 182 | $fe = PFUtils::getSpecialPage( 'FormEdit' ); |
| 183 | |
| 184 | if ( count( $popularForms ) > 0 ) { |
| 185 | if ( count( $otherForms ) > 0 ) { |
| 186 | $output->addHTML( Html::element( |
| 187 | 'p', |
| 188 | [], |
| 189 | wfMessage( 'pf-formedit-mainforms' )->text() |
| 190 | ) ); |
| 191 | } |
| 192 | $text = self::printLinksToFormArray( $popularForms, $targetName, $fe ); |
| 193 | $output->addHTML( Html::rawElement( 'div', [ 'class' => 'infoMessage mainForms' ], $text ) ); |
| 194 | } |
| 195 | |
| 196 | if ( count( $otherForms ) > 0 ) { |
| 197 | if ( count( $popularForms ) > 0 ) { |
| 198 | $output->addHTML( Html::element( |
| 199 | 'p', |
| 200 | [], |
| 201 | wfMessage( 'pf-formedit-otherforms' )->text() |
| 202 | ) ); |
| 203 | } |
| 204 | $text = self::printLinksToFormArray( $otherForms, $targetName, $fe ); |
| 205 | $output->addHTML( Html::rawElement( 'div', [ 'class' => 'infoMessage otherForms' ], $text ) ); |
| 206 | } |
| 207 | |
| 208 | $linkRenderer = MediaWikiServices::getInstance()->getLinkRenderer(); |
| 209 | $linkParams = [ 'action' => 'edit', 'redlink' => true ]; |
| 210 | $noFormLink = $linkRenderer->makeKnownLink( $title, wfMessage( 'pf-formedit-donotuseform' )->escaped(), [], $linkParams ); |
| 211 | $output->addHTML( Html::rawElement( 'p', null, $noFormLink ) ); |
| 212 | } |
| 213 | |
| 214 | /** |
| 215 | * Find the number of pages on the wiki that use each form, by getting |
| 216 | * all the categories that have a #default_form call pointing to a |
| 217 | * particular form, and adding up the number of pages in each such |
| 218 | * category. |
| 219 | * This approach doesn't count #default_form calls for namespaces or |
| 220 | * individual pages, but that doesn't seem like a big deal, because, |
| 221 | * when creating a page in a namespace that has a form, this interface |
| 222 | * probably won't get called anyway; and #default_form calls for |
| 223 | * individual pages are (hopefully) pretty rare. |
| 224 | * @return int[] |
| 225 | */ |
| 226 | static function getNumPagesPerForm() { |
| 227 | $dbr = PFUtils::getReadDB(); |
| 228 | $res = $dbr->select( |
| 229 | [ 'category', 'page', 'page_props' ], |
| 230 | [ 'pp_value', 'SUM(cat_pages) AS total_pages' ], |
| 231 | [ |
| 232 | // Keep backward compatibility with |
| 233 | // the page property name for |
| 234 | // Semantic Forms. |
| 235 | 'pp_propname' => [ 'PFDefaultForm', 'SFDefaultForm' ] |
| 236 | ], |
| 237 | __METHOD__, |
| 238 | [ |
| 239 | 'GROUP BY' => 'pp_value', |
| 240 | 'ORDER BY' => 'total_pages DESC', |
| 241 | 'LIMIT' => 100 |
| 242 | ], |
| 243 | [ |
| 244 | 'page' => [ 'JOIN', 'cat_title = page_title' ], |
| 245 | 'page_props' => [ 'JOIN', 'page_id = pp_page' ] |
| 246 | ] |
| 247 | ); |
| 248 | |
| 249 | $pagesPerForm = []; |
| 250 | while ( $row = $res->fetchRow() ) { |
| 251 | $formName = $row['pp_value']; |
| 252 | $pagesPerForm[$formName] = $row['total_pages']; |
| 253 | } |
| 254 | return $pagesPerForm; |
| 255 | } |
| 256 | |
| 257 | static function printLinksToFormArray( $formNames, $targetName, $fe ) { |
| 258 | $text = ''; |
| 259 | foreach ( $formNames as $i => $formName ) { |
| 260 | if ( $i > 0 ) { |
| 261 | $text .= ' <span class="pageforms-separator">·</span> '; |
| 262 | } |
| 263 | |
| 264 | // Special handling for forms whose name contains a slash. |
| 265 | if ( strpos( $formName, '/' ) !== false ) { |
| 266 | $url = $fe->getPageTitle()->getLocalURL( [ 'form' => $formName, 'target' => $targetName ] ); |
| 267 | } else { |
| 268 | $url = $fe->getPageTitle( "$formName/$targetName" )->getLocalURL(); |
| 269 | } |
| 270 | $text .= Html::element( 'a', [ 'href' => $url ], $formName ); |
| 271 | } |
| 272 | return $text; |
| 273 | } |
| 274 | |
| 275 | /** |
| 276 | * The function called if we're in index.php (as opposed to one of the |
| 277 | * special pages) |
| 278 | * @param Action $action |
| 279 | * @param Article $article |
| 280 | * @return true |
| 281 | */ |
| 282 | static function displayForm( $action, $article ) { |
| 283 | $output = $action->getOutput(); |
| 284 | $title = $article->getTitle(); |
| 285 | $form_names = PFFormLinker::getDefaultFormsForPage( $title ); |
| 286 | if ( count( $form_names ) == 0 ) { |
| 287 | // If no form is set, display an interface to let the |
| 288 | // user choose out of all the forms defined on this wiki |
| 289 | // (or none at all). |
| 290 | self::displayFormChooser( $output, $title ); |
| 291 | return true; |
| 292 | } |
| 293 | |
| 294 | if ( count( $form_names ) > 1 ) { |
| 295 | $warning_text = Html::warningBox( wfMessage( 'pf_formedit_morethanoneform' )->text() ); |
| 296 | $output->addWikiTextAsInterface( $warning_text ); |
| 297 | } |
| 298 | |
| 299 | $form_name = $form_names[0]; |
| 300 | $page_name = $title->getPrefixedText(); |
| 301 | |
| 302 | $pfFormEdit = new PFFormEdit(); |
| 303 | $pfFormEdit->printForm( $form_name, $page_name ); |
| 304 | |
| 305 | return false; |
| 306 | } |
| 307 | |
| 308 | public function doesWrites() { |
| 309 | return true; |
| 310 | } |
| 311 | } |