Completed
Branch dev (87c2e5)
by
unknown
03:52
created

AdminPageFramework_Form_Utility::getInputsUnset()   A

Complexity

Conditions 5
Paths 6

Size

Total Lines 32

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
nc 6
nop 3
dl 0
loc 32
rs 9.0968
c 0
b 0
f 0
1
<?php
2
/**
3
 * Admin Page Framework
4
 * 
5
 * http://admin-page-framework.michaeluno.jp/
6
 * Copyright (c) 2013-2018, Michael Uno; Licensed MIT
7
 * 
8
 */
9
10
/**
11
 * Provides shared methods for the form classes.
12
 * 
13
 * @package     AdminPageFramework/Common/Form/Utility
14
 * @since       3.7.0
15
 * @extends     AdminPageFramework_FrameworkUtility
16
 * @internal
17
 */
18
abstract class AdminPageFramework_Form_Utility extends AdminPageFramework_FrameworkUtility {
19
20
    /**
21
     * Removes form input elements whose 'save' argument is false.
22
     *
23
     * The inputs array structure looks like the following.
24
     * ```
25
     *     [example_section] => Array
26
     *       (
27
     *           [example_text] => (string, length: 5) hello
28
     *           [__submit] => (string, length: 6) Submit
29
     *       )
30
     * ```
31
     * The unset keys stored in $_POST looks like the following. The pipe (|) character is used to delimit dimensional elements.
32
     * ```
33
     *   [example_section|example_text] => (string, length: 28) example_section|example_text
34
     *   [example_section|__submit] => (string, length: 24) example_section|__submit
35
     * ```
36
     *
37
     * @return      array
38
     * @since       3.8.17
39
     * @param       array       $aInputs        The inputs array to parse.
40
     * @param       string      $sFieldsType    The subject fields type (factory structure type).
41
     * @param       integer     $iSkipDepth     The dimensional depth to skip.
42
     * Depending on the fields type (structure type), dimensional keys are prepended.
43
     * For the `admin_page` fields type, an option key is prepended.
44
     * For `page_meta_box`, no prepended element and it starts with the section or field ID.
45
     */
46
    static public function getInputsUnset( array $aInputs, $sFieldsType, $iSkipDepth=0 ) {
0 ignored issues
show
Coding Style introduced by
getInputsUnset uses the super-global variable $_POST 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...
47
48
        $_sUnsetKey = '__unset_' . $sFieldsType;
49
        if ( ! isset( $_POST[ $_sUnsetKey ] ) ) {
50
            return $aInputs;
51
        }
52
53
        $_aUnsetElements = array_unique( $_POST[ $_sUnsetKey ] );
54
        foreach( $_aUnsetElements as $_sFlatInputName ) {
55
56
            $_aDimensionalKeys = explode( '|', $_sFlatInputName );
57
58
            // For form sections, a dummy key is set
59
            if ( '__dummy_option_key' === $_aDimensionalKeys[ 0 ] ) {
60
                 array_shift( $_aDimensionalKeys );
61
            }
62
63
            // The first element is the option key for the `admin_page` field type and section or field dimensional keys follow.
64
            for ( $_i = 0; $_i < $iSkipDepth; $_i++) {
65
                unset( $_aDimensionalKeys[ $_i ] );
66
            }
67
68
            self::unsetDimensionalArrayElement(
69
                $aInputs,
70
                $_aDimensionalKeys
71
            );
72
73
        }
74
75
        return $aInputs;
76
77
    }
78
79
80
    /**
81
     * @since       3.7.0
82
     * @return      array
83
     */
84
    static public function getElementPathAsArray( $asPath ) {
85
        if ( is_array( $asPath ) ) {
86
            return;
87
        }
88
        return explode( '|', $asPath );
89
    }
90
    
91
    /**
92
     * @since       3.7.0
93
     * @return      string      The section path. e.g. my_section|nested_section
94
     */
95
    static public function getFormElementPath( $asID ) {
96
        return implode( 
97
            '|', 
98
            self::getAsArray( $asID ) 
99
        );        
100
    }
101
  
102
    /**
103
     * Sanitizes a given section or field id.
104
     * @return      array|string
105
     * @since       3.7.0
106
     */
107
    static public function getIDSanitized( $asID ) {
108
        return is_scalar( $asID )
109
            ? self::sanitizeSlug( $asID )
110
            : self::getAsArray( $asID );
111
            
112
    }
113
    
114
    /**
115
     * Checks whether the given field-set definition has nested field items.
116
     * @since       3.8.0
117
     * @return      boolean
118
     */
119
    static public function hasNestedFields( $aFieldset ) {
120
        
121
        if ( ! self::hasFieldDefinitionsInContent( $aFieldset ) ) {
122
            return false;
123
        }
124
        // At this point, the `content` argument contains either the definition of nested fields or inline-mixed fields.
125
        
126
        // If it is the `inline_mixed` field type, yield false.
127
        if ( 'inline_mixed' === self::getElement( $aFieldset, 'type' ) ) {
128
            return false;
129
        }
130
        
131
        // If the first element is a string, it is a inline mixed field definition.
132
       return is_array( self::getElement( $aFieldset[ 'content' ], 0 ) );
133
       
134
    }  
135
136
    /**
137
     * Checks whether the given field-set definition has field-set definitions in the `content` argument.
138
     * @since       3.8.0
139
     * @return      boolean
140
     */
141
    static public function hasFieldDefinitionsInContent( $aFieldset ) {
142
        
143
        if ( ! isset( $aFieldset[ 'content' ] ) ) {
144
            return false;
145
        }
146
        if ( empty( $aFieldset[ 'content' ] ) ) {
147
            return false;
148
        }
149
        return is_array( $aFieldset[ 'content' ] );            
150
        
151
    }
152
    
153
    /**
154
     * Checks whether the given field has a sub-field.
155
     * @since       3.8.0
156
     * @param       array       $aFields        An array holding sub-fields.
157
     * @param       array       $aField         A field definition array. 
158
     * @return      boolean
159
     */
160
    static public function hasSubFields( array $aFields, $aField ) {
161
        
162
        if ( count( $aFields ) > 1 ) {
163
            return true;
164
        }
165
        if ( self::isDynamicField( $aField ) ) {
166
            return true;
167
        }
168
        return false;
169
        
170
    }
171
172
    /**
173
     * Checks whether the given field is dynamic.
174
     * @return      boolean
175
     * @since       3.8.13
176
     */
177
    static public function isDynamicField( $aField ) {
178
        if ( ! empty( $aField[ 'repeatable' ] ) ) {
179
            return true;
180
        }
181
        if ( ! empty( $aField[ 'sortable' ] ) ) {
182
            return true;
183
        }
184
        return false;
185
    }
186
    
187
    /**
188
     * Checks whether the parent field is repeatable or sortable.
189
     * 
190
     * @since       3.8.0
191
     * @return      boolean
192
     * @deprecated  3.8.0
193
     */
194
    // static public function isParentFieldDynamic( $aFieldset ) {
195
// return false;        
196
    // }
197
198
    /**
199
     * Adds a trailing pipe (|) character to the given string value.
200
     *
201
     * Used to construct a field path.
202
     *
203
     * @return      string
204
     * @since       3.8.0
205
     */
206
    static public function getTrailingPipeCharacterAppended( $sString ) {
207
        if ( empty( $sString ) ) {
208
            return $sString;
209
        }
210
        return $sString . '|';
211
    }
212
213
    /**
214
     * Re-formats the field-set definition with the passed sub-field index. The field path and other internal keys need to be updated to insert a sub-field index.
215
     *
216
     * It is assumed that the passed field-set definition array is already formatted as this is for sub-fields of nested field-sets.
217
     *
218
     * This is used for nested and inline-mixed field types.
219
     *
220
     * @internal
221
     * @since       3.8.0
222
     * @return      array
223
     */
224
    static public function getFieldsetReformattedBySubFieldIndex( $aFieldset, $iSubFieldIndex, $bHasSubFields, $aParentFieldset ) {
225
226
        $_oCallerForm   = $aFieldset[ '_caller_object' ];
227
228
        // Add sub-field index to the parent field path for repeated nested items.
229
        $aFieldset[ '_parent_field_path' ]   = self::getAOrB(
230
            $bHasSubFields,
231
            $aFieldset[ '_parent_field_path' ] . '|' . $iSubFieldIndex,
232
            $aFieldset[ '_parent_field_path' ]
233
        );
234
        $aFieldset[ '_parent_tag_id' ]       = self::getAOrB(
235
            $bHasSubFields,
236
            $aParentFieldset[ 'tag_id' ] . '__' . $iSubFieldIndex,
237
            $aParentFieldset[ 'tag_id' ]
238
        );
239
240
        // Re-format the field-set definition array to re-construct field path and relevant attribute IDs and names.
241
        $_oFieldsetFormatter = new AdminPageFramework_Form_Model___Format_Fieldset(
242
            $aFieldset,
243
            $aFieldset[ '_structure_type' ],
244
            $aFieldset[ 'capability' ],
245
            ( integer ) $iSubFieldIndex + 1,   // 1-based count (not index)
246
            $aFieldset[ '_subsection_index' ],
247
            $aFieldset[ '_is_section_repeatable' ],
248
            $aFieldset[ '_caller_object' ]
249
        );
250
        $aFieldset = $_oFieldsetFormatter->get();
251
252
        $_oFieldsetOutputFormatter = new AdminPageFramework_Form_Model___Format_FieldsetOutput(
253
            $aFieldset,
254
            $aFieldset[ '_section_index' ],    // `_section_index` is defined in the ...FieldsetOutput class. Since this is a nested item, it should be already set.
255
            $_oCallerForm->aFieldTypeDefinitions
256
        );
257
        return $_oFieldsetOutputFormatter->get();
258
259
    }
260
261
    /**
262
     * Checks whether the field placement is normal.
263
     *
264
     * @since       3.8.0
265
     * @internal
266
     * @return      boolean
267
     */
268
    static public function isNormalPlacement( array $aFieldset ) {
269
270
        if ( 'section_title' === $aFieldset[ 'type' ] ) {
271
            return false;
272
        }
273
        return 'normal' === $aFieldset[ 'placement' ];
274
275
    }
276
277
    /**
278
     * Generates an HTML element for the WordPress modal window to display user-defined message
279
     * for disabled repeatable elements including repeatable sections and fields.
280
     *
281
     * @since   3.8.13
282
     * @param   string  $sBoxElementID
283
     * @param   array   $aArguments         The `disabled` argument of a repeatable field/section.
284
     * @return  string  A generated container element for the modal window.
285
     */
286
    static public function getModalForDisabledRepeatableElement( $sBoxElementID, $aArguments ) {
287
288
        if ( empty( $aArguments ) ) {
289
            return '';
290
        }
291
        if ( self::hasBeenCalled( 'disabled_repeatable_elements_modal_' . $sBoxElementID ) ) {
292
            return '';
293
        }
294
        add_thickbox(); // to display a message to the user.
295
        return "<div id='{$sBoxElementID}' style='display:none'>"
296
                . "<p>" . $aArguments[ 'message' ] . "</p>"
297
            . "</div>";
298
299
    }
300
    
301
}
302