AdminPageFrameworkLoader_AdminPage_Tool_Compiler_CustomFieldTypes   A
last analyzed

Complexity

Total Complexity 30

Size/Duplication

Total Lines 457
Duplicated Lines 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
wmc 30
eloc 208
dl 0
loc 457
rs 10
c 2
b 0
f 0

15 Methods

Rating   Name   Duplication   Size   Complexity  
A ___getModifiedFileContents() 0 39 2
A ___getClassListOfCustomFieldTypes() 0 19 2
A ___getClassPrefixRegexReplacements() 0 14 1
A ___getModifiedIncludeList() 0 5 1
A ___getClassNamesPrefixed() 0 10 1
A ___getClassPrefixRegexPatterns() 0 7 2
A __construct() 0 41 1
B ___setProperties() 0 77 2
A replyToModifyFileContents() 0 27 5
A ___getClassNameIfSelected() 0 9 3
A ___replyToSetPrefix() 0 2 1
A ___getCheckedCustomFieldTypeKeys() 0 12 1
A replyToGetAdditionalHeaderComment() 0 9 4
A ___getSelectedCustomFieldTypes() 0 17 2
A replyToSetAdditionalDirectoriesForGenerator() 0 9 2
1
<?php
2
/**
3
 * Admin Page Framework Loader
4
 *
5
 * http://admin-page-framework.michaeluno.jp/
6
 * Copyright (c) 2013-2022, Michael Uno; Licensed GPLv2
7
 */
8
9
/**
10
 * Adds the 'custom_field_types' field to the 'Compiler' section.
11
 *
12
 * @since 3.6.0
13
 */
14
class AdminPageFrameworkLoader_AdminPage_Tool_Compiler_CustomFieldTypes {
15
16
    /**
17
     * Stores the admin page factory object.
18
     * @var AdminPageFramework
19
     */
20
    public $oFactory;
21
22
    /**
23
     * @var string
24
     */
25
    public $sSectionID = '';
26
27
    /**
28
     * @var array
29
     * ### Structure
30
     * ```
31
     * array(
32
     *     'class_name'           => '',   // the source class name to be prefixed with the user specified one.
33
     *     'directory_path'       => '',
34
     *     'label'                => '',
35
     *     'description'          => '',
36
     *     'archive_file_path'    => '',
37
     *     'archive_dir_path'     => '',
38
     *     'text_domain'          => '',   // the source text domain to be converted to the user specified one.
39
     * )
40
     * ```
41
     */
42
    public $aCustomFieldTypes = array();
43
44
    public $aCustomFieldTypeLabels = array();
45
46
    /**
47
     * Sets up hooks and properties.
48
     */
49
    public function __construct( $oFactory, $sSectionID ) {
50
51
        // Properties
52
        $this->oFactory   = $oFactory;
53
        $this->sSectionID = $sSectionID;
54
        $this->___setProperties();
55
56
        // Form fields - the field type pack extension also uses this field.
57
        $oFactory->addSettingFields(
58
            $sSectionID, // the target section id
59
            array(
60
                'field_id'              => 'custom_field_types',
61
                'title'                 => __( 'Custom Field Types', 'admin-page-framework-loader' ),
62
                'type'                  => 'checkbox',
63
                'order'                 => 13,
64
                'label'                 => $this->aCustomFieldTypeLabels,
65
                'label_min_width'       => '100%',
66
                'select_all_button'     => true,
67
                'select_none_button'    => true,
68
            )
69
        );
70
71
        // Hooks
72
        /// Register custom field files to the Generator of the framework loader.
73
        add_filter(
74
            'admin_page_framework_loader_filter_generator_additional_source_directories',
75
            array( $this, 'replyToSetAdditionalDirectoriesForGenerator' )
76
        );
77
78
        /// Register a callback to modify archive files.
79
        add_filter(
80
            'admin_page_framework_loader_filter_generator_file_contents',
81
            array( $this, 'replyToModifyFileContents' ),
82
            10,
83
            4
84
        );
85
86
        /// [3.9.0] Insert checked custom field types in the file comment header
87
        add_filter(
88
            AdminPageFrameworkLoader_Registry::HOOK_SLUG . '_filter_generator_header_comment',
89
            array( $this, 'replyToGetAdditionalHeaderComment' )
90
        );
91
92
    }
93
        /**
94
         * Sets up properties.
95
         * @since 3.6.0
96
         */
97
        private function ___setProperties() {
98
99
            $this->aCustomFieldTypes = array(
100
                'AceCustomFieldType'   =>  array(
101
                    'class_name'           => 'AceCustomFieldType',
102
                    'label'                => __( 'ACE', 'admin-page-framework-loader' ),
103
                    'description'          => __( 'provides code syntax highlighting in a text area field.', 'admin-page-framework-loader' ),
104
                    'directory_path'       => AdminPageFrameworkLoader_Registry::$sDirPath . '/example/library/ace-custom-field-type',
105
                    'archive_file_path'    => 'custom-field-types/ace-custom-field-type/AceCustomFieldType.php',
106
                    'archive_dir_path'     => 'custom-field-types/ace-custom-field-type',
107
                    'text_domain'          => 'admin-page-framework',
108
                ),
109
                'GitHubCustomFieldType'   =>  array(
110
                    'class_name'           => 'GitHubCustomFieldType',
111
                    'label'                => __( 'GitHub Buttons', 'admin-page-framework-loader' ),
112
                    'description'          => __( 'allows you to display GitHub buttons in a field.', 'admin-page-framework-loader' ),
113
                    'directory_path'       => AdminPageFrameworkLoader_Registry::$sDirPath . '/include/library/github-custom-field-type',
114
                    'archive_file_path'    => 'custom-field-types/github-custom-field-type/GitHubCustomFieldType.php',
115
                    'archive_dir_path'     => 'custom-field-types/github-custom-field-type',
116
                    'text_domain'          => 'admin-page-framework',
117
                ),
118
                'PathCustomFieldType'   =>  array(
119
                    'class_name'           => 'PathCustomFieldType',
120
                    'label'                => __( 'Path', 'admin-page-framework-loader' ),
121
                    'description'          => __( 'allows the user to select a file path on the server.', 'admin-page-framework-loader' ),
122
                    'directory_path'       => AdminPageFrameworkLoader_Registry::$sDirPath . '/example/library/path-custom-field-type',
123
                    'archive_file_path'    => 'custom-field-types/path-custom-field-type/PathCustomFieldType.php',
124
                    'archive_dir_path'     => 'custom-field-types/path-custom-field-type',
125
                    'text_domain'          => 'admin-page-framework',
126
                ),
127
                'ToggleCustomFieldType'   =>  array(
128
                    'class_name'           => 'ToggleCustomFieldType',
129
                    'label'                => __( 'Toggle', 'admin-page-framework-loader' ),
130
                    'description'          => __( 'allows the user to switch a button.', 'admin-page-framework-loader' ),
131
                    'directory_path'       => AdminPageFrameworkLoader_Registry::$sDirPath . '/example/library/toggle-custom-field-type',
132
                    'archive_file_path'    => 'custom-field-types/toggle-custom-field-type/ToggleCustomFieldType.php',
133
                    'archive_dir_path'     => 'custom-field-types/toggle-custom-field-type',
134
                    'text_domain'          => 'admin-page-framework',
135
                ),
136
                'NoUISliderCustomFieldType'   =>  array(
137
                    'class_name'           => 'NoUISliderCustomFieldType',
138
                    'label'                => __( 'NoUISlider (Range Slider)', 'admin-page-framework-loader' ),
139
                    'description'          => __( 'allows the user to set values in ranges.', 'admin-page-framework-loader' ),
140
                    'directory_path'       => AdminPageFrameworkLoader_Registry::$sDirPath . '/example/library/nouislider-custom-field-type',
141
                    'archive_file_path'    => 'custom-field-types/nouislider-custom-field-type/NoUISliderCustomFieldType.php',
142
                    'archive_dir_path'     => 'custom-field-types/nouislider-custom-field-type',
143
                    'text_domain'          => 'admin-page-framework',
144
                ),
145
                'Select2CustomFieldType'   =>  array(
146
                    'class_name'           => 'Select2CustomFieldType',
147
                    'label'                => __( 'Select2', 'admin-page-framework-loader' ),
148
                    'description'          => __( 'allows the user to select items with autocomplete from a list which can be populated with AJAX.', 'admin-page-framework-loader' ),
149
                    'directory_path'       => AdminPageFrameworkLoader_Registry::$sDirPath . '/example/library/select2-custom-field-type',
150
                    'archive_file_path'    => 'custom-field-types/select2-custom-field-type/Select2CustomFieldType.php',
151
                    'archive_dir_path'     => 'custom-field-types/select2-custom-field-type',
152
                    'text_domain'          => 'admin-page-framework',
153
                ),
154
                'PostTypeTaxonomyCustomFieldType'   =>  array(
155
                    'class_name'           => 'PostTypeTaxonomyCustomFieldType',
156
                    'label'                => __( 'Post Type Taxonomy', 'admin-page-framework-loader' ),
157
                    'description'          => __( 'allows the user to select taxonomy terms of selected post types.', 'admin-page-framework-loader' ),
158
                    'directory_path'       => AdminPageFrameworkLoader_Registry::$sDirPath . '/example/library/post_type_taxonomy_field-type',
159
                    'archive_file_path'    => 'custom-field-types/post_type_taxonomy_field-type/PostTypeTaxonomyCustomFieldType.php',
160
                    'archive_dir_path'     => 'custom-field-types/post_type_taxonomy_field-type',
161
                    'text_domain'          => 'admin-page-framework',
162
                ),
163
            );
164
165
            // Let third-party scripts add custom field types.
166
            $this->aCustomFieldTypes = apply_filters(
167
                AdminPageFrameworkLoader_Registry::HOOK_SLUG . '_filter_generator_custom_field_types',
168
                $this->aCustomFieldTypes
169
            );
170
171
            foreach( $this->aCustomFieldTypes as $_sKey => $_aCustomFieldType ) {
172
                $this->aCustomFieldTypeLabels[ $_sKey ] = $_aCustomFieldType[ 'label' ]
173
                    . ' - <span class="description">' . $_aCustomFieldType[ 'description' ] . '</span>';
174
            }
175
176
        }
177
178
            /**
179
             * Modifies the file contents.
180
             *
181
             * @since    3.6.0
182
             * @return   string
183
             * @callback add_filter() admin_page_framework_loader_filter_generator_file_contents
184
             */
185
            public function replyToModifyFileContents( $sFileContents, $sPathInArchive, $aFormData, $oFactory ) {
0 ignored issues
show
Unused Code introduced by
The parameter $oFactory 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

185
            public function replyToModifyFileContents( $sFileContents, $sPathInArchive, $aFormData, /** @scrutinizer ignore-unused */ $oFactory ) {

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...
Unused Code introduced by
The parameter $aFormData 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

185
            public function replyToModifyFileContents( $sFileContents, $sPathInArchive, /** @scrutinizer ignore-unused */ $aFormData, $oFactory ) {

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...
186
187
                // Check the file extension.
188
                $_aAllowedExtensions = apply_filters(
189
                    AdminPageFrameworkLoader_Registry::HOOK_SLUG . '_filter_generator_allowed_file_extensions',
190
                    array( 'php', 'css', 'js' )
191
                );
192
                if ( ! in_array( pathinfo( $sPathInArchive, PATHINFO_EXTENSION ), $_aAllowedExtensions, true ) ) {
193
                    return $sFileContents;
194
                }
195
196
                // Skip the framework bootstrap file.
197
                if ( $this->oFactory->oUtil->hasSuffix( 'admin-page-framework.php', $sPathInArchive ) ) {
198
                    return $sFileContents;
199
                }
200
201
                // The inclusion class list file needs to be handled differently.
202
                if ( $this->oFactory->oUtil->hasSuffix( 'admin-page-framework-class-map.php', $sPathInArchive ) ) {
203
                    return $this->___getModifiedIncludeList( $sFileContents );
204
                }
205
206
                $_bsParsingClassName = $this->___getClassNameIfSelected( $sPathInArchive );
207
                if ( $_bsParsingClassName ) {
208
                    return $this->___getModifiedFileContents( $sFileContents, $sPathInArchive, $_bsParsingClassName );
209
                }
210
211
                return $sFileContents;
212
213
            }
214
                /**
215
                 * Modifies the class include list.
216
                 * @since  3.6.0
217
                 * @return string
218
                 */
219
                private function ___getModifiedIncludeList( $sFileContents ) {
220
                    return str_replace(
221
                        ');', // search
222
                        $this->___getClassListOfCustomFieldTypes() . ');', // replace - @todo insert the selected class list here
223
                        $sFileContents // subject
224
                    );
225
                }
226
                    /**
227
                     * @since  3.6.0
228
                     * @return string
229
                     */
230
                    private function ___getClassListOfCustomFieldTypes() {
231
232
                        $_aCheckedCustomFieldTypes = $this->___getSelectedCustomFieldTypes( $this->aCustomFieldTypes );
233
                        $_sClassPrefix             = sanitize_text_field( $this->oFactory->oUtil->getElement(
234
                            $_POST,
235
                            array(
236
                                $this->oFactory->oProp->sOptionKey,
237
                                'compiler',    // section id
238
                                'class_prefix'  // field id
239
                            ),
240
                            ''
241
                        ) );
242
                        $_aOutput = array();
243
                        foreach( $_aCheckedCustomFieldTypes as $_sClassName => $_aCustomFieldType ) {
244
                            $_aOutput[] = '    "' . $_sClassPrefix . $_sClassName . '"'
245
                                . ' => '
246
                                . 'AdminPageFramework_Registry::$sDirPath . ' . '"/' . ltrim( $_aCustomFieldType[ 'archive_file_path' ], '/' ) . '",';
247
                        }
248
                        return implode( PHP_EOL, $_aOutput ) . PHP_EOL;
249
250
                    }
251
252
                /**
253
                 * Retrieves the custom field type class name from the given archive path.
254
                 *
255
                 * Checks if the user select the field type in the Generator form.
256
                 *
257
                 * @since  3.6.0
258
                 * @since  3.9.0       Changed the return value from `false` to an empty string if not found.
259
                 * @return string      The found class name. An empty string if not found.
260
                 */
261
                private function ___getClassNameIfSelected( $sPathInArchive ) {
262
                    $_aSelectedCustomFieldTypes = $this->___getSelectedCustomFieldTypes( $this->aCustomFieldTypes );
263
                    foreach( $_aSelectedCustomFieldTypes as $_sClassName => $_aCustomFieldType ) {
264
                        $_sThisArchiveDirPath = $this->oFactory->oUtil->getElement( $_aCustomFieldType, 'archive_dir_path' );
265
                        if ( false !== strpos( $sPathInArchive, $_sThisArchiveDirPath ) ) {
266
                            return $_sClassName;
267
                        }
268
                    }
269
                    return '';
270
                }
271
272
                /**
273
                 * Modify the file contents of the given path.
274
                 *
275
                 * Converts the class name by adding the user-set class name prefix.
276
                 * Also, the text domain used in the custom field type will be converted.
277
                 *
278
                 * @remark The reason why it retrieves all the selected custom field type classes, not the parsing item is
279
                 * because some custom field types extend another custom field type. In that case, a name is used among multiple files.
280
                 * @since  3.6.0
281
                 * @since  3.7.2  Added the `$sParsingClassName` argument.
282
                 * @return string
283
                 */
284
                private function ___getModifiedFileContents( $sFileContents, $sPathInArchive, $sParsingClassName ) {
285
286
                    // 3.8.4+ Some custom field types names conflict each other such as `TuneCustomFieldType` and `DateTimeCustomFieldType` so they must be dealt with regular expressions.
287
                    $sFileContents = $this->___getClassNamesPrefixed( $sFileContents );
288
289
                    // Searches and replaces for `str_replace()`.
290
                    $_aSearches = array();
291
                    $_aReplaces = array();
292
293
                    $_sUserTextDomain = sanitize_text_field( $this->oFactory->oUtil->getElement(
294
                        $_POST,
295
                        array(
296
                            $this->oFactory->oProp->sOptionKey,
297
                            'compiler', // section id
298
                            'text_domain' // field id
299
                        ),
300
                        ''
301
                    ) );
302
303
                    // Change the text domain.
304
305
                    /// 3.7.2+ Get the custom field type text domain.
306
                    $_sFieldTypeTextDomain = $this->oFactory->oUtil->getElement(
307
                        $this->aCustomFieldTypes,
308
                        array( $sParsingClassName, 'text_domain' )
309
                    );
310
                    if ( $_sFieldTypeTextDomain ) {
311
                        $_aSearches[] = $_sFieldTypeTextDomain;
312
                        $_aReplaces[] = $_sUserTextDomain;
313
                    }
314
315
                    $_aSearches[] = 'admin-page-framework';
316
                    $_aReplaces[] = $_sUserTextDomain;
317
318
                    // Return the converted string.
319
                    return str_replace(
320
                        $_aSearches,    // search
321
                        $_aReplaces,    // replace
322
                        $sFileContents  // subject
323
                    );
324
325
                }
326
327
                    /**
328
                     * Modifies the given content by replacing the class names with a prefix.
329
                     * @since  3.8.4
330
                     * @return string
331
                     */
332
                    private function ___getClassNamesPrefixed( $sFileContents ) {
333
334
                        $_aSelectedFieldTypeClassNames = array_keys(
335
                            $this->___getSelectedCustomFieldTypes( $this->aCustomFieldTypes )
336
                        );
337
338
                        return preg_replace(
339
                            $this->___getClassPrefixRegexPatterns( $_aSelectedFieldTypeClassNames ),    // search
340
                            $this->___getClassPrefixRegexReplacements( $_aSelectedFieldTypeClassNames ),    // replace
341
                            $sFileContents  // subject
342
                        );
343
344
                    }
345
                        /**
346
                         * Returns an array holding regular expressions needle patterns for class names.
347
                         * @since       3.8.4
348
                         * @return      array
349
                         */
350
                        private function ___getClassPrefixRegexPatterns( array $aSelectedFieldTypeClassNames ) {
351
352
                            $_aPregSearches = array();
353
                            foreach( $aSelectedFieldTypeClassNames as $_sClassName ) {
354
                                $_aPregSearches[] = '/(?<=[^a-zA-Z0-9])(' . $_sClassName . ')/';
355
                            }
356
                            return $_aPregSearches;
357
358
                        }
359
                        /**
360
                         * Returns an array holding regular expressions replacements for class names.
361
                         * @since  3.8.4
362
                         * @return array
363
                         */
364
                        private function ___getClassPrefixRegexReplacements( array $aSelectedFieldTypeClassNames ) {
365
366
                            $_aPrefixedClassNames = $aSelectedFieldTypeClassNames;
367
                            $_sPrefix             = sanitize_text_field( $this->oFactory->oUtil->getElement(
368
                                $_POST,
369
                                array(
370
                                    $this->oFactory->oProp->sOptionKey,
371
                                    'compiler', // section id
372
                                    'class_prefix' // field id
373
                                ),
374
                                ''
375
                             ) );
376
                            array_walk( $_aPrefixedClassNames, array( $this, '___replyToSetPrefix' ), $_sPrefix );
377
                            return $_aPrefixedClassNames;
378
379
                        }
380
                            /**
381
                             * @since    3.6.0
382
                             * @since    3.8.4        Changed it for regular expression patterns.
383
                             * @since    3.9.0        Changed the visibility scope from `public` to `private`.
384
                             * @callback array_walk()
385
                             */
386
                            private function ___replyToSetPrefix( &$sClassName, $sKey, $sPrefix ) {
387
                                $sClassName = $sPrefix . '$0';
388
                            }
389
390
391
            /**
392
             * Inserts extra archive directories of custom field types chosen by the user.
393
             *
394
             * Structure:
395
             * Archive directory path => Source directory path
396
             * `
397
             * array(
398
             *  'custom-field-types/my-custom-field-type' =>  AdminPageFrameworkLoader_Registry::$sDirPath . '/include/library/my-custom-field-type',
399
             * )
400
             * `
401
             *
402
             * @since       3.6.0
403
             * @return      array
404
             * @callback    add_filter() admin_page_framework_loader_filter_generator_additional_source_directories
405
             */
406
            public function replyToSetAdditionalDirectoriesForGenerator( $aDirPaths ) {
407
                $_aCheckedCustomFieldTypes = $this->___getSelectedCustomFieldTypes( $this->aCustomFieldTypes );
408
                $_aDirPathInfo             = array();
409
                foreach( $_aCheckedCustomFieldTypes as $_sKey => $_aCheckedCustomFieldType ) {
410
                    $_sArchiveDirPath = $this->oFactory->oUtil->getElement( $_aCheckedCustomFieldType, 'archive_dir_path' );
411
                    $_sSourceDirPath  = $this->oFactory->oUtil->getElement( $_aCheckedCustomFieldType, 'directory_path' );
412
                    $_aDirPathInfo[ $_sArchiveDirPath ] = $_sSourceDirPath;
413
                }
414
                return $aDirPaths + $_aDirPathInfo;
415
            }
416
                /**
417
                 * @return array The array keys of the checked items.
418
                 * @since  3.6.0
419
                 */
420
                private function ___getSelectedCustomFieldTypes( array $aSubject=array() ) {
421
                    static $_aCheckedCustomFieldTypes;  // cache
422
                    if ( ! isset( $_aCheckedCustomFieldTypes ) ) {
423
                        $_aCheckedCustomFieldTypes = $this->oFactory->oUtil->getElementAsArray(
424
                            $_POST,
425
                            array(
426
                                $this->oFactory->oProp->sOptionKey,
427
                                'compiler', // section id
428
                                'custom_field_types' // field id
429
                            ),
430
                            array()
431
                        );
432
                        $_aCheckedCustomFieldTypes = $this->oFactory->oUtil->getArrayMappedRecursive( 'sanitize_text_field', $_aCheckedCustomFieldTypes );
433
                    }
434
                    return array_intersect_key(
435
                        $aSubject,
436
                        array_filter( $_aCheckedCustomFieldTypes ) // drop 0 values
437
                    );
438
                }
439
440
    /**
441
     * @param  string $sComment
442
     * @return string
443
     * @since  3.9.0
444
     */
445
    public function replyToGetAdditionalHeaderComment( $sComment ) {
446
        $_aCustomFieldTypeLabels = array();
447
        foreach( $this->___getCheckedCustomFieldTypeKeys() as $_sCheckedKey ) {
448
            $_sThisLabel = $this->oFactory->oUtil->getElement( $this->aCustomFieldTypes, array( $_sCheckedKey, 'label' ) );
449
            $_aCustomFieldTypeLabels[] = strlen( $_sThisLabel ) ? $_sThisLabel : $_sCheckedKey;
450
        }
451
        return empty( $_aCustomFieldTypeLabels )
452
            ? $sComment
453
            : $sComment . PHP_EOL . ' * Custom Field Types: ' . implode( ', ', $_aCustomFieldTypeLabels );
454
    }
455
        /**
456
         * @return string[]
457
         * @since  3.9.0
458
         */
459
        private function ___getCheckedCustomFieldTypeKeys() {
460
            $_aChecked = $this->oFactory->oUtil->getElementAsArray(
461
                $_POST,
462
                array(
463
                    $this->oFactory->oProp->sOptionKey,
464
                    $this->sSectionID,
465
                    'custom_field_types' // field id
466
                ),
467
                array()
468
            );
469
            $_aChecked = array_filter( $_aChecked );
470
            return array_keys( $_aChecked );
471
        }
472
}