Completed
Branch dev (1ad2e5)
by
unknown
04:33
created

AdminPageFramework_Model_Form   B

Complexity

Total Complexity 39

Size/Duplication

Total Lines 419
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 3

Importance

Changes 2
Bugs 0 Features 2
Metric Value
c 2
b 0
f 2
dl 0
loc 419
rs 8.2857
wmc 39
lcom 1
cbo 3

15 Methods

Rating   Name   Duplication   Size   Complexity  
B __construct() 0 19 5
A _replyToHandleSubmittedFormData() 0 9 1
B _replyToFieldsetResourceRegistration() 0 38 3
A _replyToModifySectionsets() 0 8 1
B _registerHelpPaneItemsOfFormSections() 0 29 3
A _replyToDetermineSectionsetVisibility() 0 14 4
A _isSectionOfCurrentPage() 0 19 3
A _replyToDetermineFieldsetVisibility() 0 11 2
B _replyToFormatFieldsetDefinition() 0 42 3
A _replyToFormatSectionsetDefinition() 0 21 2
B _getSectionCapability() 0 26 4
B _getSectionPageSlug() 0 22 4
A _getSectionTabSlug() 0 8 2
A _replyToDetermineWhetherToProcessFormRegistration() 0 4 1
A _replyToGetCapabilityForForm() 0 14 1
1
<?php
2
/**
3
 * Admin Page Framework
4
 * 
5
 * http://en.michaeluno.jp/admin-page-framework/
6
 * Copyright (c) 2013-2016 Michael Uno; Licensed MIT
7
 * 
8
 */
9
10
/**
11
 * Interacts with the database for the forms.
12
 *
13
 * @abstract
14
 * @since           3.3.1
15
 * @since           3.6.3       Changed the name from `AdminPageFramework_Form_Model`.
16
 * @extends         AdminPageFramework_Router
17
 * @package         AdminPageFramework
18
 * @subpackage      Factory/AdminPage/Model
19
 * @internal
20
 */
21
abstract class AdminPageFramework_Model_Form extends AdminPageFramework_Router {
22
    
23
    /**
24
     * Stores the settings field errors. 
25
     * 
26
     * @remark      Do not set a default value here since it is checked whether it is null or not later.
27
     * @since       2.0.0
28
     * @since       3.6.3       Changed the visibility scope to public as a delegation class needs to access this property.
29
     * @var         array       Stores field errors.
30
     * @internal
31
     */ 
32
    public $aFieldErrors; 
33
        
34
    /**
35
     * Stores the target page slug which will be applied when no page slug is specified for the `addSettingSection()` method.
36
     * 
37
     * @since       3.0.0
38
     */
39
    protected $_sTargetPageSlug = null;
40
    
41
    /**
42
     * Stores the target tab slug which will be applied when no tab slug is specified for the `addSettingSection()` method.
43
     * 
44
     * @since       3.0.0
45
     */    
46
    protected $_sTargetTabSlug = null;
47
48
    /**
49
     * Stores the target section tab slug which will be applied when no section tab slug is specified for the `addSettingSection()` method.
50
     * 
51
     * @since 3.0.0
52
     */    
53
    protected $_sTargetSectionTabSlug = null;
54
    
55
    /**
56
     * Registers necessary hooks and sets up properties.
57
     * 
58
     * @internal
59
     * @since       3.3.0
60
     * @since       3.3.1       Moved from `AdminPageFramework_Setting_Base`.
61
     */
62
    public function __construct( $sOptionKey=null, $sCallerPath=null, $sCapability='manage_options', $sTextDomain='admin-page-framework' ) {
0 ignored issues
show
Coding Style introduced by
__construct uses the super-global variable $_REQUEST which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
63
64
        parent::__construct( $sOptionKey, $sCallerPath, $sCapability, $sTextDomain );
65
        
66
        if ( $this->oProp->bIsAdminAjax ) {
67
            return;
68
        }
69
        if ( ! $this->oProp->bIsAdmin ) {
70
            return;
71
        }
72
73
        new AdminPageFramework_Model__FormEmailHandler( $this );                
74
        
75
        // Checking the GET and POST methods.
76
        if ( isset( $_REQUEST[ 'apf_remote_request_test' ] ) && '_testing' === $_REQUEST[ 'apf_remote_request_test' ] ) {
77
            exit( 'OK' );
0 ignored issues
show
Coding Style Compatibility introduced by
The method __construct() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
78
        }
79
        
80
    }
81
    
82
    /**
83
     * Validates submitted form data and saves them.
84
     * 
85
     * @since       3.7.0
86
     * @callback    form        handle_form_data
87
     * @return      void
88
     */
89
    public function _replyToHandleSubmittedFormData( $aSavedData, $aArguments, $aSectionsets, $aFieldsets ) {
90
        new AdminPageFramework_Model__FormSubmission( 
91
            $this,
92
            $aSavedData, 
93
            $aArguments, 
94
            $aSectionsets, 
95
            $aFieldsets
96
        );
97
    }
98
    
99
    /**
100
     * Called upon fieldset resource registration.
101
     * 
102
     * A contextual help pane item associated with this fieldset will be added.
103
     * 
104
     * @remark      Overrides the method of the factory class.
105
     * @since       3.7.0
106
     * @return      void
107
     */
108
    public function _replyToFieldsetResourceRegistration( $aFieldset ) {
109
        
110
        $aFieldset = $aFieldset + array(
111
            'help'          => null,
112
            'title'         => null,
113
            'help_aside'    => null,
114
            'page_slug'     => null,
115
            'tab_slug'      => null,
116
            'section_title' => null,
117
            'section_id'    => null,
118
        );
119
        if ( ! $aFieldset[ 'help' ] ) {
120
            return;
121
        }
122
123
        // Get the first item of the section path.
124
        $_sRootSectionID = $this->oUtil->getElement(
125
            $this->oUtil->getAsArray( $aFieldset[ 'section_id' ] ),
126
            0   
127
        );
128
        
129
        $this->addHelpTab( 
0 ignored issues
show
Documentation Bug introduced by
The method addHelpTab does not exist on object<AdminPageFramework_Model_Form>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
130
            array(
131
                'page_slug'                 => $aFieldset[ 'page_slug' ],
132
                'page_tab_slug'             => $aFieldset[ 'tab_slug' ],
133
                'help_tab_title'            => $aFieldset[ 'section_title' ],
134
                'help_tab_id'               => $_sRootSectionID,
135
                'help_tab_content'          => "<span class='contextual-help-tab-title'>" 
136
                        . $aFieldset[ 'title' ] 
137
                    . "</span> - " . PHP_EOL
138
                    . $aFieldset[ 'help' ],
139
                'help_tab_sidebar_content'  => $aFieldset[ 'help_aside' ] 
140
                    ? $aFieldset[ 'help_aside' ] 
141
                    : "",
142
            )
143
        );
144
                                  
145
    }
146
    
147
    /**
148
     * Modifies registered sectionsets definition array.
149
     * @since       3.7.0
150
     * @remark      Overrides the method of the factory class.
151
     * @return      array       The modified sectionsets definition array.
152
     */    
153
    public function _replyToModifySectionsets( $aSectionsets ) {
154
155
        // Help pane elements must be added before the head tag gets rendered.
156
        $this->_registerHelpPaneItemsOfFormSections( $aSectionsets );
157
        
158
        return parent::_replyToModifySectionsets( $aSectionsets );
159
160
    }    
161
        /**
162
         * Parse the definition array and add help pane items.
163
         * 
164
         * Help pane elements must be added before the head tag gets rendered.
165
         * @return      void
166
         * @since       3.7.0
167
         */
168
        public function _registerHelpPaneItemsOfFormSections( $aSectionsets ) {            
169
// @todo Test if help pane item gets displayed        
170
171
            foreach( $aSectionsets as $_aSectionset ) {
172
// @todo check capability and conditions                
173
                $_aSectionset = $_aSectionset + array(
174
                    'help'          => null,
175
                    'page_slug'     => null,
176
                    'tab_slug'      => null,
177
                    'title'         => null,
178
                    'section_id'    => null,
179
                    'help'          => null,
180
                    'help_aside'    => null,
181
                );
182
                if ( empty( $_aSectionset[ 'help' ] ) ) {
183
                    continue;
184
                }
185
                $this->addHelpTab( 
0 ignored issues
show
Documentation Bug introduced by
The method addHelpTab does not exist on object<AdminPageFramework_Model_Form>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
186
                    array(
187
                        'page_slug'                 => $_aSectionset[ 'page_slug' ],
188
                        'page_tab_slug'             => $_aSectionset[ 'tab_slug' ],
189
                        'help_tab_title'            => $_aSectionset[ 'title' ],
190
                        'help_tab_id'               => $_aSectionset[ 'section_id' ],
191
                        'help_tab_content'          => $_aSectionset[ 'help' ],
192
                        'help_tab_sidebar_content'  => $this->getElement( $_aSectionset, 'help_aside', '' ),
0 ignored issues
show
Documentation Bug introduced by
The method getElement does not exist on object<AdminPageFramework_Model_Form>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
193
                    )
194
                );            
195
            }
196
        }
197
            
198
    /**
199
     * Determines whether the passed field should be visible or not.
200
     * @since       3.7.0
201
     * @return      boolean
202
     */
203
    public function _replyToDetermineSectionsetVisibility( $bVisible, $aSectionset ) {
204
205
        if ( ! current_user_can( $aSectionset[ 'capability' ] ) ) {
206
            return false;
207
        }
208
        if ( ! $aSectionset[ 'if' ] ) { 
209
            return false;
210
        }
211
        if ( ! $this->_isSectionOfCurrentPage( $aSectionset ) ) { 
212
            return false;
213
        }
214
        return $bVisible;
215
        
216
    }
217
        /**
218
         * Checks if the given section belongs to the currently loading tab.
219
         * 
220
         * @since       2.0.0
221
         * @since       3.0.0       Moved from the setting class.
222
         * @since       3.7.0      Moved from `AdminPageFramework_FormDefinition_Page`.
223
         * @remark      Assumes the given section definition array is already formatted.
224
         * @return      boolean     Returns true if the section belongs to the current tab page. Otherwise, false.
225
         */     
226
        private function _isSectionOfCurrentPage( array $aSectionset ) {
227
        
228
            // Make sure the value type is string so that when the page_slug is not set, it won't match.
229
            $_sCurrentPageSlug  = ( string ) $this->oProp->getCurrentPageSlug();
230
            
231
            // Make sure if it's in the loading page.
232
            if ( $aSectionset[ 'page_slug' ] !== $_sCurrentPageSlug  ) { 
233
                return false; 
234
            }
235
236
            // If no tag is specified, the user wants to display the section regardless of the tab.
237
            if ( ! $aSectionset[ 'tab_slug' ] ) {
238
                return true;
239
            }
240
                
241
            // If the checking tab slug and the current loading tab slug is the same, it should be registered.
242
            return  ( $aSectionset[ 'tab_slug' ] === $this->oProp->getCurrentTabSlug( $_sCurrentPageSlug ) );
243
            
244
        }        
245
    
246
    /**
247
     * Determines whether the passed field should be visible or not.
248
     * @since       3.7.0
249
     * @return      boolean
250
     */
251
    public function _replyToDetermineFieldsetVisibility( $bVisible, $aFieldset ) {
252
        
253
        $_sCurrentPageSlug  = $this->oProp->getCurrentPageSlug();
254
        
255
        // If the specified field does not exist, do nothing.
256
        if ( $aFieldset[ 'page_slug' ] !== $_sCurrentPageSlug ) { 
257
            return false; 
258
        }        
259
        return parent::_replyToDetermineFieldsetVisibility( $bVisible, $aFieldset );
260
        
261
    }
262
    
263
    /**
264
     * @since       3.7.0
265
     * @return      array
266
     */
267
    public function _replyToFormatFieldsetDefinition( $aFieldset, $aSectionsets ) {
268
        
269
        if ( empty( $aFieldset ) ) { 
270
            return $aFieldset; 
271
        }
272
        
273
        $_aSectionPath = $this->oUtil->getAsArray( $aFieldset[ 'section_id' ] );
274
        $_sSectionPath = implode( '|', $_aSectionPath );
275
        
276
        $aFieldset[ 'option_key' ]      = $this->oProp->sOptionKey;
277
        $aFieldset[ 'class_name' ]      = $this->oProp->sClassName;
278
        $aFieldset[ 'page_slug' ]       = $this->oUtil->getElement( 
279
            $aSectionsets, 
280
            array( $_sSectionPath, 'page_slug' ), 
281
            $this->oProp->getCurrentPageSlugIfAdded()
282
        );        
283
        $aFieldset[ 'tab_slug' ]        = $this->oUtil->getElement( 
284
            $aSectionsets, 
285
            array( $_sSectionPath, 'tab_slug' ), 
286
            $this->oProp->getCurrentInPageTabSlugIfAdded()
287
        );
288
        
289
        // used for the contextual help pane.
290
        $_aSectionset = $this->oUtil->getElementAsArray(
291
            $aSectionsets,
292
            $_sSectionPath
293
        );
294
        $aFieldset[ 'section_title' ]   = $this->oUtil->getElement( 
295
            $_aSectionset, 
296
            'title'
297
        );
298
        $aFieldset[ 'capability' ]   = $aFieldset[ 'capability' ]
299
            ? $aFieldset[ 'capability' ]
300
            : $this->_replyToGetCapabilityForForm( 
301
                $this->oUtil->getElement( $_aSectionset, 'capability' ),
302
                $aSectionset[ 'page_slug' ], 
0 ignored issues
show
Bug introduced by
The variable $aSectionset does not exist. Did you mean $aSectionsets?

This check looks for variables that are accessed but have not been defined. It raises an issue if it finds another variable that has a similar name.

The variable may have been renamed without also renaming all references.

Loading history...
303
                $aSectionset[ 'tab_slug' ] 
0 ignored issues
show
Bug introduced by
The variable $aSectionset does not exist. Did you mean $aSectionsets?

This check looks for variables that are accessed but have not been defined. It raises an issue if it finds another variable that has a similar name.

The variable may have been renamed without also renaming all references.

Loading history...
304
            );
305
306
        return parent::_replyToFormatFieldsetDefinition( $aFieldset, $aSectionsets );
307
    
308
    }
309
    
310
    /**
311
     * @since       3.7.0
312
     * @return      array
313
     */
314
    public function _replyToFormatSectionsetDefinition( $aSectionset ) {
315
        
316
        if ( empty( $aSectionset ) ) {
317
            return $aSectionset;
318
        }
319
320
        $aSectionset = $aSectionset + array(
321
            'page_slug'     => null,
322
            'tab_slug'      => null,
323
            'capability'    => null,
324
        );
325
        
326
        $aSectionset[ 'page_slug' ]  = $this->_getSectionPageSlug( $aSectionset );
327
        $aSectionset[ 'tab_slug' ]   = $this->_getSectionTabSlug( $aSectionset );
328
        
329
        // 3.6.0+ Inherit the capability value from the page.
330
        $aSectionset[ 'capability' ] = $this->_getSectionCapability( $aSectionset );
331
       
332
        return parent::_replyToFormatSectionsetDefinition( $aSectionset );
333
        
334
    }
335
        /**
336
         * Attempts to find the capability of a given section.
337
         * @since       3.7.0
338
         * @return      string
339
         */
340
        private function _getSectionCapability( $aSectionset ) {
341
            
342
            if ( $aSectionset[ 'capability' ] ) {
343
                return $aSectionset[ 'capability' ];
344
            }
345
            
346
            // Find the capability of the parent section if nested.
347
            if ( 0 < $aSectionset[ '_nested_depth' ] ) {
348
                $_aSectionPath         = $aSectionset[ '_section_path_array' ];
349
                array_pop( $_aSectionPath ); // remove the last element
350
                $_sParentCapability = $this->oUtil->getElement(
351
                    $this->oForm->aSectionsets,
352
                    array_merge( $_aSectionPath, array( 'capability' ) )
353
                );
354
                if( $_sParentCapability ) {
355
                    return $_sParentCapability;
356
                }
357
            }
358
            
359
            return $this->_replyToGetCapabilityForForm( 
360
                $aSectionset[ 'capability' ], 
361
                $aSectionset[ 'page_slug' ], 
362
                $aSectionset[ 'tab_slug' ] 
363
            );            
364
            
365
        }
366
        /**
367
         * Attempts to find the page slug of a given section set definition.
368
         * 
369
         * Nested sections may not have the page slug assigned. 
370
         * In that case, it tries to set the value of the ancestor.
371
         * 
372
         * @since       3.7.0
373
         * @return      string
374
         */
375
        private function _getSectionPageSlug( $aSectionset ) {
376
            
377
            if ( $aSectionset[ 'page_slug' ] ) {
378
                return $aSectionset[ 'page_slug' ];
379
            }
380
            if ( 0 < $aSectionset[ '_nested_depth' ] ) {
381
                
382
                $_aSectionPath         = $aSectionset[ '_section_path_array' ];
383
                $_sRootSectionID       = $this->oUtil->getFirstElement( $_aSectionPath );
384
                $_sRootSectionPageSlug = $this->oUtil->getElement( 
385
                    $this->oForm->aSectionsets,
386
                    array( $_sRootSectionID, 'page_slug' )
387
                );
388
                if ( $_sRootSectionPageSlug ) {
389
                    return $_sRootSectionPageSlug;
390
                }
391
            }
392
            return $this->oProp->getCurrentPageSlugIfAdded();
393
            // @deprecated 3.7.2
394
            // return $this->oProp->sDefaultPageSlug;
395
            
396
        }
397
        /**
398
         * @since       3.7.2
399
         * @return      string|null
400
         */
401
        private function _getSectionTabSlug( $aSectionset ) {
402
            
403
            if ( $aSectionset[ 'tab_slug' ] ) {
404
                return $aSectionset[ 'tab_slug' ];
405
            }            
406
            return $this->oProp->getCurrentInPageTabSlugIfAdded();
407
            
408
        }
409
    /**
410
     * @since       3.7.0
411
     * @return      boolean     Whether or not the form registration should be allowed in the current screen.
412
     */
413
    public function _replyToDetermineWhetherToProcessFormRegistration( $bAllowed ) {
414
        $_sPageSlug = $this->oProp->getCurrentPageSlug();
415
        return $this->oProp->isPageAdded( $_sPageSlug );
416
    }
417
    /**
418
     * Returns the inherited capability value from the page and in-page tab for form elements.
419
     * 
420
     * @since       3.6.0
421
     * @since       3.7.0      Moved from `AdminPageFramework_FormDefinition_Page`.
422
     * @return      string
423
     */    
424
    public function _replyToGetCapabilityForForm( $sCapability /*, $sPageSlug, $sTabSlug */ ) {
425
        
426
        $_aParameters     = func_get_args() + array( '', '', '' );
427
        $_sPageSlug       = $this->oUtil->getAOrB( $_aParameters[ 1 ], $_aParameters[ 1 ], $this->oProp->getCurrentPageSlug() );
428
        $_sTabSlug        = $this->oUtil->getAOrB( $_aParameters[ 2 ], $_aParameters[ 2 ], $this->oProp->getCurrentTabSlug( $_sPageSlug ) );
429
        
430
        // Note that the passed capability value to the method is same as the one set to the factory class constructor.
431
        $_sTabCapability  = $this->_getInPageTabCapability( $_sTabSlug, $_sPageSlug );
0 ignored issues
show
Documentation Bug introduced by
The method _getInPageTabCapability does not exist on object<AdminPageFramework_Model_Form>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
432
        $_sPageCapability = $this->_getPageCapability( $_sPageSlug );
0 ignored issues
show
Documentation Bug introduced by
The method _getPageCapability does not exist on object<AdminPageFramework_Model_Form>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
433
        $_aCapabilities   = array_filter( array( $_sTabCapability, $_sPageCapability ) )
434
            + array( $this->oProp->sCapability );
435
        return $_aCapabilities[ 0 ];
436
437
    }
438
    
439
}
440