Passed
Push — master ( c29de4...7571e0 )
by Paul
04:24
created

Application   B

Complexity

Total Complexity 50

Size/Duplication

Total Lines 354
Duplicated Lines 0 %

Test Coverage

Coverage 38.89%

Importance

Changes 6
Bugs 2 Features 2
Metric Value
eloc 139
c 6
b 2
f 2
dl 0
loc 354
ccs 56
cts 144
cp 0.3889
rs 8.4
wmc 50

26 Methods

Rating   Name   Duplication   Size   Complexity  
A build() 0 5 1
A __construct() 0 11 1
A activate() 0 4 1
A can() 0 3 1
A registerReviewTypes() 0 5 1
A themePath() 0 3 1
A path() 0 8 2
A registerLanguages() 0 4 1
A unscheduleCronJob() 0 3 1
A register() 0 11 3
A isAdmin() 0 3 2
A scheduleCronJob() 0 4 2
A registerAddons() 0 3 1
A url() 0 4 1
A render() 0 11 2
A config() 0 7 2
A getPermission() 0 28 4
A version() 0 18 5
A deactivate() 0 3 1
A hasPermission() 0 4 3
A constant() 0 6 2
A getDefaults() 0 6 2
A init() 0 4 1
A setDefaults() 0 5 2
A file() 0 14 4
A catchFatalError() 0 8 3

How to fix   Complexity   

Complex Class

Complex classes like Application 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.

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

1
<?php
2
3
namespace GeminiLabs\SiteReviews;
4
5
use GeminiLabs\SiteReviews\Database\DefaultsManager;
6
use GeminiLabs\SiteReviews\Helpers\Arr;
7
use GeminiLabs\SiteReviews\Helpers\Str;
8
9
/**
10
 * @property string $capability
11
 * @property string $cron_event
12
 * @property string $id
13
 * @property string $paged_query_var
14
 * @property string $post_type
15
 * @property string $prefix
16
 * @property string $taxonomy
17
 */
18
final class Application extends Container
19
{
20
    const CAPABILITY = 'edit_others_posts';
21
    const CRON_EVENT = 'site-reviews/schedule/session/purge';
22
    const ID = 'site-reviews';
23
    const PAGED_QUERY_VAR = 'reviews-page';
24
    const POST_TYPE = 'site-review';
25
    const PREFIX = 'glsr_';
26
    const TAXONOMY = 'site-review-category';
27
28
    public $addons = [];
29
    public $defaults;
30
    public $deprecated = [];
31
    public $file;
32
    public $languages;
33
    public $mceShortcodes = []; //defined elsewhere
34
    public $name;
35
    public $postTypeColumns = []; // defined elsewhere
36
    public $reviewTypes;
37
    public $schemas = []; //defined elsewhere
38
    public $version;
39
40
    public function __construct()
41
    {
42
        static::$instance = $this;
43
        $this->file = realpath(trailingslashit(dirname(__DIR__)).static::ID.'.php');
44
        $plugin = get_file_data($this->file, [
45
            'languages' => 'Domain Path',
46
            'name' => 'Plugin Name',
47
            'version' => 'Version',
48
        ], 'plugin');
49
        array_walk($plugin, function ($value, $key) {
50
            $this->$key = $value;
51
        });
52
    }
53
54
    /**
55
     * @return void
56
     */
57 7
    public function activate()
58
    {
59 7
        $this->scheduleCronJob();
60 7
        add_option(static::PREFIX.'activated', true);
61 7
    }
62
63
    /**
64
     * @param string $view
65
     * @return string
66
     */
67 7
    public function build($view, array $data = [])
68
    {
69 7
        ob_start();
70 7
        $this->render($view, $data);
71 7
        return ob_get_clean();
72
    }
73
74
    /**
75
     * @param string $capability
76
     * @return bool
77
     */
78 1
    public function can($capability)
79
    {
80 1
        return $this->make(Role::class)->can($capability);
81
    }
82
83
    /**
84
     * @return void
85
     */
86
    public function catchFatalError()
87
    {
88
        $error = error_get_last();
89
        if (E_ERROR !== Arr::get($error, 'type') 
90
            || !Str::contains(Arr::get($error, 'message'), $this->path())) {
91
            return;
92
        }
93
        glsr_log()->error($error['message']);
94
    }
95
96
    /**
97
     * @param string $name
98
     * @return array
99
     */
100 7
    public function config($name)
101
    {
102 7
        $configFile = $this->path('config/'.$name.'.php');
103 7
        $config = file_exists($configFile)
104 7
            ? include $configFile
105 7
            : [];
106 7
        return apply_filters('site-reviews/config/'.$name, $config);
107
    }
108
109
    /**
110
     * @param string $property
111
     * @return string
112
     */
113 7
    public function constant($property, $className = 'static')
114
    {
115 7
        $constant = $className.'::'.$property;
116 7
        return defined($constant)
117 7
            ? apply_filters('site-reviews/const/'.$property, constant($constant))
118 7
            : '';
119
    }
120
121
    /**
122
     * @return void
123
     */
124
    public function deactivate()
125
    {
126
        $this->unscheduleCronJob();
127
    }
128
129
    /**
130
     * @param string $view
131
     * @return void|string
132
     */
133 7
    public function file($view)
134
    {
135 7
        $view.= '.php';
136 7
        $filePaths = [];
137 7
        if (Str::startsWith('templates/', $view)) {
138 7
            $filePaths[] = $this->themePath(Str::removePrefix('templates/', $view));
139
        }
140 7
        $filePaths[] = $this->path($view);
141 7
        $filePaths[] = $this->path('views/'.$view);
142 7
        foreach ($filePaths as $file) {
143 7
            if (!file_exists($file)) {
144 7
                continue;
145
            }
146 7
            return $file;
147
        }
148
    }
149
150
    /**
151
     * @return array
152
     */
153
    public function getDefaults()
154
    {
155
        if (empty($this->defaults)) {
156
            $this->defaults = $this->make(DefaultsManager::class)->get();
157
        }
158
        return apply_filters('site-reviews/get/defaults', $this->defaults);
159
    }
160
161
    /**
162
     * @param string $page
163
     * @param string $tab
164
     * @return string
165
     */
166
    public function getPermission($page = '', $tab = 'index')
167
    {
168
        $fallback = 'edit_posts';
169
        $permissions = [
170
            'addons' => 'install_plugins',
171
            'documentation' => [
172
                'faq' => 'edit_others_posts',
173
                'functions' => 'manage_options',
174
                'hooks' => 'edit_others_posts',
175
                'index' => 'edit_posts',
176
                'support' => 'edit_others_posts',
177
            ],
178
            'settings' => 'manage_options',
179
            'tools' => [
180
                'console' => 'edit_others_posts',
181
                'general' => 'edit_others_posts',
182
                'index' => 'edit_others_posts',
183
                'sync' => 'manage_options',
184
                'system-info' => 'edit_others_posts',
185
            ]
186
        ];
187
        $permission = Arr::get($permissions, $page, $fallback);
188
        if (is_array($permission)) {
189
            $permission = Arr::get($permission, $tab, $fallback);
190
        }
191
        return empty($permission) || !is_string($permission)
192
            ? $fallback
193
            : $permission;
194
    }
195
196
    /**
197
     * @param string $page
198
     * @param string $tab
199
     * @return bool
200
     */
201
    public function hasPermission($page = '', $tab = 'index')
202
    {
203
        $isAdmin = $this->isAdmin();
204
        return !$isAdmin || ($isAdmin && $this->can($this->getPermission($page, $tab)));
205
    }
206
207
    /**
208
     * @return void
209
     */
210
    public function init()
211
    {
212
        $this->make(Actions::class)->run();
213
        $this->make(Filters::class)->run();
214
    }
215
216
    /**
217
     * @return bool
218
     */
219
    public function isAdmin()
220
    {
221
        return is_admin() && !wp_doing_ajax();
222
    }
223
224
    /**
225
     * @param string $file
226
     * @return string
227
     */
228 7
    public function path($file = '', $realpath = true)
229
    {
230 7
        $path = plugin_dir_path($this->file);
231 7
        if (!$realpath) {
232
            $path = trailingslashit(WP_PLUGIN_DIR).basename(dirname($this->file));
233
        }
234 7
        $path = trailingslashit($path).ltrim(trim($file), '/');
235 7
        return apply_filters('site-reviews/path', $path, $file);
236
    }
237
238
    /**
239
     * @param object $addon
240
     * @return void
241
     */
242
    public function register($addon)
243
    {
244
        try {
245
            $reflection = new \ReflectionClass($addon);
246
            if ($id = $reflection->getConstant('ID')) {
247
                $this->addons[] = $id;
248
                $this->bind($id, $addon);
249
                $addon->init();
250
            }
251
        } catch(\ReflectionException $e) {
252
            glsr_log()->error('Attempted to register an invalid addon.');
253
        }
254
    }
255
256
    /**
257
     * @return void
258
     */
259
    public function registerAddons()
260
    {
261
        do_action('site-reviews/addon/register', $this);
262
    }
263
264
    /**
265
     * @return void
266
     */
267
    public function registerLanguages()
268
    {
269
        load_plugin_textdomain(static::ID, false,
270
            trailingslashit(plugin_basename($this->path()).'/'.$this->languages)
271
        );
272
    }
273
274
    /**
275
     * @return void
276
     */
277
    public function registerReviewTypes()
278
    {
279
        $types = apply_filters('site-reviews/addon/types', []);
280
        $this->reviewTypes = wp_parse_args($types, [
281
            'local' => __('Local', 'site-reviews'),
282
        ]);
283
    }
284
285
    /**
286
     * @param string $view
287
     * @return void
288
     */
289 7
    public function render($view, array $data = [])
290
    {
291 7
        $view = apply_filters('site-reviews/render/view', $view, $data);
292 7
        $file = apply_filters('site-reviews/views/file', $this->file($view), $view, $data);
293 7
        if (!file_exists($file)) {
294
            glsr_log()->error('File not found: '.$file);
295
            return;
296
        }
297 7
        $data = apply_filters('site-reviews/views/data', $data, $view);
298 7
        extract($data);
299 7
        include $file;
300 7
    }
301
302
    /**
303
     * @return void
304
     */
305 7
    public function scheduleCronJob()
306
    {
307 7
        if (false === wp_next_scheduled(static::CRON_EVENT)) {
308 7
            wp_schedule_event(time(), 'twicedaily', static::CRON_EVENT);
309
        }
310 7
    }
311
312
    /**
313
     * @return void
314
     */
315 1
    public function setDefaults()
316
    {
317 1
        if (get_option(static::PREFIX.'activated')) {
318 1
            $this->make(DefaultsManager::class)->set();
319 1
            delete_option(static::PREFIX.'activated');
320
        }
321 1
    }
322
323
    /**
324
     * @param string $file
325
     * @return string
326
     */
327 7
    public function themePath($file = '')
328
    {
329 7
        return get_stylesheet_directory().'/'.static::ID.'/'.ltrim(trim($file), '/');
330
    }
331
332
    /**
333
     * @return void
334
     */
335
    public function unscheduleCronJob()
336
    {
337
        wp_unschedule_event(intval(wp_next_scheduled(static::CRON_EVENT)), static::CRON_EVENT);
338
    }
339
340
    /**
341
     * @param string $path
342
     * @return string
343
     */
344
    public function url($path = '')
345
    {
346
        $url = esc_url(plugin_dir_url($this->file).ltrim(trim($path), '/'));
347
        return apply_filters('site-reviews/url', $url, $path);
348
    }
349
350
    /**
351
     * @param string $versionLevel
352
     * @return string
353
     */
354
    public function version($versionLevel = '')
355
    {
356
        $pattern = '/^v?(\d{1,5})(\.\d++)?(\.\d++)?(.+)?$/i';
357
        preg_match($pattern, $this->version, $matches);
358
        switch ($versionLevel) {
359
            case 'major':
360
                $version = Arr::get($matches, 1);
361
                break;
362
            case 'minor':
363
                $version = Arr::get($matches, 1).Arr::get($matches, 2);
364
                break;
365
            case 'patch':
366
                $version = Arr::get($matches, 1).Arr::get($matches, 2).Arr::get($matches, 3);
367
                break;
368
        }
369
        return empty($version)
370
            ? $this->version
371
            : $version;
372
    }
373
}
374