Completed
Branch BUG-10626-dst-unit-test (cc62a6)
by
unknown
37:15 queued 23:58
created

EspressoShortcode   A

Complexity

Total Complexity 22

Size/Duplication

Total Lines 220
Duplicated Lines 15.45 %

Coupling/Cohesion

Components 1
Dependencies 3

Importance

Changes 0
Metric Value
dl 34
loc 220
rs 10
c 0
b 0
f 0
wmc 22
lcom 1
cbo 3

8 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
A shortcodeHasBeenInitialized() 0 4 1
A processShortcodeCallback() 0 13 3
B shortcodeContent() 0 27 2
A currentPostID() 0 13 2
A shortcodeCacheID() 0 5 1
A customAttributeSanitizationMap() 0 4 1
C sanitizeAttributes() 34 39 11

How to fix   Duplicated Code   

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:

1
<?php
2
namespace EventEspresso\core\services\shortcodes;
3
4
use EE_Error;
5
use EEH_Event_View;
6
use EventEspresso\core\domain\EnqueueAssetsInterface;
7
use EventEspresso\core\services\cache\PostRelatedCacheManager;
8
9
defined('EVENT_ESPRESSO_VERSION') || exit;
10
11
12
13
/**
14
 * Class EspressoShortcode
15
 * base class for all EE shortcode classes
16
 *
17
 * @package       Event Espresso
18
 * @author        Brent Christensen
19
 * @since         $VID:$
20
 */
21
abstract class EspressoShortcode implements ShortcodeInterface
22
{
23
24
    /**
25
     * transient prefix
26
     *
27
     * @type string
28
     */
29
    const CACHE_TRANSIENT_PREFIX = 'ee_sc_';
30
31
    /**
32
     * @var PostRelatedCacheManager $cache_manager
33
     */
34
    private $cache_manager;
35
36
    /**
37
     * true if ShortcodeInterface::initializeShortcode() has been called
38
     * if false, then that will get called before processing
39
     *
40
     * @var boolean $initialized
41
     */
42
    private $initialized = false;
43
44
45
46
    /**
47
     * EspressoShortcode constructor
48
     *
49
     * @param PostRelatedCacheManager $cache_manager
50
     */
51
    public function __construct(PostRelatedCacheManager $cache_manager)
52
    {
53
        $this->cache_manager = $cache_manager;
54
    }
55
56
57
58
    /**
59
     * @return void
60
     */
61
    public function shortcodeHasBeenInitialized()
62
    {
63
        $this->initialized = true;
64
    }
65
66
67
68
    /**
69
     * enqueues scripts then processes the shortcode
70
     *
71
     * @param array $attributes
72
     * @return string
73
     * @throws EE_Error
74
     */
75
    final public function processShortcodeCallback($attributes = array())
76
    {
77
        if ($this instanceof EnqueueAssetsInterface) {
78
            if (is_admin()) {
79
                $this->enqueueAdminScripts();
80
            } else {
81
                $this->enqueueScripts();
82
            }
83
        }
84
        return $this->shortcodeContent(
85
            $this->sanitizeAttributes((array)$attributes)
86
        );
87
    }
88
89
90
91
    /**
92
     * If shortcode caching is enabled for the shortcode,
93
     * and cached results exist, then that will be returned
94
     * else new content will be generated.
95
     * If caching is enabled, then the new content will be cached for later.
96
     *
97
     * @param array $attributes
98
     * @return mixed|string
99
     * @throws EE_Error
100
     */
101
    private function shortcodeContent(array $attributes)
102
    {
103
        $shortcode = $this;
104
        $post_ID = $this->currentPostID();
105
        // something like "SC_EVENTS-123"
106
        $cache_ID = $this->shortcodeCacheID($post_ID);
107
        $this->cache_manager->clearPostRelatedCacheOnUpdate($post_ID, $cache_ID);
108
        return $this->cache_manager->get(
109
            $cache_ID,
110
            // serialized attributes
111
            wp_json_encode($attributes),
112
            // Closure for generating content if cache is expired
113
            function () use ($shortcode, $attributes) {
114
                if($shortcode->initialized === false){
115
                    $shortcode->initializeShortcode();
116
                }
117
                return $shortcode->processShortcode($attributes);
118
            },
119
            // filterable cache expiration set by each shortcode
120
            apply_filters(
121
                'FHEE__EventEspresso_core_services_shortcodes_EspressoShortcode__shortcodeContent__cache_expiration',
122
                $this->cacheExpiration(),
123
                $this->getTag(),
124
                $this
125
            )
126
        );
127
    }
128
129
130
131
    /**
132
     * @return int
133
     * @throws EE_Error
134
     */
135
    private function currentPostID()
136
    {
137
        // try to get EE_Event any way we can
138
        $event = EEH_Event_View::get_event();
139
        // then get some kind of ID
140
        if ($event instanceof \EE_Event) {
141
            $post_ID = $event->ID();
142
        } else {
143
            global $post;
144
            $post_ID = $post->ID;
145
        }
146
        return $post_ID;
147
    }
148
149
150
151
    /**
152
     * @param int $post_ID
153
     * @return string
154
     * @throws EE_Error
155
     */
156
    private function shortcodeCacheID($post_ID)
157
    {
158
        $tag = str_replace('ESPRESSO_', '', $this->getTag());
159
        return "SC_{$tag}-{$post_ID}";
160
    }
161
162
163
164
    /**
165
     * array for defining custom attribute sanitization callbacks,
166
     * where keys match keys in your attributes array,
167
     * and values represent the sanitization function you wish to be applied to that attribute.
168
     * So for example, if you had an integer attribute named "event_id"
169
     * that you wanted to be sanitized using absint(),
170
     * then you would return the following:
171
     *      array('event_id' => 'absint')
172
     * Entering 'skip_sanitization' for the callback value
173
     * means that no sanitization will be applied
174
     * on the assumption that the attribute
175
     * will be sanitized at some point... right?
176
     * You wouldn't pass around unsanitized attributes would you?
177
     * That would be very Tom Foolery of you!!!
178
     *
179
     * @return array
180
     */
181
    protected function customAttributeSanitizationMap()
182
    {
183
        return array();
184
    }
185
186
187
188
    /**
189
     * Performs basic sanitization on shortcode attributes
190
     * Since incoming attributes from the shortcode usage in the WP editor will all be strings,
191
     * most attributes will by default be sanitized using the sanitize_text_field() function.
192
     * This can be overridden using the customAttributeSanitizationMap() method (see above),
193
     * all other attributes would be sanitized using the defaults in the switch statement below
194
     *
195
     * @param array $attributes
196
     * @return array
197
     */
198
    private function sanitizeAttributes(array $attributes)
199
    {
200
        $custom_sanitization = $this->customAttributeSanitizationMap();
201 View Code Duplication
        foreach ($attributes as $key => $value) {
202
            // is a custom sanitization callback specified ?
203
            if (isset($custom_sanitization[$key])) {
204
                $callback = $custom_sanitization[$key];
205
                if ($callback === 'skip_sanitization') {
206
                    $attributes[$key] = $value;
207
                    continue;
208
                }
209
                if (function_exists($callback)) {
210
                    $attributes[$key] = $callback($value);
211
                    continue;
212
                }
213
            }
214
            switch (true) {
215
                case $value === null :
216
                case is_int($value) :
217
                case is_float($value) :
218
                    // typical booleans
219
                case in_array($value, array(true, 'true', '1', 'on', 'yes', false, 'false', '0', 'off', 'no'), true) :
220
                    $attributes[$key] = $value;
221
                    break;
222
                case is_string($value) :
223
                    $attributes[$key] = sanitize_text_field($value);
224
                    break;
225
                case is_array($value) :
226
                    $attributes[$key] = $this->sanitizeAttributes($value);
227
                    break;
228
                default :
229
                    // only remaining data types are Object and Resource
230
                    // which are not allowed as shortcode attributes
231
                    $attributes[$key] = null;
232
                    break;
233
            }
234
        }
235
        return $attributes;
236
    }
237
238
239
240
}
241
// End of file EspressoShortcode.php
242
// Location: EventEspresso\core\services\shortcodes/EspressoShortcode.php