Passed
Branch dev (3fd540)
by Michael
22:28
created

AdminPageFramework_Factory_Router   B

Complexity

Total Complexity 49

Size/Duplication

Total Lines 547
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 49
eloc 142
dl 0
loc 547
rs 8.48
c 0
b 0
f 0

29 Methods

Rating   Name   Duplication   Size   Complexity  
A setFooterInfoLeft() 0 1 1
A _replyTpSetAndGetInstance_oForm() 0 3 1
A __toString() 0 2 1
A _getFormObject() 0 8 1
A _getPageLoadObject() 0 2 1
A _replyTpSetAndGetInstance_oDebug() 0 4 1
A _isWordPressCoreAjaxRequest() 0 11 4
A _replyTpSetAndGetInstance_oPageLoadInfo() 0 3 1
A _getAutoCallback() 0 16 3
A _replyTpSetAndGetInstance_oLink() 0 3 1
A __call() 0 17 4
A __get() 0 6 2
A setFooterInfoRight() 0 1 1
A ___getSubClassNames() 0 5 2
A _triggerUndefinedMethodWarning() 0 8 1
A _isInstantiatable() 0 5 2
A _load() 0 8 2
A _isValidAjaxReferrer() 0 5 2
A _setUp() 0 6 1
A _replyTpSetAndGetInstance_oMsg() 0 6 1
A _replyTpSetAndGetInstance_oResource() 0 7 2
A _replyTpSetAndGetInstance_oUtil() 0 4 1
A __construct() 0 27 2
A _getLinkObject() 0 2 1
A _replyToDetermineToLoad() 0 7 2
A _isInThePage() 0 2 1
A _replyToLoadComponents() 0 16 5
A _replyTpSetAndGetInstance_oHelpPane() 0 4 1
A _replyTpSetAndGetInstance_oHeadTag() 0 3 1

How to fix   Complexity   

Complex Class

Complex classes like AdminPageFramework_Factory_Router 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_Factory_Router, 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-2021, Michael Uno; Licensed MIT
7
 *
8
 */
9
10
/**
11
 * Provides routing functionality to the Admin Page Framework factory object based on the fields type.
12
 *
13
 * This class mainly deals with routing function calls and instantiation of objects based on the type.
14
 *
15
 * @abstract
16
 * @since       3.0.4
17
 * @package     AdminPageFramework/Common/Factory
18
 * @internal
19
 */
20
abstract class AdminPageFramework_Factory_Router {
21
22
    /**
23
     * Stores the property object.
24
     *
25
     * @since       2.0.0
26
     * @access      public      The AdminPageFramework_Page_MetaBox class accesses it.
27
     * @var AdminPageFramework_Property_Base
28
     */
29
    public $oProp;
30
31
    /**
32
     * The object that provides the debug methods.
33
     *
34
     * @internal
35
     * @access      public
36
     * @since       2.0.0
37
     * @since       3.1.0   Changed the scope to public from protected.
38
     * @var AdminPageFramework_Debug
39
     */
40
    public $oDebug;
41
    /**
42
     * Provides the utility methods.
43
     *
44
     * @internal
45
     * @since       2.0.0
46
     * @since       3.1.0     Changed the scope to public from protected.
47
     * @var         AdminPageFramework_FrameworkUtility
48
     */
49
    public $oUtil;
50
    /**
51
     * Provides the methods for text messages of the framework.
52
     *
53
     * @since       2.0.0
54
     * @since       3.1.0     Changed the scope to public from protected.
55
     * @access      public
56
     * @internal
57
     * @var         AdminPageFramework_Message
58
     */
59
    public $oMsg;
60
61
    /**
62
     * The form object that provides methods to handle form sections and fields.
63
     * @internal
64
     * @since       3.0.0
65
     * @since       3.5.2       Changed the scope to public from protected as the widget class needs to initialize this object.
66
     * @var         AdminPageFramework_Form
67
     */
68
    public $oForm;
69
70
    /**
71
     * Inserts page load information into the footer area of the page.
72
     * @var         AdminPageFramework_PageLoadInfo_Base
73
     */
74
    protected $oPageLoadInfo;
75
76
    /**
77
     * Provides the methods to insert head tag elements.
78
     *
79
     * @since   3.3.0   Changed the name from $oHeadTag as it has become to deal with footer elements.
80
     * @var     AdminPageFramework_Resource_Base
81
     */
82
    protected $oResource;
83
84
    /**
85
     * Provides the methods to insert head tag elements.
86
     * @deprecated
87
     */
88
    protected $oHeadTag;
89
90
    /**
91
     * Provides methods to manipulate contextual help pane.
92
     * @var AdminPageFramework_HelpPane_Base
93
     */
94
    protected $oHelpPane;
95
96
    /**
97
     * Provides the methods for creating HTML link elements.
98
     * @var AdminPageFramework_Link_Base
99
     */
100
    protected $oLink;
101
102
    /**
103
     * Stores sub-class names.
104
     *
105
     * Used in the __get() method to check whether a method with the name of the property should be called or not.
106
     *
107
     * @since       3.7.12      Renamed from `_aSubClassNames`.
108
     * @internal
109
     * @remark      `$oProp` is not listed as it is created prior to calling the constructor of this class.
110
     */
111
    protected $_aSubClassPrefixes = array(
112
        'oForm'             => 'AdminPageFramework_Form_',
113
        'oPageLoadInfo'     => 'AdminPageFramework_PageLoadInfo_',
114
        'oResource'         => 'AdminPageFramework_Resource_',
115
        'oHelpPane'         => 'AdminPageFramework_HelpPane_',
116
        'oLink'             => 'AdminPageFramework_Link_',
117
    );
118
119
    /**
120
     * Stores the sub-object class names.
121
     * @since       3.5.3
122
     * @since       3.7.12      Changed the scope to private.
123
     */
124
    private $_aSubClassNames = array(
125
        'oProp'             => null,
126
        'oDebug'            => 'AdminPageFramework_Debug',
127
        'oUtil'             => 'AdminPageFramework_FrameworkUtility',
128
        'oMsg'              => 'AdminPageFramework_Message',
129
        'oForm'             => null,
130
        'oPageLoadInfo'     => null,
131
        'oResource'         => null,
132
        'oHelpPane'         => null,
133
        'oLink'             => null,
134
    );
135
136
    /**
137
     * Stores user-set sub-object class names.
138
     *
139
     * This is for the user to use own classes for sub-class objects.
140
     * @since       3.7.12
141
     */
142
    public $aSubClassNames = array();
143
144
    /**
145
     * Sets up built-in objects.
146
     */
147
    public function __construct( $oProp ) {
148
149
        // Set sub-class names.
150
        $this->aSubClassNames = $this->___getSubClassNames();
151
152
        // Let them overload so that these sub-class objects will not be instantiated until they are required.
153
        unset(
154
            $this->oDebug,
155
            $this->oUtil,
156
            $this->oMsg,
157
            $this->oForm,
158
            $this->oPageLoadInfo,
159
            $this->oResource,
160
            $this->oHelpPane,
161
            $this->oLink
162
        );
163
164
        // Required sub-class objects
165
        $this->oProp = $oProp;
166
167
        if ( $this->oProp->bIsAdmin ) {
168
            $this->oUtil->registerAction( 'current_screen', array( $this, '_replyToLoadComponents' ) );
169
        }
170
171
        // Call the user constructor.
172
        $this->start();     // defined in the controller class.
0 ignored issues
show
Bug introduced by
The method start() does not exist on AdminPageFramework_Factory_Router. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

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

172
        $this->/** @scrutinizer ignore-call */ 
173
               start();     // defined in the controller class.
Loading history...
173
        $this->oUtil->addAndDoAction( $this, 'start_' . $this->oProp->sClassName, $this );
174
175
    }
176
        /**
177
         * Retrieves sub-class names for sub-objects.
178
         * @since       3.8.14
179
         * @return      array
180
         */
181
        private function ___getSubClassNames() {
182
            foreach( $this->_aSubClassPrefixes as $_sObjectVariableName => $_sPrefix ) {
183
                $this->aSubClassNames[ $_sObjectVariableName ] = $_sPrefix . $this->_sStructureType;
0 ignored issues
show
Bug Best Practice introduced by
The property _sStructureType does not exist on AdminPageFramework_Factory_Router. Since you implemented __get, consider adding a @property annotation.
Loading history...
184
            }
185
            return $this->aSubClassNames + $this->_aSubClassNames;
186
        }
187
188
    /**
189
     * Determines whether the class component classes should be instantiated or not.
190
     *
191
     * @internal
192
     * @callback    action      current_screen
193
     * @return      void
194
     */
195
    public function _replyToLoadComponents( /* $oScreen */ ) {
196
197
        if ( ! $this->_isInThePage() ) {
198
            return;
199
        }
200
201
        if ( ! isset( $this->oResource ) ) {
202
            $this->oResource = $this->_replyTpSetAndGetInstance_oResource();
203
        }
204
205
        if ( ! isset(  $this->oLink ) ) {
206
            $this->oLink = $this->_replyTpSetAndGetInstance_oLink();
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $this->oLink is correct as $this->_replyTpSetAndGetInstance_oLink() targeting AdminPageFramework_Facto...tAndGetInstance_oLink() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
207
        }
208
209
        if ( $this->oUtil->isDebugMode() ) {
210
            $this->oPageLoadInfo = $this->oPageLoadInfo;
211
        }
212
213
    }
214
215
    /**
216
     * Calls the load method and callbacks.
217
     * @since       3.8.14
218
     */
219
    protected function _load( $aActions=array() ) {
220
        $aActions = empty( $aActions )
221
            ? array(
222
                'load_' . $this->oProp->sClassName,
223
            )
224
            : $aActions;
225
        $this->load();
0 ignored issues
show
Bug introduced by
The method load() does not exist on AdminPageFramework_Factory_Router. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

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

225
        $this->/** @scrutinizer ignore-call */ 
226
               load();
Loading history...
226
        $this->oUtil->addAndDoActions( $this, $aActions, $this );
227
    }
228
229
    /**
230
     * Calls the `setUp()` method and callbacks.
231
     */
232
    protected function _setUp() {
233
        $aActions = array(
234
            'set_up_' . $this->oProp->sClassName,
235
        );
236
        $this->setUp();
0 ignored issues
show
Bug introduced by
The method setUp() does not exist on AdminPageFramework_Factory_Router. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

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

236
        $this->/** @scrutinizer ignore-call */ 
237
               setUp();
Loading history...
237
        $this->oUtil->addAndDoActions( $this, $aActions, $this );
238
    }
239
240
    /**
241
     * Determines whether the class object is instantiatable in the current page.
242
     *
243
     * This method should be redefined in the extended class.
244
     *
245
     * @since       3.1.0
246
     * @internal
247
     */
248
    protected function _isInstantiatable() {
249
        if ( $this->_isWordPressCoreAjaxRequest() ) {
250
            return false;
251
        }
252
        return true;
253
    }
254
        /**
255
         * Checks whether the page call is by WordPress core ajax requests.
256
         * @return  boolean
257
         * @remark  Not using the property or utility object as this can be called prior to instantiating those.
258
         * @since   3.8.19
259
         */
260
        protected function _isWordPressCoreAjaxRequest() {
261
            if ( ! isset( $GLOBALS[ 'pagenow' ] ) ) {
262
                return false;
263
            }
264
            if ( 'admin-ajax.php' !== $GLOBALS[ 'pagenow' ] ) {
265
                return false;
266
            }
267
            return in_array(
268
                isset( $_POST[ 'action' ] ) ? $_POST[ 'action' ] : '',  // sanitization unnecessary as just checking
269
                array( 'heartbeat', 'closed-postboxes', 'meta-box-order' ),
270
                true
271
            );
272
        }
273
274
    /**
275
     * Determines whether the instantiated object and its producing elements belong to the loading page.
276
     *
277
     * This method should be redefined in the extended class.
278
     *
279
     * @remark      This method should be called AFTER current screen is determined such as after the `current_screen` action hook.
280
     * @since       3.0.3
281
     * @since       3.2.0   Changed the visibility scope to `public` from `protected` as the head tag object will access it.
282
     * @since       3.8.14  Changed the visibility scope to `protected` from `public` as there is the `isInThePage()` public method.
283
     * @internal
284
     */
285
    protected function _isInThePage() {
286
        return true;
287
    }
288
289
    /**
290
     * Checks if the `admin-ajax.php` is called from the page that this meta box belongs to.
291
     * @remark  Extended factory types should override this method.
292
     * @sicne   3.8.19
293
     * @return  boolean
294
     */
295
    protected function _isValidAjaxReferrer() {
296
        if ( ! $this->oProp->bIsAdminAjax ) {
297
            return false;
298
        }
299
        return true;
300
    }
301
302
    /**
303
     * Determines whether the `setUp()` method should be called.
304
     *
305
     * @since       3.7.10
306
     * @callback
307
     * @internal
308
     * @return      void
309
     */
310
    public function _replyToDetermineToLoad() {
311
312
        if ( ! $this->_isInThePage() ) {
313
            return;
314
        }
315
316
        $this->_setUp();
317
318
    }
319
320
321
    /**
322
     * Instantiate a form object based on the type.
323
     *
324
     * @since       3.1.0
325
     * @internal
326
     * @return      object|null
327
     */
328
    protected function _getFormObject() {
329
330
        $this->oProp->setFormProperties();
331
        $_sFormClass = $this->aSubClassNames[ 'oForm' ];
332
        return new $_sFormClass(
333
            $this->oProp->aFormArguments, // Options - for the values that do not need to change through out the script execution.
334
            $this->oProp->aFormCallbacks, // Callbacks - for the values which change dynamically depending on conditions such as the loaded page url.
335
            $this->oMsg
336
        );
337
338
    }
339
340
    /**
341
     * Instantiates a link object based on the type.
342
     *
343
     * @since       3.0.4
344
     * @since       3.7.10      Removed the parameters as those values will be set in the extended class.
345
     * @remark      Override this method in an extended class.
346
     * @internal
347
     * @return      null|object
348
     */
349
    protected function _getLinkObject() {
350
        return null;
351
    }
352
353
    /**
354
     * Instantiates a page load object based on the type.
355
     *
356
     * @since       3.0.4
357
     * @since       3.7.10      Removed the parameters as those values will be set in the extended class.
358
     * @internal
359
     */
360
    protected function _getPageLoadObject() {
361
        return null;
362
    }
363
364
    /**
365
     * Responds to a request of an undefined property.
366
     *
367
     * This is used to instantiate classes only when necessary, rather than instantiating them all at once.
368
     *
369
     * @internal
370
     * @param       string $sPropertyName
371
     * @return      mixed
372
     */
373
    public function __get( $sPropertyName ) {
374
375
        // Set and return the sub class object instance.
376
        if ( isset( $this->aSubClassNames[ $sPropertyName ] ) ) {
377
            return call_user_func(
378
                array( $this, "_replyTpSetAndGetInstance_{$sPropertyName}"  )
379
            );
380
        }
381
382
    }
383
        /**#@+
384
         * @internal
385
         * @return      object
386
         * @callback    function    call_user_func
387
         */
388
        /**
389
         * Sets and returns the `oUtil` property.
390
         * @since       3.5.3
391
         */
392
        public function _replyTpSetAndGetInstance_oUtil() {
393
            $_sClassName = $this->aSubClassNames[ 'oUtil' ];
394
            $this->oUtil = new $_sClassName;
395
            return $this->oUtil;
396
        }
397
        /**
398
         * Sets and returns the `oDebug` property.
399
         * @since       3.5.3
400
         */
401
        public function _replyTpSetAndGetInstance_oDebug() {
402
            $_sClassName = $this->aSubClassNames[ 'oDebug' ];
403
            $this->oDebug = new $_sClassName;
404
            return $this->oDebug;
405
        }
406
        /**
407
         * Sets and returns the `oMsg` property.
408
         * @since       3.5.3
409
         */
410
        public function _replyTpSetAndGetInstance_oMsg() {
411
            $this->oMsg = call_user_func_array(
412
                array( $this->aSubClassNames[ 'oMsg' ], 'getInstance'),
413
                array( $this->oProp->sTextDomain )  // parameters
414
            );
415
            return $this->oMsg;
416
        }
417
        /**
418
         * Sets and returns the `oForm` property.
419
         * @since       3.5.3
420
         */
421
        public function _replyTpSetAndGetInstance_oForm() {
422
            $this->oForm = $this->_getFormObject();
423
            return $this->oForm;
424
        }
425
        /**
426
         * Sets and returns the `oResouce` property.
427
         * @since       3.5.3
428
         */
429
        public function _replyTpSetAndGetInstance_oResource() {
430
            if ( isset( $this->oResource ) ) {
431
                return $this->oResource;
432
            }
433
            $_sClassName     = $this->aSubClassNames[ 'oResource' ];
434
            $this->oResource = new $_sClassName( $this->oProp );
435
            return $this->oResource;
436
        }
437
            /**
438
             * Kept for backward compatibility.
439
             * @since       3.7.10
440
             */
441
            public function _replyTpSetAndGetInstance_oHeadTag() {
442
                $this->oHead = $this->_replyTpSetAndGetInstance_oResource();
0 ignored issues
show
Bug Best Practice introduced by
The property oHead does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
443
                return $this->oHead;
444
            }
445
        /**
446
         * Sets and returns the `oHelpPane` property.
447
         * @since       3.5.3
448
         */
449
        public function _replyTpSetAndGetInstance_oHelpPane() {
450
            $_sClassName     = $this->aSubClassNames[ 'oHelpPane' ];
451
            $this->oHelpPane = new $_sClassName( $this->oProp );
452
            return $this->oHelpPane;
453
        }
454
        /**
455
         * Sets and returns the `oLink` property.
456
         * @since       3.5.3
457
         */
458
        public function _replyTpSetAndGetInstance_oLink() {
459
            $this->oLink = $this->_getLinkObject();
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $this->oLink is correct as $this->_getLinkObject() targeting AdminPageFramework_Facto...outer::_getLinkObject() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
460
            return $this->oLink;
461
        }
462
        /**
463
         * Sets and returns the `oPageLoadInfo` property.
464
         * @since       3.5.3
465
         */
466
        public function _replyTpSetAndGetInstance_oPageLoadInfo() {
467
            $this->oPageLoadInfo = $this->_getPageLoadObject();
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $this->oPageLoadInfo is correct as $this->_getPageLoadObject() targeting AdminPageFramework_Facto...r::_getPageLoadObject() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
468
            return $this->oPageLoadInfo;
469
        }
470
        /**#@-*/
471
472
    /**
473
     * Redirects dynamic function calls to the pre-defined internal method.
474
     *
475
     * @internal
476
     */
477
    public function __call( $sMethodName, $aArguments=null ) {
478
479
        $_mFirstArg = $this->oUtil->getElement( $aArguments, 0 );
480
481
        switch ( $sMethodName ) {
482
            case 'validate':
483
            case 'content':
484
                return $_mFirstArg;
485
486
        }
487
488
        // If it is called with the framework auto-callback,
489
        if ( has_filter( $sMethodName ) ) {
490
            return $this->_getAutoCallback( $sMethodName, $aArguments );
491
        }
492
493
        $this->_triggerUndefinedMethodWarning( $sMethodName );
494
495
    }
496
        /**
497
         * Returns the first parameter value if the method name does not contain a backslash.
498
         * If it contains a backslash, the user uses a name-spaced class name. In that case,
499
         * the backslashes need to be converted to underscores to support valid PHP method names.
500
         *
501
         * @since       3.7.0
502
         */
503
        private function _getAutoCallback( $sMethodName, $aArguments ) {
504
505
            // Check if the method name does not contain a backslash.
506
            if ( false === strpos( $sMethodName, "\\" ) ) {
507
                return $this->oUtil->getElement( $aArguments, 0 );  // the first element - the filter value
508
            }
509
510
            // If the method name contains a backslash, the user may be using a name space.
511
            // In that case, convert the backslash to underscore and call the method.
512
            $_sAutoCallbackMethodName = str_replace( '\\', '_', $sMethodName );
513
            return method_exists( $this, $_sAutoCallbackMethodName )
514
                ? call_user_func_array(
515
                    array( $this, $_sAutoCallbackMethodName ),
516
                    $aArguments
517
                )
518
                : $this->oUtil->getElement( $aArguments, 0 );   // the first argument
519
520
        }
521
522
        /**
523
         * @since   3.7.0
524
         * @return  void
525
         */
526
        private function _triggerUndefinedMethodWarning( $sMethodName ) {
527
            trigger_error(
528
                AdminPageFramework_Registry::NAME . ': '
529
                    . sprintf(
530
                        __( 'The method is not defined: %1$s', $this->oProp->sTextDomain ),
531
                        $sMethodName
532
                    ),
533
                E_USER_WARNING
534
            );
535
        }
536
537
538
539
    /**
540
     * Prevents the output from getting too long when the object is dumped.
541
     *
542
     * Field definition arrays contain the factory object reference and when the debug log method tries to dump it, the output gets too long.
543
     * So shorten it here.
544
     *
545
     * @remark      Called when the object is called as a string.
546
     * @remark      This method can be called statically with `AdminPageFramework_FrameworkUtility::getCallerScriptPath()` and the self instance is not instantiated.
547
     * In that case somehow `__get()` does not get triggered so here not using `$oUtil` and accessing the static method directly.
548
     * @since       3.4.4
549
     */
550
    public function __toString() {
551
        return AdminPageFramework_FrameworkUtility::getObjectInfo( $this );
552
    }
553
554
    /**
555
     * Deprecated methods.
556
     */
557
    /**
558
     * @remark          This was not functional since 3.1.3
559
     * @deprecated      3.5.5
560
     */
561
    public function setFooterInfoRight() {}
562
    /**
563
     * @remark          This was not functional since 3.1.3
564
     * @deprecated      3.5.5
565
     */
566
    public function setFooterInfoLeft() {}
567
568
}
569