AdminPageFramework_FieldType_Base   B
last analyzed

Complexity

Total Complexity 44

Size/Duplication

Total Lines 424
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 44
eloc 124
dl 0
loc 424
rs 8.8798
c 0
b 0
f 0

22 Methods

Rating   Name   Duplication   Size   Complexity  
A _replyToReplaceThickBoxText() 0 18 5
A _replyToGetScripts() 0 1 1
A _replyToRemovingMediaLibraryTab() 0 9 3
A _replyToGetInputIEStyles() 0 1 1
A getLabelContainerAttributes() 0 12 3
A isTinyMCESupported() 0 3 2
A _replyToGetEnqueuingStyles() 0 1 1
A getDefinitionArray() 0 21 3
A _replyToDoOnFieldRegistration() 0 1 1
A _replyToGetStyles() 0 1 1
A enqueueMediaUploader() 0 17 4
A geFieldOutput() 0 2 1
A __construct() 0 21 5
A getElementByLabel() 0 11 3
A construct() 0 1 1
A _replyToFieldTypeSetter() 0 2 1
A getFieldOutput() 0 21 2
A _replyToGetEnqueuingScripts() 0 1 1
A replyToEnqueueScriptsForMediaUpload() 0 3 1
A _replyToRegisterInputFieldType() 0 6 2
A _replyToGetField() 0 1 1
A _replyToFieldLoader() 0 1 1

How to fix   Complexity   

Complex Class

Complex classes like AdminPageFramework_FieldType_Base often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use AdminPageFramework_FieldType_Base, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * Admin Page Framework
4
 * 
5
 * http://admin-page-framework.michaeluno.jp/
6
 * Copyright (c) 2013-2022, Michael Uno; Licensed MIT
7
 * 
8
 */
9
10
/**
11
 * The base class of field type classes that define input field types.
12
 * 
13
 * @package     AdminPageFramework/Common/Form/FieldType
14
 * @since       2.1.5
15
 * @since       3.8.0       Changed it to extend the `AdminPageFramework_Form_Utility`.
16
 * @internal
17
 * @extends     AdminPageFramework_FrameworkUtility
18
 */
19
abstract class AdminPageFramework_FieldType_Base extends AdminPageFramework_Form_Utility {
20
    
21
    /**
22
     * Stores the field set type indicating what this field is for such as for meta boxes, taxonomy fields or page fields.
23
     * @remark      This will be automatically set when head tag elements are enqueued.
24
     * @since       3.0.0
25
     * @internal
26
     */
27
    public $_sFieldSetType = '';
28
    
29
    /**
30
     * Defines the slugs used for this field type.
31
     * 
32
     * This should be overridden in the extended class.
33
     * 
34
     * @access       public      This must be public as accessed from outside.
35
     */
36
    public $aFieldTypeSlugs = array( 'default' );
37
    
38
    /**
39
     * Defines the default key-values of the extended field type. 
40
     * This should be overridden in the extended class.
41
     */
42
    protected $aDefaultKeys = array();
43
    
44
    /**
45
     * Defines the default key-values of all field types.
46
     * 
47
     * @internal
48
     */
49
    protected static $_aDefaultKeys = array(
50
        'value'             => null, // ( array or string ) this suppresses the default key value. This is useful to display the value saved in a custom place other than the framework automatically saves.
51
        'default'           => null, // ( array or string )
52
        'repeatable'        => false,
53
        'sortable'          => false,
54
        'label'             => '', // ( string ) labels for some input fields. Do not set null here because it is casted as string in the field output methods, which creates an element of empty string so that it can be iterated with foreach().
55
        'delimiter'         => '',
56
        'before_input'      => '',
57
        'after_input'       => '',     
58
        'before_label'      => null,
59
        'after_label'       => null,    
60
        'before_field'      => null,
61
        'after_field'       => null,
62
        'label_min_width'   => '',   // (string|integer) min-width applied to the input label in pixels. 3.8.0+ Changed the default value from 140 to 0 as it is now applied via embedded CSS. When this value is set by the user, it is set inline and the value will be overridden. [3.8.4+] Changed the value from `0`  to `''`.
63
        'before_fieldset'   => null, // 3.1.1+
64
        'after_fieldset'    => null, // 3.1.1+
65
        
66
        /* Mandatory keys */
67
        'field_id'          => null,     
68
        
69
        /* For the meta box class - it does not require the following keys; these are just to help to avoid undefined index warnings. */
70
        'page_slug'         => null,
71
        'section_id'        => null,
72
        'before_fields'     => null,
73
        'after_fields'      => null,    
74
        
75
        'attributes'        => array(
76
            /* Root Attributes - the root attributes are assumed to be for the input tag. */
77
            'disabled'  => null, // set 'Disabled' or an empty value '' to make it disabled. Null will not set the attribute.
78
            'class'     => '',
79
            
80
            /* Component Attributes */
81
            'fieldrow'  => array(), // attributes applied to the field group container row tag that holds all the field components including descriptions and scripts and the title.
82
            'fieldset'  => array(), // attributes applied to the field group container tag that holds all the field components including descriptions and scripts.
83
            'fields'    => array(), // attributes applied to the fields container tag that holds all sub-fields.
84
            'field'     => array(), // attributes applied to each field container tag.
85
        ),
86
    );    
87
    
88
    protected $oMsg;
89
    
90
    /**
91
     * Sets up hooks and properties.
92
     * 
93
     * @internal
94
     * @since       2.1.5
95
     * @since       3.5.0               'admin_page_framework' can be passed to register the field type site-wide.
96
     * @param       string|array        $asClassName            The instantiated class name that uses the field type(s). To enable it site-wide, pass `admin_page_framework`. 
97
     * This value will be used to the `field_types_{instantiated class name}` filter to set field definition callbacks.
98
     * @param       string|array        $asFieldTypeSlug        The field type slugs. To have multiple slugs for one definition, pass an array holding the slugs.
99
     * @param       object              $oMsg                   The framework message object.
100
     * @param       boolean             $bAutoRegister          Whether or not to register the field type(s).
101
     */
102
    public function __construct( $asClassName='admin_page_framework', $asFieldTypeSlug=null, $oMsg=null, $bAutoRegister=true ) {
103
            
104
        $this->aFieldTypeSlugs  = empty( $asFieldTypeSlug ) 
105
            ? $this->aFieldTypeSlugs 
106
            : ( array ) $asFieldTypeSlug;
107
        $this->oMsg             = $oMsg 
108
            ? $oMsg 
109
            : AdminPageFramework_Message::getInstance();
110
        
111
        // This automatically registers the field type. The build-in ones will be registered manually so it will be skipped.
112
        if ( $bAutoRegister ) {
113
            foreach( ( array ) $asClassName as $_sClassName ) {
114
                add_filter( 
115
                    'field_types_' . $_sClassName, 
116
                    array( $this, '_replyToRegisterInputFieldType' )
117
                );
118
            }
119
        }
120
        
121
        // User constructor
122
        $this->construct();
123
        
124
    }    
125
    
126
    /**
127
     * The user constructor.
128
     * 
129
     * When the user defines a field type, they may use this instead of the real constructor 
130
     * so that they don't have to care about the internal parameters.
131
     * 
132
     * @since       3.1.3
133
     */
134
    protected function construct() {}
135
    
136
    /**
137
     * Checks whether TinyMCE is supported.
138
     * @since       3.5.8
139
     * @return      boolean
140
     */
141
    protected function isTinyMCESupported() {
142
        return version_compare( $GLOBALS[ 'wp_version' ], '3.3', '>=' )
143
            && function_exists( 'wp_editor' )
144
        ;
145
    }
146
    
147
    /**
148
     * Returns the sub-element of a given element by the element key.
149
     * 
150
     * @remark      Used by the `text`, `textarea`, `size`, 'radio', and `checkbox` field types.
151
     * @since       3.5.8
152
     * @since       3.7.0        Changed the third parameter to accept a label argument from a boolean value to be usable for other filed types.
153
     * @param       array|string $asElement
154
     * @param       array|string $asKey
155
     * @param       array|string $asLabel
156
     * @return      string
157
     */
158
    protected function getElementByLabel( $asElement, $asKey, $asLabel ) {
159
        if ( is_scalar( $asElement ) ) {
160
            return $asElement;
161
        }
162
        return is_array( $asLabel ) // if the user sets multiple items
0 ignored issues
show
Bug Best Practice introduced by
The expression return is_array($asLabel...true), '') : $asElement also could return the type array which is incompatible with the documented return type string.
Loading history...
163
            ? $this->getElement( 
164
                $asElement,         // subject
165
                $this->getAsArray( $asKey, true /* preserve empty */ ),     // dimensional path 
166
                ''                  // default - if the element is not found, return an empty
167
            )
168
            : $asElement;
169
    }    
170
      
171
    /**
172
     * Returns another field output by the given field definition array.
173
     * 
174
     * This is used to create nested fields or dynamically create a different type of field.
175
     * @since       3.4.0
176
     * @param       array       $aFieldset
177
     * @return      string      The fieldset output.
178
     */
179
    protected function getFieldOutput( array $aFieldset ) {
180
        
181
        if ( ! is_object( $aFieldset[ '_caller_object' ] ) ) {
182
            return '';
183
        }
184
185
        $aFieldset[ '_nested_depth' ]++;
186
        $aFieldset[ '_parent_field_object' ] = $aFieldset[ '_field_object' ]; // 3.6.0+
187
        
188
        // 3.7.0+ The caller object is no longer a factory object but a form object.
189
        $_oCallerForm   = $aFieldset[ '_caller_object' ];
190
191
        $_oFieldset = new AdminPageFramework_Form_View___Fieldset( 
192
            $aFieldset,                          // the field definition array
193
            $_oCallerForm->aSavedData,               // the stored form data
194
            $_oCallerForm->getFieldErrors(),         // the field error array.
195
            $_oCallerForm->aFieldTypeDefinitions,    // the field type definition array.
196
            $_oCallerForm->oMsg,                     // the system message object
197
            $_oCallerForm->aCallbacks                // field output element callables.
198
        );           
199
        return $_oFieldset->get();
200
        
201
    }
202
        /**
203
         * @deprecated  Kept for backward compatibility.
204
         * @param       array       $aFieldset
205
         * @return      string
206
         */
207
        protected function geFieldOutput( array $aFieldset ) {
208
            return $this->getFieldOutput( $aFieldset );
209
        }
210
    
211
    /**
212
     * Registers the field type.
213
     * 
214
     * @since       2.1.5
215
     * @callback    filter      field_types_{class name}
216
     * @callback    filter      field_types_admin_page_framework
217
     * @return      array
218
     * @internal
219
     */
220
    public function _replyToRegisterInputFieldType( $aFieldDefinitions ) {
221
        
222
        foreach ( $this->aFieldTypeSlugs as $sFieldTypeSlug ) {
223
            $aFieldDefinitions[ $sFieldTypeSlug ] = $this->getDefinitionArray( $sFieldTypeSlug );
224
        }
225
        return $aFieldDefinitions;     
226
227
    }
228
    
229
    /**
230
     * Returns the field type definition array.
231
     * 
232
     * @remark      The scope is public since AdminPageFramework_FieldType class allows the user to use this method.
233
     * @since       2.1.5
234
     * @since       3.0.0       Added the $sFieldTypeSlug parameter.
235
     * @since       3.0.3       Tweaked it to have better execution speed.
236
     * @param       string      $sFieldTypeSlug
237
     * @return      array
238
     * @internal
239
     */
240
    public function getDefinitionArray( $sFieldTypeSlug='' ) {
241
        
242
        // The uniteArrays() method resulted in somewhat being slow due to overhead on checking array keys for recursive array merges.
243
        $_aDefaultKeys = $this->aDefaultKeys + self::$_aDefaultKeys;
244
        $_aDefaultKeys['attributes'] = isset( $this->aDefaultKeys['attributes'] ) && is_array( $this->aDefaultKeys['attributes'] )
245
            ? $this->aDefaultKeys['attributes'] + self::$_aDefaultKeys['attributes'] 
246
            : self::$_aDefaultKeys['attributes'];
247
        
248
        return array(
249
            'sFieldTypeSlug'        => $sFieldTypeSlug,
250
            'aFieldTypeSlugs'       => $this->aFieldTypeSlugs,
251
            'hfRenderField'         => array( $this, "_replyToGetField" ),
252
            'hfGetScripts'          => array( $this, "_replyToGetScripts" ),
253
            'hfGetStyles'           => array( $this, "_replyToGetStyles" ),
254
            'hfGetIEStyles'         => array( $this, "_replyToGetInputIEStyles" ),
255
            'hfFieldLoader'         => array( $this, "_replyToFieldLoader" ),
256
            'hfFieldSetTypeSetter'  => array( $this, "_replyToFieldTypeSetter" ),
257
            'hfDoOnRegistration'    => array( $this, "_replyToDoOnFieldRegistration" ), // 3.5.0+
258
            'aEnqueueScripts'       => $this->_replyToGetEnqueuingScripts(), // urls of the scripts
259
            'aEnqueueStyles'        => $this->_replyToGetEnqueuingStyles(), // urls of the styles
260
            'aDefaultKeys'          => $_aDefaultKeys,       
261
        );
262
        
263
    }
264
    
265
    /*
266
     * These methods should be overridden in the extended class.
267
     */
268
    /**
269
     * @internal
270
     * @param       array      $aField
271
     * @return      string
272
     */    
273
    public function _replyToGetField( $aField ) { return ''; }          // should return the field output
274
    /**#@+
275
     * @internal
276
     * @return   string
277
     */
278
    public function _replyToGetScripts() { return ''; }                 // should return the script
279
    public function _replyToGetInputIEStyles() { return ''; }           // should return the style for IE
280
    public function _replyToGetStyles() { return ''; }                  // should return the style
281
    /**#@-*/
282
    public function _replyToFieldLoader() {}                            // do stuff that should be done when the field type is loaded for the first time.
283
284
    /**
285
     * Sets the field set type.
286
     * 
287
     * Called when enqueuing the field type's head tag elements.
288
     * @since       3.0.0
289
     * @param       string  $sFieldSetType
290
     * @internal
291
     */
292
    public function _replyToFieldTypeSetter( $sFieldSetType='' ) {
293
        $this->_sFieldSetType = $sFieldSetType;
294
    }
295
    
296
    /**
297
     * Called when the given field of this field type is registered.
298
     * 
299
     * @since       3.5.0
300
     * @param       array       $aField
301
     * @internal
302
     */
303
    public function _replyToDoOnFieldRegistration( $aField ) {}
0 ignored issues
show
Unused Code introduced by
The parameter $aField is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

303
    public function _replyToDoOnFieldRegistration( /** @scrutinizer ignore-unused */ $aField ) {}

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
304
    
305
    /**
306
     * 
307
     * @return array e.g. each element can hold a sting of the source url: array( 'http://..../my_script.js', 'http://..../my_script2.js' )
308
     * Optionally, an option array can be passed to specify dependencies etc.
309
     * array( array( 'src' => 'http://...my_script1.js', 'dependencies' => array( 'jquery' ) ), 'http://.../my_script2.js' )
310
     * @internal
311
     */
312
    protected function _replyToGetEnqueuingScripts() { return array(); } // should return an array holding the urls of enqueuing items
313
    
314
    /**
315
     * @return array e.g. each element can hold a sting of the source url: array( 'http://..../my_style.css', 'http://..../my_style2.css' )
316
     * Optionally, an option array can be passed to specify dependencies etc.
317
     * array( array( 'src' => 'http://...my_style1.css', 'dependencies' => array( 'jquery' ) ), 'http://.../my_style2.css' )
318
     * @internal
319
     */
320
    protected function _replyToGetEnqueuingStyles() { return array(); } // should return an array holding the urls of enqueuing items
321
        
322
    /*
323
     * Shared methods
324
     */
325
    
326
    /**
327
     * Enqueues scripts for the media uploader.
328
     * 
329
     * @remark      Used by the image and the media field types.
330
     * @internal
331
     */
332
    protected function enqueueMediaUploader() {
333
        
334
        add_filter( 'media_upload_tabs', array( $this, '_replyToRemovingMediaLibraryTab' ) );
335
        
336
        wp_enqueue_script( 'jquery' );     
337
        wp_enqueue_script( 'thickbox' );
338
        wp_enqueue_style( 'thickbox' );
339
340
        // If the WordPress version is 3.5 or above,
341
        if ( function_exists( 'wp_enqueue_media' ) ) {
342
            add_action( is_admin() ? 'admin_footer' : 'wp_footer', array( $this, 'replyToEnqueueScriptsForMediaUpload' ), 1 );
343
        } else {
344
            wp_enqueue_script( 'media-upload' );    
345
        }
346
347
        if ( in_array( $this->getPageNow(), array( 'media-upload.php', 'async-upload.php', ) ) ) {     
348
            add_filter( 'gettext', array( $this, '_replyToReplaceThickBoxText' ) , 1, 2 );     
349
        }
350
        
351
    }
352
        /**
353
         * Enqueues scripts for media upload.
354
         * These must be done after the `admin-page-framework-script-form-media-uploader` script is registered.
355
         * The `enqueueMediaUploader()` method maybe called earlier than that, so do it in the footer action hook.
356
         * @since    3.9.0
357
         * @callback action wp_footer|admin_footer
358
         */
359
        public function replyToEnqueueScriptsForMediaUpload() {
360
            wp_enqueue_media();
361
            wp_enqueue_script( 'admin-page-framework-script-form-media-uploader' );
362
        }
363
364
        /**
365
         * Replaces the label text of a button used in the media uploader.
366
         * 
367
         * @internal
368
         * @since       2.0.0
369
         * @param       string       $sTranslated
370
         * @param       string       $sText
371
         * @return      string
372
         * @callback    add_filter() gettext
373
         */ 
374
        public function _replyToReplaceThickBoxText( $sTranslated, $sText ) {
375
376
            // Replace the button label in the media thick box.
377
            if ( ! in_array( $this->getPageNow(), array( 'media-upload.php', 'async-upload.php' ) ) ) { 
378
                return $sTranslated; 
379
            }
380
            if ( $sText !== 'Insert into Post' ) { 
381
                return $sTranslated; 
382
            }
383
            if ( $this->getQueryValueInURLByKey( wp_get_referer(), 'referrer' ) !== 'admin_page_framework' ) { 
384
                return $sTranslated; 
385
            }
386
            
387
            if ( isset( $_GET[ 'button_label' ] ) ) {   // sanitization unnecessary
388
                return $this->getHTTPQueryGET( 'button_label', '' );
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->getHTTPQueryGET('button_label', '') also could return the type array which is incompatible with the documented return type string.
Loading history...
389
            }
390
391
            return $this->oMsg->get( 'use_this_image' );
392
            // @deprecated 3.8.32 Accessing an unreferenced property
393
            // return $this->oProp->sThickBoxButtonUseThis
394
            //     ? $this->oProp->sThickBoxButtonUseThis
395
            //     : $this->oMsg->get( 'use_this_image' );
396
            
397
        }
398
        /**
399
         * Removes the From URL tab from the media uploader.
400
         * 
401
         * @internal
402
         * @since       2.1.3
403
         * @since       2.1.5        Moved from AdminPageFramework_Setting. Changed the name from removeMediaLibraryTab() to _replyToRemovingMediaLibraryTab().
404
         * @callback    add_filter() media_upload_tabs
405
         * @param       array        $aTabs
406
         * @return      array
407
         */
408
        public function _replyToRemovingMediaLibraryTab( $aTabs ) {
409
            
410
            if ( ! isset( $_REQUEST[ 'enable_external_source' ] ) ) {    // sanitization unnecessary
411
                return $aTabs; 
412
            }
413
            if ( ! ( boolean ) $_REQUEST[ 'enable_external_source' ] ) { // sanitization unnecessary
414
                unset( $aTabs[ 'type_url' ] ); // removes the 'From URL' tab in the thick box.
415
            }
416
            return $aTabs;
417
            
418
        }
419
420
    /**
421
     * Generates HTML attributes of label containers.
422
     *
423
     * This is used for element that `label_min_width` is applied.
424
     *
425
     * @param  array         $aField
426
     * @param  array|string $asClassAttributes
427
     * @param  array        $aAttributes
428
     * @return string
429
     * @since  3.8.0
430
     */
431
    protected function getLabelContainerAttributes( $aField, $asClassAttributes, array $aAttributes=array() ) {
432
433
        $aAttributes[ 'class' ] = $this->getClassAttribute( $asClassAttributes, $this->getElement( $aAttributes, 'class' ) );
434
        $aAttributes[ 'style' ] = $this->getStyleAttribute(
435
            array(
436
                'min-width' => $aField[ 'label_min_width' ] || '0' === ( string ) $aField[ 'label_min_width' ]
437
                    ? $this->getLengthSanitized( $aField[ 'label_min_width' ] ) 
438
                    : null,
439
            ),
440
            $this->getElement( $aAttributes, 'style' )
441
        );
442
        return $this->getAttributes( $aAttributes );
443
444
    }
445
        
446
}