Completed
Branch BUG-11108-ticket-reserved-coun... (144d27)
by
unknown
14:21 queued 17s
created

PersistentAdminNoticeManager::displayNotices()   C

Complexity

Conditions 7
Paths 11

Size

Total Lines 32
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 7
eloc 18
c 0
b 0
f 0
nc 11
nop 0
dl 0
loc 32
rs 6.7272
1
<?php
2
3
namespace EventEspresso\core\services\notifications;
4
5
use DomainException;
6
use EE_Error;
7
use EE_Request;
8
use EventEspresso\core\domain\entities\notifications\PersistentAdminNotice;
9
use EventEspresso\core\domain\services\capabilities\CapabilitiesChecker;
10
use EventEspresso\core\exceptions\InsufficientPermissionsException;
11
use EventEspresso\core\exceptions\InvalidClassException;
12
use EventEspresso\core\exceptions\InvalidDataTypeException;
13
use EventEspresso\core\exceptions\InvalidEntityException;
14
use EventEspresso\core\exceptions\InvalidInterfaceException;
15
use EventEspresso\core\services\collections\Collection;
16
use EventEspresso\core\services\loaders\LoaderFactory;
17
use Exception;
18
use InvalidArgumentException;
19
20
defined('EVENT_ESPRESSO_VERSION') || exit;
21
22
23
24
/**
25
 * Class PersistentAdminNoticeManager
26
 * class for managing the loading, display, and storage of PersistentAdminNotice objects
27
 *
28
 * @package Event Espresso
29
 * @author  Brent Christensen
30
 * @since   4.9.27
31
 */
32
class PersistentAdminNoticeManager
33
{
34
35
    const WP_OPTION_KEY = 'ee_pers_admin_notices';
36
37
    /**
38
     * @var Collection|PersistentAdminNotice[] $notice_collection
39
     */
40
    private $notice_collection;
41
42
    /**
43
     * if AJAX is not enabled, then the return URL will be used for redirecting back to the admin page where the
44
     * persistent admin notice was displayed, and ultimately dismissed from.
45
     *
46
     * @var string $return_url
47
     */
48
    private $return_url;
49
50
    /**
51
     * @var CapabilitiesChecker $capabilities_checker
52
     */
53
    private $capabilities_checker;
54
55
    /**
56
     * @var EE_Request $request
57
     */
58
    private $request;
59
60
61
62
    /**
63
     * PersistentAdminNoticeManager constructor
64
     *
65
     * @param string              $return_url  where to  redirect to after dismissing notices
66
     * @param CapabilitiesChecker $capabilities_checker
67
     * @param EE_Request          $request
68
     * @throws InvalidDataTypeException
69
     */
70
    public function __construct($return_url = '', CapabilitiesChecker $capabilities_checker, EE_Request $request)
71
    {
72
        $this->setReturnUrl($return_url);
73
        $this->capabilities_checker = $capabilities_checker;
74
        $this->request              = $request;
75
        // setup up notices at priority 9 because `EE_Admin::display_admin_notices()` runs at priority 10,
76
        // and we want to retrieve and generate any nag notices at the last possible moment
77
        add_action('admin_notices', array($this, 'displayNotices'), 9);
78
        add_action('network_admin_notices', array($this, 'displayNotices'), 9);
79
        add_action('wp_ajax_dismiss_ee_nag_notice', array($this, 'dismissNotice'));
80
        add_action('shutdown', array($this, 'registerAndSaveNotices'), 998);
81
    }
82
83
84
85
    /**
86
     * @param string $return_url
87
     * @throws InvalidDataTypeException
88
     */
89
    public function setReturnUrl($return_url)
90
    {
91
        if (! is_string($return_url)) {
92
            throw new InvalidDataTypeException('$return_url', $return_url, 'string');
93
        }
94
        $this->return_url = $return_url;
95
    }
96
97
98
99
    /**
100
     * @return Collection
101
     * @throws InvalidEntityException
102
     * @throws InvalidInterfaceException
103
     * @throws InvalidDataTypeException
104
     * @throws DomainException
105
     */
106
    protected function getPersistentAdminNoticeCollection()
107
    {
108
        if (! $this->notice_collection instanceof Collection) {
109
            $this->notice_collection = new Collection(
110
                'EventEspresso\core\domain\entities\notifications\PersistentAdminNotice'
111
            );
112
            $this->retrieveStoredNotices();
113
            $this->registerNotices();
114
        }
115
        return $this->notice_collection;
116
    }
117
118
119
120
    /**
121
     * generates PersistentAdminNotice objects for all non-dismissed notices saved to the db
122
     *
123
     * @return void
124
     * @throws InvalidEntityException
125
     * @throws DomainException
126
     * @throws InvalidDataTypeException
127
     */
128
    protected function retrieveStoredNotices()
129
    {
130
        $persistent_admin_notices = get_option(PersistentAdminNoticeManager::WP_OPTION_KEY, array());
131
        // \EEH_Debug_Tools::printr($persistent_admin_notices, '$persistent_admin_notices', __FILE__, __LINE__);
132
        if (! empty($persistent_admin_notices)) {
133
            foreach ($persistent_admin_notices as $name => $details) {
134
                if (is_array($details)) {
135
                    if (
136
                        ! isset(
137
                            $details['message'],
138
                            $details['capability'],
139
                            $details['cap_context'],
140
                            $details['dismissed']
141
                        )
142
                    ) {
143
                        throw new DomainException(
144
                            sprintf(
145
                                esc_html__(
146
                                    'The "%1$s" PersistentAdminNotice could not be retrieved from the database.',
147
                                    'event_espresso'
148
                                ),
149
                                $name
150
                            )
151
                        );
152
                    }
153
                    // new format for nag notices
154
                    $this->notice_collection->add(
155
                        new PersistentAdminNotice(
156
                            $name,
157
                            $details['message'],
158
                            false,
159
                            $details['capability'],
160
                            $details['cap_context'],
161
                            $details['dismissed']
162
                        ),
163
                        $name
164
                    );
165
                } else {
166
                    try {
167
                        // old nag notices, that we want to convert to the new format
168
                        $this->notice_collection->add(
169
                            new PersistentAdminNotice(
170
                                $name,
171
                                (string)$details,
172
                                false,
173
                                '',
174
                                '',
175
                                empty($details)
176
                            ),
177
                            $name
178
                        );
179
                    } catch (Exception $e) {
180
                        EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__);
181
                    }
182
                }
183
                // each notice will self register when the action hook in registerNotices is triggered
184
            }
185
        }
186
    }
187
188
189
190
    /**
191
     * exposes the Persistent Admin Notice Collection via an action
192
     * so that PersistentAdminNotice objects can be added and/or removed
193
     * without compromising the actual collection like a filter would
194
     */
195
    protected function registerNotices()
196
    {
197
        do_action(
198
            'AHEE__EventEspresso_core_services_notifications_PersistentAdminNoticeManager__registerNotices',
199
            $this->notice_collection
200
        );
201
    }
202
203
204
205
    /**
206
     * @throws DomainException
207
     * @throws InvalidClassException
208
     * @throws InvalidDataTypeException
209
     * @throws InvalidInterfaceException
210
     * @throws InvalidEntityException
211
     */
212
    public function displayNotices()
213
    {
214
        $this->notice_collection = $this->getPersistentAdminNoticeCollection();
215
        if ($this->notice_collection->hasObjects()) {
216
            $enqueue_assets = false;
217
            // and display notices
218
            foreach ($this->notice_collection as $persistent_admin_notice) {
219
                /** @var PersistentAdminNotice $persistent_admin_notice */
220
                // don't display notices that have already been dismissed
221
                if ($persistent_admin_notice->getDismissed()) {
222
                    continue;
223
                }
224
                try {
225
                    $this->capabilities_checker->processCapCheck(
226
                        $persistent_admin_notice->getCapCheck()
227
                    );
228
                } catch (InsufficientPermissionsException $e) {
229
                    // user does not have required cap, so skip to next notice
230
                    // and just eat the exception - nom nom nom nom
231
                    continue;
232
                }
233
                if ($persistent_admin_notice->getMessage() === '') {
234
                    continue;
235
                }
236
                $this->displayPersistentAdminNotice($persistent_admin_notice);
237
                $enqueue_assets = true;
238
            }
239
            if ($enqueue_assets) {
240
                $this->enqueueAssets();
241
            }
242
        }
243
    }
244
245
246
247
    /**
248
     * does what it's named
249
     *
250
     * @return void
251
     */
252
    public function enqueueAssets()
253
    {
254
        wp_register_script(
255
            'espresso_core',
256
            EE_GLOBAL_ASSETS_URL . 'scripts/espresso_core.js',
257
            array('jquery'),
258
            EVENT_ESPRESSO_VERSION,
259
            true
260
        );
261
        wp_register_script(
262
            'ee_error_js',
263
            EE_GLOBAL_ASSETS_URL . 'scripts/EE_Error.js',
264
            array('espresso_core'),
265
            EVENT_ESPRESSO_VERSION,
266
            true
267
        );
268
        wp_localize_script(
269
            'ee_error_js',
270
            'ee_dismiss',
271
            array(
272
                'return_url'    => urlencode($this->return_url),
273
                'ajax_url'      => WP_AJAX_URL,
274
                'unknown_error' => esc_html__(
275
                    'An unknown error has occurred on the server while attempting to dismiss this notice.',
276
                    'event_espresso'
277
                ),
278
            )
279
        );
280
        wp_enqueue_script('ee_error_js');
281
    }
282
283
284
285
    /**
286
     * displayPersistentAdminNoticeHtml
287
     *
288
     * @param  PersistentAdminNotice $persistent_admin_notice
289
     */
290
    protected function displayPersistentAdminNotice(PersistentAdminNotice $persistent_admin_notice)
291
    {
292
        // used in template
293
        $persistent_admin_notice_name    = $persistent_admin_notice->getName();
294
        $persistent_admin_notice_message = $persistent_admin_notice->getMessage();
295
        require EE_TEMPLATES . DS . 'notifications' . DS . 'persistent_admin_notice.template.php';
296
    }
297
298
299
300
    /**
301
     * dismissNotice
302
     *
303
     * @param string $pan_name the name, or key of the Persistent Admin Notice to be dismissed
304
     * @param bool   $purge    if true, then delete it from the db
305
     * @param bool   $return   forget all of this AJAX or redirect nonsense, and just return
306
     * @return void
307
     * @throws InvalidEntityException
308
     * @throws InvalidInterfaceException
309
     * @throws InvalidDataTypeException
310
     * @throws DomainException
311
     */
312
    public function dismissNotice($pan_name = '', $purge = false, $return = false)
313
    {
314
        $pan_name                = $this->request->get('ee_nag_notice', $pan_name);
315
        $this->notice_collection = $this->getPersistentAdminNoticeCollection();
316
        if (! empty($pan_name) && $this->notice_collection->has($pan_name)) {
317
            /** @var PersistentAdminNotice $persistent_admin_notice */
318
            $persistent_admin_notice = $this->notice_collection->get($pan_name);
319
            $persistent_admin_notice->setDismissed(true);
320
            $persistent_admin_notice->setPurge($purge);
321
            $this->saveNotices();
322
        }
323
        if ($return) {
324
            return;
325
        }
326
        if ($this->request->ajax) {
327
            // grab any notices and concatenate into string
328
            echo wp_json_encode(
329
                array(
330
                    'errors' => implode('<br />', EE_Error::get_notices(false)),
331
                )
332
            );
333
            exit();
334
        }
335
        // save errors to a transient to be displayed on next request (after redirect)
336
        EE_Error::get_notices(false, true);
337
        wp_safe_redirect(
338
            urldecode(
339
                $this->request->get('return_url', '')
340
            )
341
        );
342
    }
343
344
345
346
    /**
347
     * saveNotices
348
     *
349
     * @throws DomainException
350
     * @throws InvalidDataTypeException
351
     * @throws InvalidInterfaceException
352
     * @throws InvalidEntityException
353
     */
354
    public function saveNotices()
355
    {
356
        $this->notice_collection = $this->getPersistentAdminNoticeCollection();
357
        if ($this->notice_collection->hasObjects()) {
358
            $persistent_admin_notices = get_option(PersistentAdminNoticeManager::WP_OPTION_KEY, array());
359
            //maybe initialize persistent_admin_notices
360
            if (empty($persistent_admin_notices)) {
361
                add_option(PersistentAdminNoticeManager::WP_OPTION_KEY, array(), '', 'no');
362
            }
363
            foreach ($this->notice_collection as $persistent_admin_notice) {
364
                // are we deleting this notice ?
365
                if ($persistent_admin_notice->getPurge()) {
366
                    unset($persistent_admin_notices[$persistent_admin_notice->getName()]);
367
                } else {
368
                    /** @var PersistentAdminNotice $persistent_admin_notice */
369
                    $persistent_admin_notices[$persistent_admin_notice->getName()] = array(
370
                        'message'     => $persistent_admin_notice->getMessage(),
371
                        'capability'  => $persistent_admin_notice->getCapability(),
372
                        'cap_context' => $persistent_admin_notice->getCapContext(),
373
                        'dismissed'   => $persistent_admin_notice->getDismissed(),
374
                    );
375
                }
376
            }
377
            update_option(PersistentAdminNoticeManager::WP_OPTION_KEY, $persistent_admin_notices);
378
        }
379
    }
380
381
382
383
    /**
384
     * @throws DomainException
385
     * @throws InvalidDataTypeException
386
     * @throws InvalidEntityException
387
     * @throws InvalidInterfaceException
388
     */
389
    public function registerAndSaveNotices()
390
    {
391
        $this->getPersistentAdminNoticeCollection();
392
        $this->registerNotices();
393
        $this->saveNotices();
394
        add_filter(
395
            'PersistentAdminNoticeManager__registerAndSaveNotices__complete',
396
            '__return_true'
397
        );
398
    }
399
400
401
    /**
402
     * @throws DomainException
403
     * @throws InvalidDataTypeException
404
     * @throws InvalidEntityException
405
     * @throws InvalidInterfaceException
406
     * @throws InvalidArgumentException
407
     */
408
    public static function loadRegisterAndSaveNotices()
409
    {
410
        /** @var PersistentAdminNoticeManager $persistent_admin_notice_manager */
411
        $persistent_admin_notice_manager = LoaderFactory::getLoader()->getShared(
412
            'EventEspresso\core\services\notifications\PersistentAdminNoticeManager'
413
        );
414
        // if shutdown has already run, then call registerAndSaveNotices() manually
415
        if(did_action('shutdown')){
416
            $persistent_admin_notice_manager->registerAndSaveNotices();
417
        }
418
    }
419
420
421
}
422
// End of file PersistentAdminNoticeManager.php
423
// Location: EventEspresso\core\services\notifications/PersistentAdminNoticeManager.php
424