Completed
Branch FET-10486-add-timestamp-checki... (611b15)
by
unknown
136:24 queued 121:17
created

LegacyShortcodesManager   B

Complexity

Total Complexity 47

Size/Duplication

Total Lines 431
Duplicated Lines 5.8 %

Coupling/Cohesion

Components 1
Dependencies 5

Importance

Changes 0
Metric Value
dl 25
loc 431
rs 8.439
c 0
b 0
f 0
wmc 47
lcom 1
cbo 5

14 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
A registry() 0 4 1
A registerShortcodes() 0 4 1
B getShortcodes() 0 26 4
B registerShortcode() 20 61 5
B addShortcodes() 0 29 4
C initializeShortcodes() 5 68 12
A parseContentForShortcodes() 0 12 4
B initializeShortcode() 0 38 6
A generateShortcodeTagFromClassName() 0 4 1
B generateShortcodeClassNameFromTag() 0 24 1
A addShortcodeClassPrefix() 0 4 2
A getEspressoShortcodeTags() 0 8 2
A doShortcode() 0 10 3

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like LegacyShortcodesManager 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. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

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 LegacyShortcodesManager, and based on these observations, apply Extract Interface, too.

1
<?php
2
namespace EventEspresso\core\services\shortcodes;
3
4
use EE_Config;
5
use EE_Error;
6
use EE_Front_controller;
7
use EE_Registry;
8
use ReflectionClass;
9
use WP;
10
use WP_Query;
11
12
defined('EVENT_ESPRESSO_VERSION') || exit;
13
14
15
16
/**
17
 * Class LegacyShortcodesManager
18
 * Legacy code extracted from EE_Config, will be deprecated sometime in the future.
19
 * Please use the ShortcodesManager for registering shortcodes
20
 *
21
 * @package       Event Espresso
22
 * @author        Brent Christensen
23
 * @since         $VID:$
24
 */
25
class LegacyShortcodesManager
26
{
27
28
    /**
29
     * @var EE_Registry $registry
30
     */
31
    private $registry;
32
33
34
35
36
    /**
37
     * LegacyShortcodesManager constructor.
38
     *
39
     * @param \EE_Registry $registry
40
     */
41
    public function __construct(EE_Registry $registry)
42
    {
43
        $this->registry = $registry;
44
    }
45
46
47
48
    /**
49
     * @return EE_Registry
50
     */
51
    public function registry()
52
    {
53
        return $this->registry;
54
    }
55
56
57
58
    /**
59
     * registerShortcodes
60
     *
61
     * @return void
62
     */
63
    public function registerShortcodes()
64
    {
65
        $this->registry->shortcodes = $this->getShortcodes();
66
    }
67
68
69
70
    /**
71
     * getShortcodes
72
     *
73
     * @return array
74
     */
75
    public function getShortcodes()
76
    {
77
        // previously this method would glob the shortcodes directory
78
        // then filter that list of shortcodes to register,
79
        // but now we are going to just supply an empty array.
80
        // this allows any shortcodes that have not yet been converted to the new system
81
        // to still get loaded and processed, albeit using the same legacy logic as before
82
        $shortcodes_to_register = apply_filters(
83
            'FHEE__EE_Config__register_shortcodes__shortcodes_to_register',
84
            array()
85
        );
86
        if ( ! empty($shortcodes_to_register)) {
87
            // cycle thru shortcode folders
88
            foreach ($shortcodes_to_register as $shortcode_path) {
89
                // add to list of installed shortcode modules
90
                $this->registerShortcode($shortcode_path);
91
            }
92
        }
93
        // filter list of installed modules
94
        return apply_filters(
95
            'FHEE__EE_Config___register_shortcodes__installed_shortcodes',
96
            ! empty($this->registry->shortcodes)
97
                ? $this->registry->shortcodes
98
                : array()
99
        );
100
    }
101
102
103
104
    /**
105
     *    register_shortcode - makes core aware of this shortcode
106
     *
107
     * @access    public
108
     * @param    string $shortcode_path - full path up to and including shortcode folder
109
     * @return    bool
110
     */
111
    public function registerShortcode($shortcode_path = null)
112
    {
113
        do_action('AHEE__EE_Config__register_shortcode__begin', $shortcode_path);
114
        $shortcode_ext = '.shortcode.php';
115
        // make all separators match
116
        $shortcode_path = str_replace(array('\\', '/'), DS, $shortcode_path);
117
        // does the file path INCLUDE the actual file name as part of the path ?
118
        if (strpos($shortcode_path, $shortcode_ext) !== false) {
119
            // grab shortcode file name from directory name and break apart at dots
120
            $shortcode_file = explode('.', basename($shortcode_path));
121
            // take first segment from file name pieces and remove class prefix if it exists
122
            $shortcode = strpos($shortcode_file[0], 'EES_') === 0
123
                ? substr($shortcode_file[0], 4)
124
                : $shortcode_file[0];
125
            // sanitize shortcode directory name
126
            $shortcode = sanitize_key($shortcode);
127
            // now we need to rebuild the shortcode path
128
            $shortcode_path = explode(DS, $shortcode_path);
129
            // remove last segment
130
            array_pop($shortcode_path);
131
            // glue it back together
132
            $shortcode_path = implode(DS, $shortcode_path) . DS;
133
        } else {
134
            // we need to generate the filename based off of the folder name
135
            // grab and sanitize shortcode directory name
136
            $shortcode = sanitize_key(basename($shortcode_path));
137
            $shortcode_path = rtrim($shortcode_path, DS) . DS;
138
        }
139
        // create classname from shortcode directory or file name
140
        $shortcode = str_replace(' ', '_', ucwords(str_replace('_', ' ', $shortcode)));
141
        // add class prefix
142
        $shortcode_class = 'EES_' . $shortcode;
143
        // does the shortcode exist ?
144 View Code Duplication
        if ( ! is_readable($shortcode_path . DS . $shortcode_class . $shortcode_ext)) {
145
            $msg = sprintf(
146
                esc_html__(
147
                    'The requested %s shortcode file could not be found or is not readable due to file permissions. It should be in %s',
148
                    'event_espresso'
149
                ),
150
                $shortcode_class,
151
                $shortcode_path . DS . $shortcode_class . $shortcode_ext
152
            );
153
            EE_Error::add_error($msg . '||' . $msg, __FILE__, __FUNCTION__, __LINE__);
154
            return false;
155
        }
156
        // load the shortcode class file
157
        require_once($shortcode_path . $shortcode_class . $shortcode_ext);
158
        // verify that class exists
159 View Code Duplication
        if ( ! class_exists($shortcode_class)) {
160
            $msg = sprintf(
161
                esc_html__('The requested %s shortcode class does not exist.', 'event_espresso'),
162
                $shortcode_class
163
            );
164
            EE_Error::add_error($msg . '||' . $msg, __FILE__, __FUNCTION__, __LINE__);
165
            return false;
166
        }
167
        $shortcode = strtoupper($shortcode);
168
        // add to array of registered shortcodes
169
        $this->registry->shortcodes->{$shortcode} = $shortcode_path . $shortcode_class . $shortcode_ext;
170
        return true;
171
    }
172
173
174
175
    /**
176
     *    _initialize_shortcodes
177
     *    allow shortcodes to set hooks for the rest of the system
178
     *
179
     * @access private
180
     * @return void
181
     */
182
    public function addShortcodes()
183
    {
184
        // cycle thru shortcode folders
185
        foreach ($this->registry->shortcodes as $shortcode => $shortcode_path) {
186
            // add class prefix
187
            $shortcode_class = 'EES_' . $shortcode;
188
            // fire the shortcode class's set_hooks methods in case it needs to hook into other parts of the system
189
            // which set hooks ?
190
            if (is_admin()) {
191
                // fire immediately
192
                call_user_func(array($shortcode_class, 'set_hooks_admin'));
193
            } else {
194
                // delay until other systems are online
195
                add_action(
196
                    'AHEE__EE_System__set_hooks_for_shortcodes_modules_and_addons',
197
                    array($shortcode_class, 'set_hooks')
198
                );
199
                // convert classname to UPPERCASE and create WP shortcode.
200
                $shortcode_tag = strtoupper($shortcode);
201
                // but first check if the shortcode has already
202
                // been added before assigning 'fallback_shortcode_processor'
203
                if ( ! shortcode_exists($shortcode_tag)) {
204
                    // NOTE: this shortcode declaration will get overridden if the shortcode
205
                    // is successfully detected in the post content in initializeShortcode()
206
                    add_shortcode($shortcode_tag, array($shortcode_class, 'fallback_shortcode_processor'));
207
                }
208
            }
209
        }
210
    }
211
212
213
214
    /**
215
     * callback for the WP "get_header" hook point
216
     * checks posts for EE shortcodes, and initializes them,
217
     * then toggles filter switch that loads core default assets
218
     *
219
     * @param \WP_Query $wp_query
220
     * @return void
221
     */
222
    public function initializeShortcodes(WP_Query $wp_query)
223
    {
224
        if (empty($this->registry->shortcodes) || ! $wp_query->is_main_query() || is_admin()) {
225
            return;
226
        }
227
        global $wp;
228
        /** @var EE_Front_controller $Front_Controller */
229
        $Front_Controller = $this->registry->load_core('Front_Controller', array(), false);
230
        do_action('AHEE__EE_Front_Controller__initialize_shortcodes__begin', $wp, $Front_Controller);
231
        $Front_Controller->Request_Handler()->set_request_vars();
232
        // grab post_name from request
233
        $current_post = apply_filters(
234
            'FHEE__EE_Front_Controller__initialize_shortcodes__current_post_name',
235
            $Front_Controller->Request_Handler()->get('post_name')
236
        );
237
        $show_on_front = get_option('show_on_front');
238
        // if it's not set, then check if frontpage is blog
239
        if (empty($current_post)) {
240
            // yup.. this is the posts page, prepare to load all shortcode modules
241
            $current_post = 'posts';
242
            // unless..
243
            if ($show_on_front === 'page') {
244
                // some other page is set as the homepage
245
                $page_on_front = get_option('page_on_front');
246
                if ($page_on_front) {
247
                    // k now we need to find the post_name for this page
248
                    global $wpdb;
249
                    $page_on_front = $wpdb->get_var(
250
                        $wpdb->prepare(
251
                            "SELECT post_name from {$wpdb->posts} WHERE post_type='page' AND post_status='publish' AND ID=%d",
252
                            $page_on_front
253
                        )
254
                    );
255
                    // set the current post slug to what it actually is
256
                    $current_post = $page_on_front ? $page_on_front : $current_post;
257
                }
258
            }
259
        }
260
        // in case $current_post is hierarchical like: /parent-page/current-page
261
        $current_post = basename($current_post);
262
        if (
263
            // is current page/post the "blog" page ?
264
            $current_post === EE_Config::get_page_for_posts()
265
            // or are we on a category page?
266
            || (
267
                is_array(term_exists($current_post, 'category'))
268
                || array_key_exists('category_name', $wp->query_vars)
269
            )
270
        ) {
271
            // initialize all legacy shortcodes
272
            $load_assets = $this->parseContentForShortcodes('', true);
273
        } else {
274
            global $wpdb;
275
            $post_content = $wpdb->get_var(
276
                $wpdb->prepare(
277
                    "SELECT post_content from {$wpdb->posts} WHERE post_status='publish' AND post_name=%s",
278
                    $current_post
279
                )
280
            );
281
            $load_assets = $this->parseContentForShortcodes($post_content);
282
        }
283 View Code Duplication
        if ($load_assets) {
284
            $this->registry->REQ->set_espresso_page(true);
285
            add_filter('FHEE_load_css', '__return_true');
286
            add_filter('FHEE_load_js', '__return_true');
287
        }
288
        do_action('AHEE__EE_Front_Controller__initialize_shortcodes__end', $Front_Controller);
289
    }
290
291
292
293
    /**
294
     * checks supplied content against list of legacy shortcodes,
295
     * then initializes any found shortcodes, and returns true.
296
     * returns false if no shortcodes found.
297
     *
298
     * @param string $content
299
     * @param bool   $load_all if true, then ALL active legacy shortcodes will be initialized
300
     * @return bool
301
     */
302
    public function parseContentForShortcodes($content = '', $load_all = false)
303
    {
304
        $has_shortcode = false;
305
        foreach ($this->registry->shortcodes as $shortcode_class => $shortcode) {
306
            if ($load_all || has_shortcode($content, $shortcode_class) ) {
307
                // load up the shortcode
308
                $this->initializeShortcode($shortcode_class);
309
                $has_shortcode = true;
310
            }
311
        }
312
        return $has_shortcode;
313
    }
314
315
316
317
    /**
318
     * given a shortcode name, will instantiate the shortcode and call it's run() method
319
     *
320
     * @param string $shortcode_class
321
     * @param WP     $wp
322
     */
323
    public function initializeShortcode($shortcode_class = '', WP $wp = null)
324
    {
325
        // don't do anything if shortcode is already initialized
326
        if (
327
            empty($this->registry->shortcodes->{$shortcode_class})
328
            || ! is_string($this->registry->shortcodes->{$shortcode_class})
329
        ) {
330
            return;
331
        }
332
        // let's pause to reflect on this...
333
        $sc_reflector = new ReflectionClass(LegacyShortcodesManager::addShortcodeClassPrefix($shortcode_class));
334
        // ensure that class is actually a shortcode
335
        if (
336
            defined('WP_DEBUG')
337
            && WP_DEBUG === true
338
            && ! $sc_reflector->isSubclassOf('EES_Shortcode')
339
        ) {
340
            EE_Error::add_error(
341
                sprintf(
342
                    esc_html__(
343
                        'The requested %s shortcode is not of the class "EES_Shortcode". Please check your files.',
344
                        'event_espresso'
345
                    ),
346
                    $shortcode_class
347
                ),
348
                __FILE__,
349
                __FUNCTION__,
350
                __LINE__
351
            );
352
            add_filter('FHEE_run_EE_the_content', '__return_true');
353
            return;
354
        }
355
        global $wp;
356
        // and pass the request object to the run method
357
        $this->registry->shortcodes->{$shortcode_class} = $sc_reflector->newInstance();
358
        // fire the shortcode class's run method, so that it can activate resources
359
        $this->registry->shortcodes->{$shortcode_class}->run($wp);
360
    }
361
362
363
364
    /**
365
     * get classname, remove EES_prefix, and convert to UPPERCASE
366
     *
367
     * @param string $class_name
368
     * @return string
369
     */
370
    public static function generateShortcodeTagFromClassName($class_name)
371
    {
372
        return strtoupper(str_replace('EES_', '', $class_name));
373
    }
374
375
376
377
    /**
378
     * add EES_prefix and Capitalize words
379
     *
380
     * @param string $tag
381
     * @return string
382
     */
383
    public static function generateShortcodeClassNameFromTag($tag)
384
    {
385
        // order of operation runs from inside to out
386
        // 5) maybe add prefix
387
        return LegacyShortcodesManager::addShortcodeClassPrefix(
388
        // 4) find spaces, replace with underscores
389
            str_replace(
390
                ' ',
391
                '_',
392
                // 3) capitalize first letter of each word
393
                ucwords(
394
                // 2) also change to lowercase so ucwords() will work
395
                    strtolower(
396
                    // 1) find underscores, replace with spaces so ucwords() will work
397
                        str_replace(
398
                            '_',
399
                            ' ',
400
                            $tag
401
                        )
402
                    )
403
                )
404
            )
405
        );
406
    }
407
408
409
410
    /**
411
     * maybe add EES_prefix
412
     *
413
     * @param string $class_name
414
     * @return string
415
     */
416
    public static function addShortcodeClassPrefix($class_name)
417
    {
418
        return strpos($class_name, 'EES_') === 0 ? $class_name : 'EES_' . $class_name;
419
    }
420
421
422
423
    /**
424
     * @return array
425
     */
426
    public function getEspressoShortcodeTags()
427
    {
428
        static $shortcode_tags = array();
429
        if (empty($shortcode_tags)) {
430
            $shortcode_tags = array_keys((array)$this->registry->shortcodes);
431
        }
432
        return $shortcode_tags;
433
    }
434
435
436
437
    /**
438
     * @param string $content
439
     * @return string
440
     */
441
    public function doShortcode($content)
442
    {
443
        foreach ($this->getEspressoShortcodeTags() as $shortcode_tag) {
444
            if (strpos($content, $shortcode_tag) !== false) {
445
                $shortcode_class = LegacyShortcodesManager::generateShortcodeClassNameFromTag($shortcode_tag);
446
                $this->initializeShortcode($shortcode_class);
447
            }
448
        }
449
        return do_shortcode($content);
450
    }
451
452
453
454
455
}
456
// End of file LegacyShortcodesManager.php
457
// Location: EventEspresso\core\services\shortcodes/LegacyShortcodesManager.php