AdminPageFramework_Factory_Router::__toString()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 2
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 1
dl 0
loc 2
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
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
 * 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 ( ! empty( $GLOBALS[ 'pagenow' ] ) && 'async-upload.php' === $GLOBALS[ 'pagenow' ] ) {   // 3.9.1
250
            return true;
251
        }
252
        if ( $this->_isWordPressCoreAjaxRequest() ) {
253
            return false;
254
        }
255
        return true;
256
    }
257
        /**
258
         * Checks whether the page call is by WordPress core ajax requests.
259
         * @return boolean
260
         * @remark Not using the property or utility object as this can be called prior to instantiating those.
261
         * @since  3.8.19
262
         */
263
        protected function _isWordPressCoreAjaxRequest() {
264
            if ( ! isset( $GLOBALS[ 'pagenow' ] ) ) {
265
                return false;
266
            }
267
            if ( 'admin-ajax.php' !== $GLOBALS[ 'pagenow' ] ) {
268
                return false;
269
            }
270
            return in_array(
271
                isset( $_POST[ 'action' ] ) ? $_POST[ 'action' ] : '',  // sanitization unnecessary as just checking
272
                array( 'heartbeat', 'closed-postboxes', 'meta-box-order' ),
273
                true
274
            );
275
        }
276
277
    /**
278
     * Determines whether the instantiated object and its producing elements belong to the loading page.
279
     *
280
     * This method should be redefined in the extended class.
281
     *
282
     * @remark      This method should be called AFTER current screen is determined such as after the `current_screen` action hook.
283
     * @since       3.0.3
284
     * @since       3.2.0   Changed the visibility scope to `public` from `protected` as the head tag object will access it.
285
     * @since       3.8.14  Changed the visibility scope to `protected` from `public` as there is the `isInThePage()` public method.
286
     * @internal
287
     */
288
    protected function _isInThePage() {
289
        return true;
290
    }
291
292
    /**
293
     * Checks if the `admin-ajax.php` is called from the page that this meta box belongs to.
294
     * @remark  Extended factory types should override this method.
295
     * @sicne   3.8.19
296
     * @return  boolean
297
     */
298
    protected function _isValidAjaxReferrer() {
299
        if ( ! $this->oProp->bIsAdminAjax ) {
300
            return false;
301
        }
302
        return true;
303
    }
304
305
    /**
306
     * Determines whether the `setUp()` method should be called.
307
     *
308
     * @since       3.7.10
309
     * @callback
310
     * @internal
311
     * @return      void
312
     */
313
    public function _replyToDetermineToLoad() {
314
315
        if ( ! $this->_isInThePage() ) {
316
            return;
317
        }
318
319
        $this->_setUp();
320
321
    }
322
323
324
    /**
325
     * Instantiate a form object based on the type.
326
     *
327
     * @since       3.1.0
328
     * @internal
329
     * @return      object|null
330
     */
331
    protected function _getFormObject() {
332
333
        $this->oProp->setFormProperties();
334
        $_sFormClass = $this->aSubClassNames[ 'oForm' ];
335
        return new $_sFormClass(
336
            $this->oProp->aFormArguments, // Options - for the values that do not need to change through out the script execution.
337
            $this->oProp->aFormCallbacks, // Callbacks - for the values which change dynamically depending on conditions such as the loaded page url.
338
            $this->oMsg
339
        );
340
341
    }
342
343
    /**
344
     * Instantiates a link object based on the type.
345
     *
346
     * @since       3.0.4
347
     * @since       3.7.10      Removed the parameters as those values will be set in the extended class.
348
     * @remark      Override this method in an extended class.
349
     * @internal
350
     * @return      null|object
351
     */
352
    protected function _getLinkObject() {
353
        return null;
354
    }
355
356
    /**
357
     * Instantiates a page load object based on the type.
358
     *
359
     * @since       3.0.4
360
     * @since       3.7.10      Removed the parameters as those values will be set in the extended class.
361
     * @internal
362
     */
363
    protected function _getPageLoadObject() {
364
        return null;
365
    }
366
367
    /**
368
     * Responds to a request of an undefined property.
369
     *
370
     * This is used to instantiate classes only when necessary, rather than instantiating them all at once.
371
     *
372
     * @internal
373
     * @param       string $sPropertyName
374
     * @return      mixed
375
     */
376
    public function __get( $sPropertyName ) {
377
378
        // Set and return the sub class object instance.
379
        if ( isset( $this->aSubClassNames[ $sPropertyName ] ) ) {
380
            return call_user_func(
381
                array( $this, "_replyTpSetAndGetInstance_{$sPropertyName}"  )
382
            );
383
        }
384
385
    }
386
        /**#@+
387
         * @internal
388
         * @return      object
389
         * @callback    function    call_user_func
390
         */
391
        /**
392
         * Sets and returns the `oUtil` property.
393
         * @since       3.5.3
394
         */
395
        public function _replyTpSetAndGetInstance_oUtil() {
396
            $_sClassName = $this->aSubClassNames[ 'oUtil' ];
397
            $this->oUtil = new $_sClassName;
398
            return $this->oUtil;
399
        }
400
        /**
401
         * Sets and returns the `oDebug` property.
402
         * @since       3.5.3
403
         */
404
        public function _replyTpSetAndGetInstance_oDebug() {
405
            $_sClassName = $this->aSubClassNames[ 'oDebug' ];
406
            $this->oDebug = new $_sClassName;
407
            return $this->oDebug;
408
        }
409
        /**
410
         * Sets and returns the `oMsg` property.
411
         * @since       3.5.3
412
         */
413
        public function _replyTpSetAndGetInstance_oMsg() {
414
            $this->oMsg = call_user_func_array(
415
                array( $this->aSubClassNames[ 'oMsg' ], 'getInstance'),
416
                array( $this->oProp->sTextDomain )  // parameters
417
            );
418
            return $this->oMsg;
419
        }
420
        /**
421
         * Sets and returns the `oForm` property.
422
         * @since       3.5.3
423
         */
424
        public function _replyTpSetAndGetInstance_oForm() {
425
            $this->oForm = $this->_getFormObject();
426
            return $this->oForm;
427
        }
428
        /**
429
         * Sets and returns the `oResouce` property.
430
         * @since       3.5.3
431
         */
432
        public function _replyTpSetAndGetInstance_oResource() {
433
            if ( isset( $this->oResource ) ) {
434
                return $this->oResource;
435
            }
436
            $_sClassName     = $this->aSubClassNames[ 'oResource' ];
437
            $this->oResource = new $_sClassName( $this->oProp );
438
            return $this->oResource;
439
        }
440
            /**
441
             * Kept for backward compatibility.
442
             * @since       3.7.10
443
             */
444
            public function _replyTpSetAndGetInstance_oHeadTag() {
445
                $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...
446
                return $this->oHead;
447
            }
448
        /**
449
         * Sets and returns the `oHelpPane` property.
450
         * @since       3.5.3
451
         */
452
        public function _replyTpSetAndGetInstance_oHelpPane() {
453
            $_sClassName     = $this->aSubClassNames[ 'oHelpPane' ];
454
            $this->oHelpPane = new $_sClassName( $this->oProp );
455
            return $this->oHelpPane;
456
        }
457
        /**
458
         * Sets and returns the `oLink` property.
459
         * @since       3.5.3
460
         */
461
        public function _replyTpSetAndGetInstance_oLink() {
462
            $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...
463
            return $this->oLink;
464
        }
465
        /**
466
         * Sets and returns the `oPageLoadInfo` property.
467
         * @since       3.5.3
468
         */
469
        public function _replyTpSetAndGetInstance_oPageLoadInfo() {
470
            $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...
471
            return $this->oPageLoadInfo;
472
        }
473
        /**#@-*/
474
475
    /**
476
     * Redirects dynamic function calls to the pre-defined internal method.
477
     *
478
     * @internal
479
     */
480
    public function __call( $sMethodName, $aArguments=null ) {
481
482
        $_mFirstArg = $this->oUtil->getElement( $aArguments, 0 );
483
484
        switch ( $sMethodName ) {
485
            case 'validate':
486
            case 'content':
487
                return $_mFirstArg;
488
489
        }
490
491
        // If it is called with the framework auto-callback,
492
        if ( has_filter( $sMethodName ) ) {
493
            return $this->_getAutoCallback( $sMethodName, $aArguments );
494
        }
495
496
        $this->_triggerUndefinedMethodWarning( $sMethodName );
497
498
    }
499
        /**
500
         * Returns the first parameter value if the method name does not contain a backslash.
501
         * If it contains a backslash, the user uses a name-spaced class name. In that case,
502
         * the backslashes need to be converted to underscores to support valid PHP method names.
503
         *
504
         * @since       3.7.0
505
         */
506
        private function _getAutoCallback( $sMethodName, $aArguments ) {
507
508
            // Check if the method name does not contain a backslash.
509
            if ( false === strpos( $sMethodName, "\\" ) ) {
510
                return $this->oUtil->getElement( $aArguments, 0 );  // the first element - the filter value
511
            }
512
513
            // If the method name contains a backslash, the user may be using a name space.
514
            // In that case, convert the backslash to underscore and call the method.
515
            $_sAutoCallbackMethodName = str_replace( '\\', '_', $sMethodName );
516
            return method_exists( $this, $_sAutoCallbackMethodName )
517
                ? call_user_func_array(
518
                    array( $this, $_sAutoCallbackMethodName ),
519
                    $aArguments
520
                )
521
                : $this->oUtil->getElement( $aArguments, 0 );   // the first argument
522
523
        }
524
525
        /**
526
         * @since   3.7.0
527
         * @return  void
528
         */
529
        private function _triggerUndefinedMethodWarning( $sMethodName ) {
530
            trigger_error(
531
                AdminPageFramework_Registry::NAME . ': '
532
                    . sprintf(
533
                        __( 'The method is not defined: %1$s', $this->oProp->sTextDomain ),
534
                        $sMethodName
535
                    ),
536
                E_USER_WARNING
537
            );
538
        }
539
540
541
542
    /**
543
     * Prevents the output from getting too long when the object is dumped.
544
     *
545
     * Field definition arrays contain the factory object reference and when the debug log method tries to dump it, the output gets too long.
546
     * So shorten it here.
547
     *
548
     * @remark      Called when the object is called as a string.
549
     * @remark      This method can be called statically with `AdminPageFramework_FrameworkUtility::getCallerScriptPath()` and the self instance is not instantiated.
550
     * In that case somehow `__get()` does not get triggered so here not using `$oUtil` and accessing the static method directly.
551
     * @since       3.4.4
552
     */
553
    public function __toString() {
554
        return AdminPageFramework_FrameworkUtility::getObjectInfo( $this );
555
    }
556
557
    /**
558
     * Deprecated methods.
559
     */
560
    /**
561
     * @remark          This was not functional since 3.1.3
562
     * @deprecated      3.5.5
563
     */
564
    public function setFooterInfoRight() {}
565
    /**
566
     * @remark          This was not functional since 3.1.3
567
     * @deprecated      3.5.5
568
     */
569
    public function setFooterInfoLeft() {}
570
571
}