Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
61 / 61
100.00% covered (success)
100.00%
7 / 7
CRAP
100.00% covered (success)
100.00%
1 / 1
PFHelperFormAction
100.00% covered (success)
100.00%
61 / 61
100.00% covered (success)
100.00%
7 / 7
26
100.00% covered (success)
100.00%
1 / 1
 setHelperPageFactory
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getName
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 show
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 execute
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 displayTab
100.00% covered (success)
100.00%
40 / 40
100.00% covered (success)
100.00%
1 / 1
14
 displayForm
100.00% covered (success)
100.00%
14 / 14
100.00% covered (success)
100.00%
1 / 1
6
 newHelperPage
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
1<?php
2
3use MediaWiki\MediaWikiServices;
4
5/**
6 * Handles the formcreate action - used for helper forms for creating
7 * properties, forms, etc..
8 *
9 * @author Yaron Koren
10 * @file
11 * @ingroup PF
12 */
13
14class PFHelperFormAction extends Action {
15    /** @var callable|null */
16    private static $helperPageFactory = null;
17
18    /**
19     * Allows tests to override helper page construction.
20     *
21     * @param callable|null $factory
22     */
23    public static function setHelperPageFactory( ?callable $factory ): void {
24        self::$helperPageFactory = $factory;
25    }
26
27    /**
28     * Return the name of the action this object responds to
29     * @return string lowercase
30     */
31    public function getName() {
32        return 'formcreate';
33    }
34
35    /**
36     * The main action entry point.  Do all output for display and send it to the context
37     * output.  Do not use globals $wgOut, $wgRequest, etc, in implementations; use
38     * $this->getOutput(), etc.
39     * @throws ErrorPageError
40     * @return false
41     */
42    public function show() {
43        return self::displayForm( $this->getArticle() );
44    }
45
46    /**
47     * Execute the action in a silent fashion: do not display anything or release any errors.
48     * @return bool whether execution was successful
49     */
50    public function execute() {
51        return true;
52    }
53
54    /**
55     * Handler for the SkinTemplateNavigation hook.
56     *
57     * Adds an "action" (i.e., a tab) to edit the current article with
58     * a form
59     * @param SkinTemplate $obj
60     * @param array &$links
61     */
62    static function displayTab( $obj, &$links ) {
63        $title = $obj->getTitle();
64        $user = $obj->getUser();
65
66        // Make sure that this page is in one of the relevant
67        // namespaces, and that it doesn't exist yet.
68        $namespacesWithHelperForms = [ NS_TEMPLATE, PF_NS_FORM, NS_CATEGORY ];
69        if ( defined( 'SMW_NS_PROPERTY' ) ) {
70            $namespacesWithHelperForms[] = SMW_NS_PROPERTY;
71        }
72        if ( !isset( $title ) ||
73            ( !in_array( $title->getNamespace(), $namespacesWithHelperForms ) ) ) {
74            return;
75        }
76        if ( $title->exists() ) {
77            return;
78        }
79
80        // The tab should show up automatically for properties and
81        // forms, but not necessarily for templates and categories,
82        // since some of them might be outside of the SMW/PF system.
83        if ( in_array( $title->getNamespace(), [ NS_TEMPLATE, NS_CATEGORY ] ) ) {
84            global $wgPageFormsShowTabsForAllHelperForms;
85            if ( !$wgPageFormsShowTabsForAllHelperForms ) {
86                return;
87            }
88        }
89
90        $content_actions = &$links['views'];
91
92        $permissionManager = MediaWikiServices::getInstance()->getPermissionManager();
93        $userCanEdit = $permissionManager->userCan( 'edit', $user, $title, $permissionManager::RIGOR_QUICK );
94        $form_create_tab_text = ( $userCanEdit ) ? 'pf_formcreate' : 'pf_viewform';
95
96        $class_name = ( $obj->getRequest()->getVal( 'action' ) == 'formcreate' ) ? 'selected' : '';
97        $form_create_tab = [
98            'class' => $class_name,
99            'text' => wfMessage( $form_create_tab_text )->text(),
100            'href' => $title->getLocalURL( 'action=formcreate' ),
101        ];
102
103        // For more recent MediaWiki versions, adding this icon adds
104        // this action to the MinervaNeue skin, while having no impact
105        // on the Vector 2022 skin; for earlier versions, it has no
106        // impact on MinervaNeue, while replacing the tab in Vector 2022
107        // with an icon (which is not good).
108        // @todo - find the ideal check for this addition, because it's
109        // probably not exactly this.
110        if ( version_compare( MW_VERSION, '1.44', '>=' ) ) {
111            $form_create_tab['icon'] = 'edit';
112        }
113
114        // Find the location of the 'create' tab, and add 'create
115        // with form' right before it.
116        // This is a "key-safe" splice - it preserves both the keys
117        // and the values of the array, by editing them separately
118        // and then rebuilding the array. Based on the example at
119        // http://us2.php.net/manual/en/function.array-splice.php#31234
120        $tab_keys = array_keys( $content_actions );
121        $tab_values = array_values( $content_actions );
122        $edit_tab_location = array_search( 'edit', $tab_keys );
123
124        // If there's no 'edit' tab, look for the 'view source' tab
125        // instead.
126        if ( $edit_tab_location == null ) {
127            $edit_tab_location = array_search( 'viewsource', $tab_keys );
128        }
129
130        // This should rarely happen, but if there was no edit *or*
131        // view source tab, set the location index to -1, so the
132        // tab shows up near the end.
133        if ( $edit_tab_location == null ) {
134            $edit_tab_location = -1;
135        }
136        array_splice( $tab_keys, $edit_tab_location, 0, 'formedit' );
137        array_splice( $tab_values, $edit_tab_location, 0, [ $form_create_tab ] );
138        $content_actions = [];
139        foreach ( $tab_keys as $i => $key ) {
140            $content_actions[$key] = $tab_values[$i];
141        }
142
143        if ( !$obj->getUser()->isAllowed( 'viewedittab' ) ) {
144            // The tab can have either of these two actions.
145            unset( $content_actions['edit'] );
146            unset( $content_actions['viewsource'] );
147        }
148    }
149
150    /**
151     * The function called if we're in index.php (as opposed to one of the
152     * special pages).
153     * @param Article $article
154     * @return false
155     */
156    private static function displayForm( $article ) {
157        $title = $article->getTitle();
158        if ( defined( 'SMW_NS_PROPERTY' ) && $title->getNamespace() == SMW_NS_PROPERTY ) {
159            $createPropertyPage = self::newHelperPage( PFCreateProperty::class );
160            $createPropertyPage->execute( $title->getText() );
161        } elseif ( $title->getNamespace() == NS_TEMPLATE ) {
162            $createTemplatePage = self::newHelperPage( PFCreateTemplate::class );
163            $createTemplatePage->execute( $title->getText() );
164        } elseif ( $title->getNamespace() == PF_NS_FORM ) {
165            $createFormPage = self::newHelperPage( PFCreateForm::class );
166            $createFormPage->execute( $title->getText() );
167        } elseif ( $title->getNamespace() == NS_CATEGORY ) {
168            $createCategoryPage = self::newHelperPage( PFCreateCategory::class );
169            $createCategoryPage->execute( $title->getText() );
170        }
171
172        return false;
173    }
174
175    /**
176     * @param string $className
177     * @return PFCreateProperty|PFCreateTemplate|PFCreateForm|PFCreateCategory
178     */
179    private static function newHelperPage( string $className ) {
180        if ( self::$helperPageFactory !== null ) {
181            return call_user_func( self::$helperPageFactory, $className );
182        }
183
184        return new $className();
185    }
186}