Completed
Branch dev (71673f)
by
unknown
05:17
created

AdminPageFramework_Router::_isInThePage()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 14
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 6
c 0
b 0
f 0
nc 3
nop 0
dl 0
loc 14
rs 9.4285
1
<?php
2
/**
3
 * Admin Page Framework
4
 * 
5
 * http://en.michaeluno.jp/admin-page-framework/
6
 * Copyright (c) 2013-2016 Michael Uno; Licensed MIT
7
 * 
8
 */
9
10
/**
11
 * Deals with redirecting function calls and instantiating classes.
12
 *
13
 * @abstract
14
 * @since           3.0.0     
15
 * @since           3.3.1       Changed from `AdminPageFramework_Base`.
16
 * @package         AdminPageFramework
17
 * @subpackage      Factory/AdminPage
18
 * @internal
19
 * @method          _renderSectionDescription( $sMethodName )           defined in AdminPageFramework_Setting
20
 * @method          _renderSettingField( $_mFirstArg, $_sPageSlug )     defined in AdminPageFramework_Setting
21
 * @method          load()
22
 */
23
abstract class AdminPageFramework_Router extends AdminPageFramework_Factory {
24
    
25
    /**'
26
     * Sets up hooks and properties.
27
     * 
28
     * @since       3.3.0
29
     */
30
    public function __construct( $sOptionKey=null, $sCallerPath=null, $sCapability='manage_options', $sTextDomain='admin-page-framework' ) {
31
        
32
        $_sProprtyClassName = isset( $this->aSubClassNames[ 'oProp' ] )
33
            ? $this->aSubClassNames[ 'oProp' ]
34
            : 'AdminPageFramework_Property_' . $this->_sStructureType;
0 ignored issues
show
Documentation introduced by
The property _sStructureType does not exist on object<AdminPageFramework_Router>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
35
            
36
        $this->oProp = new $_sProprtyClassName( 
37
            $this, 
38
            $sCallerPath, 
39
            get_class( $this ), 
40
            $sOptionKey, 
41
            $sCapability, 
42
            $sTextDomain 
43
        );
44
45
        parent::__construct( $this->oProp );
46
47
        if ( $this->oProp->bIsAdminAjax ) {
48
            return;
49
        }     
50
        if ( ! $this->oProp->bIsAdmin ) {
51
            return;
52
        }
53
        
54
        add_action( 'wp_loaded', array( $this, '_replyToDetermineToLoad' ) );        
55
        
56
    }   
57
    
58
    /**
59
     * Instantiates a link object based on the type.
60
     * 
61
     * @since       3.7.10
62
     * @internal
63
     * @return      null|object
64
     */
65
    protected function _getLinkObject() {
66
        $_sClassName = $this->aSubClassNames[ 'oLink' ];
67
        return new $_sClassName( $this->oProp, $this->oMsg );        
68
    }    
69
    
70
    /**
71
     * Instantiates a link object based on the type.
72
     * 
73
     * @since       3.7.10
74
     * @internal
75
     * @return      null|object
76
     */    
77
    protected function _getPageLoadObject() {
78
        $_sClassName = $this->aSubClassNames[ 'oPageLoadInfo' ];
79
        return new $_sClassName( $this->oProp, $this->oMsg );
80
    }        
81
    
82
    /**
83
     * Handles undefined function calls.
84
     * 
85
     * This method redirects callback-function calls with the pre-defined prefixes for hooks to the appropriate methods. 
86
     * 
87
     * @access      public
88
     * @remark      the users do not need to call or extend this method unless they know what they are doing.
89
     * @param       string      the called method name. 
90
     * @param       array       the argument array. The first element holds the parameters passed to the called method.
91
     * @return      mixed       depends on the called method. If the method name matches one of the hook prefixes, the redirected methods return value will be returned. Otherwise, none.
92
     * @since       2.0.0
93
     * @since       3.3.1       Moved from `AdminPageFramework_Base`.
94
     * @internal
95
     */
96
    public function __call( $sMethodName, $aArgs=null ) {     
97
98
        $_sPageSlug             = $this->oProp->getCurrentPageSlug();
99
        $_sTabSlug              = $this->oProp->getCurrentTabSlug( $_sPageSlug );
100
        $_mFirstArg             = $this->oUtil->getElement( $aArgs, 0 );
101
        $_aKnownMethodPrefixes  = array(
102
            'section_pre_',
103
            'field_pre_',
104
            'load_pre_',
105
        );        
106
        
107
        switch( $this->_getCallbackName( $sMethodName, $_sPageSlug, $_aKnownMethodPrefixes ) ) {
108
                
109
            // add_settings_section() callback 
110
            case 'section_pre_':
111
                return $this->_renderSectionDescription( $sMethodName );    // defined in AdminPageFramework_Setting
112
                
113
            // add_settings_field() callback
114
            case 'field_pre_':
115
                return $this->_renderSettingField( $_mFirstArg, $_sPageSlug );  // defined in AdminPageFramework_Setting
116
            
117
            // load-{page} callback            
118
            case 'load_pre_':
119
                return $this->_doPageLoadCall( $sMethodName, $_sPageSlug, $_sTabSlug, $_mFirstArg );
120
            
121
            default:
122
                return parent::__call( $sMethodName, $aArgs );
123
        }        
124
        
125
    }    
126
        /**
127
         * Attempts to find the factory class callback method for the given method name.
128
         * 
129
         * @since       3.5.3
130
         * @return      string      The found callback method name or the prefix of a known callback method name. An empty string if not found.
131
         * @internal
132
         */
133
        private function _getCallbackName( $sMethodName, $sPageSlug, array $aKnownMethodPrefixes=array() ) {
0 ignored issues
show
Unused Code introduced by
The parameter $sPageSlug is not used and could be removed.

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

Loading history...
134
                        
135
            foreach( $aKnownMethodPrefixes as $_sMethodPrefix ) {
136
                if ( $this->oUtil->hasPrefix( $_sMethodPrefix, $sMethodName ) ) {
137
                    return $_sMethodPrefix;
138
                }
139
            }
140
            return '';
141
            
142
        }    
143
                
144
        /**
145
         * Redirects the callback of the load-{page} action hook to the framework's callback.
146
         * 
147
         * @since       2.1.0
148
         * @since       3.3.1       Moved from `AdminPageFramework_Base`.
149
         * @since       3.5.3       Added the $sMethodName parameter.
150
         * 
151
         * @access      protected
152
         * @internal
153
         * @remark      This method will be triggered before the header gets sent.
154
         * @return      void
155
         * @internal
156
         */ 
157
        protected function _doPageLoadCall( $sMethodName, $sPageSlug, $sTabSlug, $oScreen ) {
158
            
159
            if ( ! $this->_isPageLoadCall( $sMethodName, $sPageSlug, $oScreen->id ) ) {
160
                return;
161
            }
162
                      
163
            // [3.4.6+] Set the page and tab slugs to the default form section so that added form fields without a section will appear in different pages and tabs.
164
            $this->_setPageAndTabSlugsForForm( $sPageSlug, $sTabSlug );
165
166
            $this->_setShowDebugInfoProperty( $sPageSlug ); // 3.8.8+
167
                                    
168
            // Do actions in this order, class ->  page -> in-page tab. This order is important as some methods rely on it.
169
            $this->load();  // 3.7.12+
170
            $this->oUtil->addAndDoActions( 
171
                $this, // the caller object
172
                array( 
173
                    "load_{$this->oProp->sClassName}",
174
                    "load_{$sPageSlug}",
175
                ),
176
                $this // the admin page object - this lets third-party scripts use the framework methods.
177
            );
178
            
179
            // * Note that the in-page tabs handling method `_replyToFinalizeInPageTabs()` is called in the above action hook.
180
            
181
            // Re-retrieve the current tab slug as in-page tabs may be added during the above `load_{...}`  hooks.
182
            // Note that the if the tab is the first item, and the user arrives the page by clicking on the sidebar menu, the tab slug will be empty unless an in-page tab is added.
183
            $sTabSlug = $this->oProp->getCurrentTabSlug( $sPageSlug );
184
            
185
            if ( strlen( $sTabSlug ) ) { 
186
                $this->_setShowDebugInfoProperty( $sPageSlug, $sTabSlug );  // 3.8.8+
187
                $this->oUtil->addAndDoActions( 
188
                    $this, // the caller object
189
                    array( "load_{$sPageSlug}_" . $sTabSlug ),
190
                    $this // the admin page object - this lets third-party scripts use the framework methods.
191
                );         
192
            }
193
            
194
            $this->oUtil->addAndDoActions( 
195
                $this, // the caller object
196
                array( 
197
                    "load_after_{$this->oProp->sClassName}",
198
                    "load_after_{$sPageSlug}", // 3.6.3+
199
                ),
200
                $this // the admin page object - this lets third-party scripts use the framework methods.
201
            );
202
            
203
        }
204
            /**
205
             * Updates the `bShowDebugInfo` property based on the current page and in-page-tab arguments.
206
             * 
207
             * If the `$sTabSlug` parameter is not set, it is considered for the current page. Otherwise, it is for the current tab.
208
             * 
209
             * @remark      This must be called before calling the `load()` method as which page to load is already determined at this point.
210
             * And if the user wants to modify the property value manually, they can do so in the `load()` method.
211
             * @since       3.8.8
212
             * @return      void
213
             */
214
            private function _setShowDebugInfoProperty( $sPageSlug, $sTabSlug='' ) {
215
216
                // For the page,
217
                if ( ! strlen( $sTabSlug ) ) {
218
                    $this->oProp->bShowDebugInfo = $this->oUtil->getElement(
219
                        $this->oProp->aPages,
220
                        array( $sPageSlug, 'show_debug_info' ),
221
                        $this->oProp->bShowDebugInfo
222
                    );                          
223
                    return;
224
                }
225
                // For the in-page tab.
226
                $this->oProp->bShowDebugInfo = $this->oUtil->getElement(
227
                    $this->oProp->aInPageTabs,
228
                    array( $sPageSlug, $sTabSlug, 'show_debug_info' ),
229
                    $this->oProp->bShowDebugInfo
230
                );
231
                
232
            }       
233
                   
234
            /**
235
             * Sets the page and tab slugs to the default form section 
236
             * so that added form fields without a section will appear in different pages and tabs.
237
             * 
238
             * @internal
239
             * @since       3.8.8
240
             * @todo        The `oForm` object will get instantiated even the user does not use a form. 
241
             * So look for a way to avoid calling `$oForm` unless the user uses a form.
242
             */
243
            private function _setPageAndTabSlugsForForm( $sPageSlug, $sTabSlug ) {
244
                $this->oForm->aSections[ '_default' ][ 'page_slug' ]  = $sPageSlug ? $sPageSlug : null;
245
                $this->oForm->aSections[ '_default' ][ 'tab_slug' ]   = $sTabSlug ? $sTabSlug : null;
246
            }
247
        
248
            /**
249
             * Determines whether the function call is of a page load.
250
             * @since       3.5.3
251
             * @internal
252
             * @return      boolean     True if it is a page load call; othwrwise, false.
253
             * @param       string      $sMethodName        The undefined method name that is passed to the __call() overload method.
254
             * @param       string      $sPageSlug          The currently loading page slug.
255
             * @param       string      $sScreenID          The screen ID that the WordPress screen object gives.
256
             */
257
            private function _isPageLoadCall( $sMethodName, $sPageSlug, $sScreenID ) {
258
                
259
                if ( substr( $sMethodName, strlen( 'load_pre_' ) ) !== $sPageSlug ) {
260
                    return false;
261
                }
262
                if ( ! isset( $this->oProp->aPageHooks[ $sPageSlug ] ) ) {
263
                    return false;
264
                }
265
                if ( $sScreenID !== $this->oProp->aPageHooks[ $sPageSlug ] ) {
266
                    return false;
267
                }
268
                return true;
269
                
270
            }       
271
            
272
    /* Shared methods */
273
    
274
    /**
275
     * Checks whether the class should be instantiated.
276
     * 
277
     * @since       3.1.0
278
     * @since       3.3.1       Moved from `AdminPageFramework_Base`.
279
     * @internal
280
     */
281
    protected function _isInstantiatable() {
0 ignored issues
show
Coding Style introduced by
_isInstantiatable uses the super-global variable $GLOBALS 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...
282
        
283
        // Disable in admin-ajax.php
284
        if ( isset( $GLOBALS[ 'pagenow' ] ) && 'admin-ajax.php' === $GLOBALS[ 'pagenow' ] ) {
285
            return false;
286
        }
287
        
288
        // Nothing to do in the network admin area.
289
        return ! is_network_admin();
290
        
291
    }
292
    
293
    /**
294
     * Checks whether the currently loading page is of the given pages. 
295
     * 
296
     * @since       3.0.2
297
     * @since       3.2.0       Changed the scope to public from protected as the head tag object will access it.
298
     * @since       3.3.1       Moved from `AdminPageFramework_Base`.
299
     * @internal
300
     */
301
    public function _isInThePage() {
0 ignored issues
show
Coding Style introduced by
_isInThePage uses the super-global variable $_GET 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...
302
        
303
        // If the setUp method is not loaded yet,
304
        if ( ! did_action( 'set_up_' . $this->oProp->sClassName ) ) {
305
            return true;
306
        }    
307
308
        if ( ! isset( $_GET[ 'page' ] ) ) { 
309
            return false; 
310
        }        
311
        
312
        return $this->oProp->isPageAdded();
313
        
314
    }
315
    
316
    /**
317
     * Determines whether the class component classes should be instantiated or not.
318
     * 
319
     * @internal
320
     * @callback    action      current_screen
321
     * @return      void
322
     * @since       3.7.0
323
     */
324
    public function _replyToLoadComponents( /* $oScreen */ ) {
325
326
        if ( 'plugins.php' === $this->oProp->sPageNow ) {
327
            $this->oLink = $this->_replyTpSetAndGetInstance_oLink();
328
        }
329
        parent::_replyToLoadComponents();
330
        
331
    }    
332
    
333
}
334