Completed
Branch FET/add-step-bubble-nav-compon... (18c94e)
by
unknown
09:13 queued 24s
created

EED_Batch::getLoader()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

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