Completed
Branch BUG-10851-events-shortcode (46b271)
by
unknown
22:11 queued 11:10
created

EspressoShortcode   A

Complexity

Total Complexity 25

Size/Duplication

Total Lines 234
Duplicated Lines 14.53 %

Coupling/Cohesion

Components 1
Dependencies 3

Importance

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

9 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 17 4
A shortcodeCacheID() 0 5 1
A customAttributeSanitizationMap() 0 4 1
C sanitizeAttributes() 34 39 11
A initialized() 0 3 1

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