Completed
Branch BUG/get-related-entities-for-i... (dc8d44)
by
unknown
18:53 queued 09:37
created

EED_Batch::batch_continue()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7

Duplication

Lines 7
Ratio 100 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 0
dl 7
loc 7
rs 10
c 0
b 0
f 0
1
<?php
2
3
use EventEspresso\core\domain\services\assets\CoreAssetManager;
4
use EventEspresso\core\exceptions\InvalidDataTypeException;
5
use EventEspresso\core\exceptions\InvalidInterfaceException;
6
use EventEspresso\core\services\loaders\LoaderFactory;
7
use EventEspresso\core\services\loaders\LoaderInterface;
8
9
define('BATCH_URL', plugin_dir_url(__FILE__));
10
11
/**
12
 *
13
 * Class EED_Batch
14
 *
15
 * Module for running batch jobs, which uses the library files in event-espresso-core/core/libraries/batch.
16
 * So will respond on the frontend at "{site_url}?espresso_batch&batch={file|job}",
17
 * or in the admin at "{site_url}/wp-admin?page=espresso_batch&batch={file|job}" (use whichever will make your user
18
 * happier, note that the admin one requires the user to be able to access the admin, and the frontend one is disabled
19
 * until specifically enabled via a filter).
20
 *
21
 *
22
 *
23
 * @package               Event Espresso
24
 * @subpackage
25
 * @author                Mike Nelson
26
 * @since                 4.8.30.rc.007
27
 *
28
 */
29
class EED_Batch extends EED_Module
30
{
31
32
    /**
33
     * Possibly value for $_REQUEST[ 'batch' ]. Indicates to run a job that
34
     * processes data only
35
     */
36
    const batch_job = 'job';
37
    /**
38
     * Possibly value for $_REQUEST[ 'batch' ]. Indicates to run a job that
39
     * produces a file for download
40
     */
41
    const batch_file_job = 'file';
42
    /**
43
     * Possibly value for $_REQUEST[ 'batch' ]. Indicates this request is NOT
44
     * for a batch job. It's the same as not providing the $_REQUEST[ 'batch' ]
45
     * at all
46
     */
47
    const batch_not_job = 'none';
48
49
    /**
50
     *
51
     * @var string 'file', or 'job', or false to indicate its not a batch request at all
52
     */
53
    protected $_batch_request_type = null;
54
55
    /**
56
     * Because we want to use the response in both the localized JS and in the body
57
     * we need to make this response available between method calls
58
     *
59
     * @var \EventEspressoBatchRequest\Helpers\JobStepResponse
60
     */
61
    protected $_job_step_response = null;
62
63
    /**
64
     * @var LoaderInterface
65
     */
66
    protected $loader;
67
68
    /**
69
     * Gets the batch instance
70
     *
71
     * @return EED_Batch
72
     */
73
    public static function instance()
74
    {
75
        return self::get_instance();
76
    }
77
78
    /**
79
     * Sets hooks to enable batch jobs on the frontend. Disabled by default
80
     * because it's an attack vector and there are currently no implementations
81
     */
82
    public static function set_hooks()
83
    {
84
        // because this is a possibel attack vector, let's have this disabled until
85
        // we at least have a real use for it on the frontend
86
        if (apply_filters('FHEE__EED_Batch__set_hooks__enable_frontend_batch', false)) {
87
            add_action('wp_enqueue_scripts', array(self::instance(), 'enqueue_scripts'));
88
            add_filter('template_include', array(self::instance(), 'override_template'), 99);
89
        }
90
    }
91
92
    /**
93
     * Initializes some hooks for the admin in order to run batch jobs
94
     */
95
    public static function set_hooks_admin()
96
    {
97
        add_action('admin_menu', array(self::instance(), 'register_admin_pages'));
98
        add_action('admin_enqueue_scripts', array(self::instance(), 'enqueue_scripts'));
99
100
        // ajax
101
        add_action('wp_ajax_espresso_batch_continue', array(self::instance(), 'batch_continue'));
102
        add_action('wp_ajax_espresso_batch_cleanup', array(self::instance(), 'batch_cleanup'));
103
        add_action('wp_ajax_nopriv_espresso_batch_continue', array(self::instance(), 'batch_continue'));
104
        add_action('wp_ajax_nopriv_espresso_batch_cleanup', array(self::instance(), 'batch_cleanup'));
105
    }
106
107
    /**
108
     * @since 4.9.80.p
109
     * @return LoaderInterface
110
     * @throws InvalidArgumentException
111
     * @throws InvalidDataTypeException
112
     * @throws InvalidInterfaceException
113
     */
114
    protected function getLoader()
115
    {
116
        if (!$this->loader instanceof LoaderInterface) {
117
            $this->loader = LoaderFactory::getLoader();
118
        }
119
        return $this->loader;
120
    }
121
122
    /**
123
     * Enqueues batch scripts on the frontend or admin, and creates a job
124
     */
125
    public function enqueue_scripts()
126
    {
127
        if (isset($_REQUEST['espresso_batch'])
128
            ||
129
            (
130
                isset($_REQUEST['page'])
131
                && $_REQUEST['page'] == 'espresso_batch'
132
            )
133
        ) {
134
            if (! isset($_REQUEST['default_nonce']) || ! wp_verify_nonce($_REQUEST['default_nonce'], 'default_nonce')) {
135
                wp_die(esc_html__('The link you clicked to start the batch job has expired. Please go back and refresh the previous page.', 'event_espresso'));
136
            }
137
            switch ($this->batch_request_type()) {
138
                case self::batch_job:
139
                    $this->enqueue_scripts_styles_batch_create();
140
                    break;
141
                case self::batch_file_job:
142
                    $this->enqueue_scripts_styles_batch_file_create();
143
                    break;
144
            }
145
        }
146
    }
147
148
    /**
149
     * Create a batch job, enqueues a script to run it, and localizes some data for it
150
     */
151
    public function enqueue_scripts_styles_batch_create()
152
    {
153
        $job_response = $this->_enqueue_batch_job_scripts_and_styles_and_start_job();
154
        wp_enqueue_script(
155
            'batch_runner_init',
156
            BATCH_URL . 'assets/batch_runner_init.js',
157
            array('batch_runner'),
158
            EVENT_ESPRESSO_VERSION,
159
            true
160
        );
161
        wp_localize_script('batch_runner_init', 'ee_job_response', $job_response->to_array());
162
        wp_localize_script(
163
            'batch_runner_init',
164
            'ee_job_i18n',
165
            array(
166
                'return_url' => $_REQUEST['return_url'],
167
            )
168
        );
169
    }
170
171
    /**
172
     * Creates a batch job which will download a file, enqueues a script to run the job, and localizes some data for it
173
     */
174
    public function enqueue_scripts_styles_batch_file_create()
175
    {
176
        // creates a job based on the request variable
177
        $job_response = $this->_enqueue_batch_job_scripts_and_styles_and_start_job();
178
        wp_enqueue_script(
179
            'batch_file_runner_init',
180
            BATCH_URL . 'assets/batch_file_runner_init.js',
181
            array('batch_runner'),
182
            EVENT_ESPRESSO_VERSION,
183
            true
184
        );
185
        wp_localize_script('batch_file_runner_init', 'ee_job_response', $job_response->to_array());
186
        wp_localize_script(
187
            'batch_file_runner_init',
188
            'ee_job_i18n',
189
            array(
190
                'download_and_redirecting' => sprintf(
191
                    __('File Generation complete. Downloading, and %1$sredirecting%2$s...', 'event_espresso'),
192
                    '<a href="' . $_REQUEST['return_url'] . '">',
193
                    '</a>'
194
                ),
195
                'return_url'               => $_REQUEST['return_url'],
196
            )
197
        );
198
    }
199
200
    /**
201
     * Enqueues scripts and styles common to any batch job, and creates
202
     * a job from the request data, and stores the response in the
203
     * $this->_job_step_response property
204
     *
205
     * @return \EventEspressoBatchRequest\Helpers\JobStepResponse
206
     */
207
    protected function _enqueue_batch_job_scripts_and_styles_and_start_job()
208
    {
209
        // just copy the bits of EE admin's eei18n that we need in the JS
210
        EE_Registry::$i18n_js_strings['batchJobError'] =  esc_html__(
211
            'An error occurred and the job has been stopped. Please refresh the page to try again.',
212
            'event_espresso'
213
        );
214
        wp_register_script(
215
            'progress_bar',
216
            EE_PLUGIN_DIR_URL . 'core/libraries/batch/Assets/progress_bar.js',
217
            array('jquery'),
218
            EVENT_ESPRESSO_VERSION,
219
            true
220
        );
221
        wp_enqueue_style(
222
            'progress_bar',
223
            EE_PLUGIN_DIR_URL . 'core/libraries/batch/Assets/progress_bar.css',
224
            array(),
225
            EVENT_ESPRESSO_VERSION
226
        );
227
        wp_enqueue_script(
228
            'batch_runner',
229
            EE_PLUGIN_DIR_URL . 'core/libraries/batch/Assets/batch_runner.js',
230
            array('progress_bar', CoreAssetManager::JS_HANDLE_CORE),
231
            EVENT_ESPRESSO_VERSION,
232
            true
233
        );
234
        $job_handler_classname = stripslashes($_GET['job_handler']);
235
        $request_data = array_diff_key(
236
            $_REQUEST,
237
            array_flip(array('action', 'page', 'ee', 'batch'))
238
        );
239
        $batch_runner = $this->getLoader()->getShared('EventEspressoBatchRequest\BatchRequestProcessor');
240
        // eg 'EventEspressoBatchRequest\JobHandlers\RegistrationsReport'
241
        $job_response = $batch_runner->create_job($job_handler_classname, $request_data);
242
        // remember the response for later. We need it to display the page body
243
        $this->_job_step_response = $job_response;
244
        return $job_response;
245
    }
246
247
    /**
248
     * If we are doing a frontend batch job, this makes it so WP shows our template's HTML
249
     *
250
     * @param string $template
251
     * @return string
252
     */
253
    public function override_template($template)
254
    {
255
        if (isset($_REQUEST['espresso_batch']) && isset($_REQUEST['batch'])) {
256
            return EE_MODULES . 'batch' . DS . 'templates' . DS . 'batch_frontend_wrapper.template.html';
257
        }
258
        return $template;
259
    }
260
261
    /**
262
     * Adds an admin page which doesn't appear in the admin menu
263
     */
264
    public function register_admin_pages()
265
    {
266
        add_submenu_page(
267
            '', // parent slug. we don't want this to actually appear in the menu
268
            __('Batch Job', 'event_espresso'), // page title
269
            'n/a', // menu title
270
            'read', // we want this page to actually be accessible to anyone,
271
            'espresso_batch', // menu slug
272
            array(self::instance(), 'show_admin_page')
273
        );
274
    }
275
276
    /**
277
     * Renders the admin page, after most of the work was already done during enqueuing scripts
278
     * of creating the job and localizing some data
279
     */
280
    public function show_admin_page()
281
    {
282
        echo EEH_Template::locate_template(
283
            EE_MODULES . 'batch' . DS . 'templates' . DS . 'batch_wrapper.template.html',
284
            array('batch_request_type' => $this->batch_request_type())
285
        );
286
    }
287
288
    /**
289
     * Receives ajax calls for continuing a job
290
     */
291 View Code Duplication
    public function batch_continue()
292
    {
293
        $job_id = sanitize_text_field($_REQUEST['job_id']);
294
        $batch_runner = $this->getLoader()->getShared('EventEspressoBatchRequest\BatchRequestProcessor');
295
        $response_obj = $batch_runner->continue_job($job_id);
296
        $this->_return_json($response_obj->to_array());
297
    }
298
299
    /**
300
     * Receives the ajax call to cleanup a job
301
     *
302
     * @return type
303
     */
304 View Code Duplication
    public function batch_cleanup()
305
    {
306
        $job_id = sanitize_text_field($_REQUEST['job_id']);
307
        $batch_runner = $this->getLoader()->getShared('EventEspressoBatchRequest\BatchRequestProcessor');
308
        $response_obj = $batch_runner->cleanup_job($job_id);
309
        $this->_return_json($response_obj->to_array());
310
    }
311
312
313
    /**
314
     * Returns a json response
315
     *
316
     * @param array $data The data we want to send echo via in the JSON response's "data" element
317
     *
318
     * The returned json object is created from an array in the following format:
319
     * array(
320
     *    'notices' => '', // - contains any EE_Error formatted notices
321
     *    'data' => array() //this can be any key/value pairs that a method returns for later json parsing by the js.
322
     *    We're also going to include the template args with every package (so js can pick out any specific template
323
     *    args that might be included in here)
324
     *    'isEEajax' => true,//indicates this is a response from EE
325
     * )
326
     */
327
    protected function _return_json($data)
328
    {
329
        $json = array(
330
            'notices'  => EE_Error::get_notices(),
331
            'data'     => $data,
332
            'isEEajax' => true
333
            // special flag so any ajax.Success methods in js can identify this return package as a EEajax package.
334
        );
335
336
337
        // make sure there are no php errors or headers_sent.  Then we can set correct json header.
338
        if (null === error_get_last() || ! headers_sent()) {
339
            header('Content-Type: application/json; charset=UTF-8');
340
        }
341
        echo wp_json_encode($json);
342
        exit();
343
    }
344
345
    /**
346
     * Gets the job step response which was done during the enqueuing of scripts
347
     *
348
     * @return \EventEspressoBatchRequest\Helpers\JobStepResponse
349
     */
350
    public function job_step_response()
351
    {
352
        return $this->_job_step_response;
353
    }
354
355
    /**
356
     * Gets the batch request type indicated in the $_REQUEST
357
     *
358
     * @return string: EED_Batch::batch_job, EED_Batch::batch_file_job, EED_Batch::batch_not_job
359
     */
360
    public function batch_request_type()
361
    {
362
        if ($this->_batch_request_type === null) {
363
            if (isset($_GET['batch'])) {
364
                if ($_GET['batch'] == self::batch_job) {
365
                    $this->_batch_request_type = self::batch_job;
366
                } elseif ($_GET['batch'] == self::batch_file_job) {
367
                    $this->_batch_request_type = self::batch_file_job;
368
                }
369
            }
370
            // if we didn't find that it was a batch request, indicate it wasn't
371
            if ($this->_batch_request_type === null) {
372
                $this->_batch_request_type = self::batch_not_job;
373
            }
374
        }
375
        return $this->_batch_request_type;
376
    }
377
378
    /**
379
     * Unnecessary
380
     *
381
     * @param type $WP
382
     */
383
    public function run($WP)
384
    {
385
    }
386
}
387