Completed
Branch BUG/11177/messages-system-fixe... (b851f8)
by
unknown
37:36 queued 24:59
created
core/libraries/form_sections/base/EE_Form_Section_Proper.form.php 3 patches
Doc Comments   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -425,7 +425,7 @@
 block discarded – undo
425 425
      *                                                      with construction finalize being called later
426 426
      *                                                      (realizing that the subsections' html names
427 427
      *                                                      might not be set yet, etc.)
428
-     * @return EE_Form_Section_Base
428
+     * @return EE_Form_Section_Validatable|null
429 429
      * @throws EE_Error
430 430
      */
431 431
     public function get_subsection($name, $require_construction_to_be_finalized = true)
Please login to merge, or discard this patch.
Indentation   +1416 added lines, -1416 removed lines patch added patch discarded remove patch
@@ -14,1421 +14,1421 @@
 block discarded – undo
14 14
 class EE_Form_Section_Proper extends EE_Form_Section_Validatable
15 15
 {
16 16
 
17
-    const SUBMITTED_FORM_DATA_SSN_KEY = 'submitted_form_data';
18
-
19
-    /**
20
-     * Subsections
21
-     *
22
-     * @var EE_Form_Section_Validatable[]
23
-     */
24
-    protected $_subsections = array();
25
-
26
-    /**
27
-     * Strategy for laying out the form
28
-     *
29
-     * @var EE_Form_Section_Layout_Base
30
-     */
31
-    protected $_layout_strategy;
32
-
33
-    /**
34
-     * Whether or not this form has received and validated a form submission yet
35
-     *
36
-     * @var boolean
37
-     */
38
-    protected $_received_submission = false;
39
-
40
-    /**
41
-     * message displayed to users upon successful form submission
42
-     *
43
-     * @var string
44
-     */
45
-    protected $_form_submission_success_message = '';
46
-
47
-    /**
48
-     * message displayed to users upon unsuccessful form submission
49
-     *
50
-     * @var string
51
-     */
52
-    protected $_form_submission_error_message = '';
53
-
54
-    /**
55
-     * Stores all the data that will localized for form validation
56
-     *
57
-     * @var array
58
-     */
59
-    static protected $_js_localization = array();
60
-
61
-    /**
62
-     * whether or not the form's localized validation JS vars have been set
63
-     *
64
-     * @type boolean
65
-     */
66
-    static protected $_scripts_localized = false;
67
-
68
-
69
-    /**
70
-     * when constructing a proper form section, calls _construct_finalize on children
71
-     * so that they know who their parent is, and what name they've been given.
72
-     *
73
-     * @param array[] $options_array   {
74
-     * @type          $subsections     EE_Form_Section_Validatable[] where keys are the section's name
75
-     * @type          $include         string[] numerically-indexed where values are section names to be included,
76
-     *                                 and in that order. This is handy if you want
77
-     *                                 the subsections to be ordered differently than the default, and if you override
78
-     *                                 which fields are shown
79
-     * @type          $exclude         string[] values are subsections to be excluded. This is handy if you want
80
-     *                                 to remove certain default subsections (note: if you specify BOTH 'include' AND
81
-     *                                 'exclude', the inclusions will be applied first, and the exclusions will exclude
82
-     *                                 items from that list of inclusions)
83
-     * @type          $layout_strategy EE_Form_Section_Layout_Base strategy for laying out the form
84
-     *                                 } @see EE_Form_Section_Validatable::__construct()
85
-     * @throws EE_Error
86
-     */
87
-    public function __construct($options_array = array())
88
-    {
89
-        $options_array = (array) apply_filters(
90
-            'FHEE__EE_Form_Section_Proper___construct__options_array',
91
-            $options_array,
92
-            $this
93
-        );
94
-        //call parent first, as it may be setting the name
95
-        parent::__construct($options_array);
96
-        //if they've included subsections in the constructor, add them now
97
-        if (isset($options_array['include'])) {
98
-            //we are going to make sure we ONLY have those subsections to include
99
-            //AND we are going to make sure they're in that specified order
100
-            $reordered_subsections = array();
101
-            foreach ($options_array['include'] as $input_name) {
102
-                if (isset($this->_subsections[ $input_name ])) {
103
-                    $reordered_subsections[ $input_name ] = $this->_subsections[ $input_name ];
104
-                }
105
-            }
106
-            $this->_subsections = $reordered_subsections;
107
-        }
108
-        if (isset($options_array['exclude'])) {
109
-            $exclude            = $options_array['exclude'];
110
-            $this->_subsections = array_diff_key($this->_subsections, array_flip($exclude));
111
-        }
112
-        if (isset($options_array['layout_strategy'])) {
113
-            $this->_layout_strategy = $options_array['layout_strategy'];
114
-        }
115
-        if (! $this->_layout_strategy) {
116
-            $this->_layout_strategy = is_admin() ? new EE_Admin_Two_Column_Layout() : new EE_Two_Column_Layout();
117
-        }
118
-        $this->_layout_strategy->_construct_finalize($this);
119
-        //ok so we are definitely going to want the forms JS,
120
-        //so enqueue it or remember to enqueue it during wp_enqueue_scripts
121
-        if (did_action('wp_enqueue_scripts') || did_action('admin_enqueue_scripts')) {
122
-            //ok so they've constructed this object after when they should have.
123
-            //just enqueue the generic form scripts and initialize the form immediately in the JS
124
-            EE_Form_Section_Proper::wp_enqueue_scripts(true);
125
-        } else {
126
-            add_action('wp_enqueue_scripts', array('EE_Form_Section_Proper', 'wp_enqueue_scripts'));
127
-            add_action('admin_enqueue_scripts', array('EE_Form_Section_Proper', 'wp_enqueue_scripts'));
128
-        }
129
-        add_action('wp_footer', array($this, 'ensure_scripts_localized'), 1);
130
-        /**
131
-         * Gives other plugins a chance to hook in before construct finalize is called.
132
-         * The form probably doesn't yet have a parent form section.
133
-         * Since 4.9.32, when this action was introduced, this is the best place to add a subsection onto a form,
134
-         * assuming you don't care what the form section's name, HTML ID, or HTML name etc are.
135
-         * Also see AHEE__EE_Form_Section_Proper___construct_finalize__end
136
-         *
137
-         * @since 4.9.32
138
-         * @param EE_Form_Section_Proper $this          before __construct is done, but all of its logic,
139
-         *                                              except maybe calling _construct_finalize has been done
140
-         * @param array                  $options_array options passed into the constructor
141
-         */
142
-        do_action(
143
-            'AHEE__EE_Form_Input_Base___construct__before_construct_finalize_called',
144
-            $this,
145
-            $options_array
146
-        );
147
-        if (isset($options_array['name'])) {
148
-            $this->_construct_finalize(null, $options_array['name']);
149
-        }
150
-    }
151
-
152
-
153
-    /**
154
-     * Finishes construction given the parent form section and this form section's name
155
-     *
156
-     * @param EE_Form_Section_Proper $parent_form_section
157
-     * @param string                 $name
158
-     * @throws EE_Error
159
-     */
160
-    public function _construct_finalize($parent_form_section, $name)
161
-    {
162
-        parent::_construct_finalize($parent_form_section, $name);
163
-        $this->_set_default_name_if_empty();
164
-        $this->_set_default_html_id_if_empty();
165
-        foreach ($this->_subsections as $subsection_name => $subsection) {
166
-            if ($subsection instanceof EE_Form_Section_Base) {
167
-                $subsection->_construct_finalize($this, $subsection_name);
168
-            } else {
169
-                throw new EE_Error(
170
-                    sprintf(
171
-                        esc_html__(
172
-                            'Subsection "%s" is not an instanceof EE_Form_Section_Base on form "%s". It is a "%s"',
173
-                            'event_espresso'
174
-                        ),
175
-                        $subsection_name,
176
-                        get_class($this),
177
-                        $subsection ? get_class($subsection) : esc_html__('NULL', 'event_espresso')
178
-                    )
179
-                );
180
-            }
181
-        }
182
-        /**
183
-         * Action performed just after form has been given a name (and HTML ID etc) and is fully constructed.
184
-         * If you have code that should modify the form and needs it and its subsections to have a name, HTML ID
185
-         * (or other attributes derived from the name like the HTML label id, etc), this is where it should be done.
186
-         * This might only happen just before displaying the form, or just before it receives form submission data.
187
-         * If you need to modify the form or its subsections before _construct_finalize is called on it (and we've
188
-         * ensured it has a name, HTML IDs, etc
189
-         *
190
-         * @param EE_Form_Section_Proper      $this
191
-         * @param EE_Form_Section_Proper|null $parent_form_section
192
-         * @param string                      $name
193
-         */
194
-        do_action(
195
-            'AHEE__EE_Form_Section_Proper___construct_finalize__end',
196
-            $this,
197
-            $parent_form_section,
198
-            $name
199
-        );
200
-    }
201
-
202
-
203
-    /**
204
-     * Gets the layout strategy for this form section
205
-     *
206
-     * @return EE_Form_Section_Layout_Base
207
-     */
208
-    public function get_layout_strategy()
209
-    {
210
-        return $this->_layout_strategy;
211
-    }
212
-
213
-
214
-    /**
215
-     * Gets the HTML for a single input for this form section according
216
-     * to the layout strategy
217
-     *
218
-     * @param EE_Form_Input_Base $input
219
-     * @return string
220
-     */
221
-    public function get_html_for_input($input)
222
-    {
223
-        return $this->_layout_strategy->layout_input($input);
224
-    }
225
-
226
-
227
-    /**
228
-     * was_submitted - checks if form inputs are present in request data
229
-     * Basically an alias for form_data_present_in() (which is used by both
230
-     * proper form sections and form inputs)
231
-     *
232
-     * @param null $form_data
233
-     * @return boolean
234
-     * @throws EE_Error
235
-     */
236
-    public function was_submitted($form_data = null)
237
-    {
238
-        return $this->form_data_present_in($form_data);
239
-    }
240
-
241
-
242
-    /**
243
-     * After the form section is initially created, call this to sanitize the data in the submission
244
-     * which relates to this form section, validate it, and set it as properties on the form.
245
-     *
246
-     * @param array|null $req_data should usually be $_POST (the default).
247
-     *                             However, you CAN supply a different array.
248
-     *                             Consider using set_defaults() instead however.
249
-     *                             (If you rendered the form in the page using echo $form_x->get_html()
250
-     *                             the inputs will have the correct name in the request data for this function
251
-     *                             to find them and populate the form with them.
252
-     *                             If you have a flat form (with only input subsections),
253
-     *                             you can supply a flat array where keys
254
-     *                             are the form input names and values are their values)
255
-     * @param boolean    $validate whether or not to perform validation on this data. Default is,
256
-     *                             of course, to validate that data, and set errors on the invalid values.
257
-     *                             But if the data has already been validated
258
-     *                             (eg you validated the data then stored it in the DB)
259
-     *                             you may want to skip this step.
260
-     * @throws InvalidArgumentException
261
-     * @throws InvalidInterfaceException
262
-     * @throws InvalidDataTypeException
263
-     * @throws EE_Error
264
-     */
265
-    public function receive_form_submission($req_data = null, $validate = true)
266
-    {
267
-        $req_data = apply_filters(
268
-            'FHEE__EE_Form_Section_Proper__receive_form_submission__req_data',
269
-            $req_data,
270
-            $this,
271
-            $validate
272
-        );
273
-        if ($req_data === null) {
274
-            $req_data = array_merge($_GET, $_POST);
275
-        }
276
-        $req_data = apply_filters(
277
-            'FHEE__EE_Form_Section_Proper__receive_form_submission__request_data',
278
-            $req_data,
279
-            $this
280
-        );
281
-        $this->_normalize($req_data);
282
-        if ($validate) {
283
-            $this->_validate();
284
-            //if it's invalid, we're going to want to re-display so remember what they submitted
285
-            if (! $this->is_valid()) {
286
-                $this->store_submitted_form_data_in_session();
287
-            }
288
-        }
289
-        do_action(
290
-            'AHEE__EE_Form_Section_Proper__receive_form_submission__end',
291
-            $req_data,
292
-            $this,
293
-            $validate
294
-        );
295
-    }
296
-
297
-
298
-    /**
299
-     * caches the originally submitted input values in the session
300
-     * so that they can be used to repopulate the form if it failed validation
301
-     *
302
-     * @return boolean whether or not the data was successfully stored in the session
303
-     * @throws InvalidArgumentException
304
-     * @throws InvalidInterfaceException
305
-     * @throws InvalidDataTypeException
306
-     * @throws EE_Error
307
-     */
308
-    protected function store_submitted_form_data_in_session()
309
-    {
310
-        return EE_Registry::instance()->SSN->set_session_data(
311
-            array(
312
-                EE_Form_Section_Proper::SUBMITTED_FORM_DATA_SSN_KEY => $this->submitted_values(true),
313
-            )
314
-        );
315
-    }
316
-
317
-
318
-    /**
319
-     * retrieves the originally submitted input values in the session
320
-     * so that they can be used to repopulate the form if it failed validation
321
-     *
322
-     * @return array
323
-     * @throws InvalidArgumentException
324
-     * @throws InvalidInterfaceException
325
-     * @throws InvalidDataTypeException
326
-     */
327
-    protected function get_submitted_form_data_from_session()
328
-    {
329
-        $session = EE_Registry::instance()->SSN;
330
-        if ($session instanceof EE_Session) {
331
-            return $session->get_session_data(
332
-                EE_Form_Section_Proper::SUBMITTED_FORM_DATA_SSN_KEY
333
-            );
334
-        }
335
-        return array();
336
-    }
337
-
338
-
339
-    /**
340
-     * flushed the originally submitted input values from the session
341
-     *
342
-     * @return boolean whether or not the data was successfully removed from the session
343
-     * @throws InvalidArgumentException
344
-     * @throws InvalidInterfaceException
345
-     * @throws InvalidDataTypeException
346
-     */
347
-    protected function flush_submitted_form_data_from_session()
348
-    {
349
-        return EE_Registry::instance()->SSN->reset_data(
350
-            array(EE_Form_Section_Proper::SUBMITTED_FORM_DATA_SSN_KEY)
351
-        );
352
-    }
353
-
354
-
355
-    /**
356
-     * Populates this form and its subsections with data from the session.
357
-     * (Wrapper for EE_Form_Section_Proper::receive_form_submission, so it shows
358
-     * validation errors when displaying too)
359
-     * Returns true if the form was populated from the session, false otherwise
360
-     *
361
-     * @return boolean
362
-     * @throws InvalidArgumentException
363
-     * @throws InvalidInterfaceException
364
-     * @throws InvalidDataTypeException
365
-     * @throws EE_Error
366
-     */
367
-    public function populate_from_session()
368
-    {
369
-        $form_data_in_session = $this->get_submitted_form_data_from_session();
370
-        if (empty($form_data_in_session)) {
371
-            return false;
372
-        }
373
-        $this->receive_form_submission($form_data_in_session);
374
-        $this->flush_submitted_form_data_from_session();
375
-        if ($this->form_data_present_in($form_data_in_session)) {
376
-            return true;
377
-        }
378
-        return false;
379
-    }
380
-
381
-
382
-    /**
383
-     * Populates the default data for the form, given an array where keys are
384
-     * the input names, and values are their values (preferably normalized to be their
385
-     * proper PHP types, not all strings... although that should be ok too).
386
-     * Proper subsections are sub-arrays, the key being the subsection's name, and
387
-     * the value being an array formatted in teh same way
388
-     *
389
-     * @param array $default_data
390
-     * @throws EE_Error
391
-     */
392
-    public function populate_defaults($default_data)
393
-    {
394
-        foreach ($this->subsections(false) as $subsection_name => $subsection) {
395
-            if (isset($default_data[ $subsection_name ])) {
396
-                if ($subsection instanceof EE_Form_Input_Base) {
397
-                    $subsection->set_default($default_data[ $subsection_name ]);
398
-                } elseif ($subsection instanceof EE_Form_Section_Proper) {
399
-                    $subsection->populate_defaults($default_data[ $subsection_name ]);
400
-                }
401
-            }
402
-        }
403
-    }
404
-
405
-
406
-    /**
407
-     * returns true if subsection exists
408
-     *
409
-     * @param string $name
410
-     * @return boolean
411
-     */
412
-    public function subsection_exists($name)
413
-    {
414
-        return isset($this->_subsections[ $name ]) ? true : false;
415
-    }
416
-
417
-
418
-    /**
419
-     * Gets the subsection specified by its name
420
-     *
421
-     * @param string  $name
422
-     * @param boolean $require_construction_to_be_finalized most client code should leave this as TRUE
423
-     *                                                      so that the inputs will be properly configured.
424
-     *                                                      However, some client code may be ok
425
-     *                                                      with construction finalize being called later
426
-     *                                                      (realizing that the subsections' html names
427
-     *                                                      might not be set yet, etc.)
428
-     * @return EE_Form_Section_Base
429
-     * @throws EE_Error
430
-     */
431
-    public function get_subsection($name, $require_construction_to_be_finalized = true)
432
-    {
433
-        if ($require_construction_to_be_finalized) {
434
-            $this->ensure_construct_finalized_called();
435
-        }
436
-        return $this->subsection_exists($name) ? $this->_subsections[ $name ] : null;
437
-    }
438
-
439
-
440
-    /**
441
-     * Gets all the validatable subsections of this form section
442
-     *
443
-     * @return EE_Form_Section_Validatable[]
444
-     * @throws EE_Error
445
-     */
446
-    public function get_validatable_subsections()
447
-    {
448
-        $validatable_subsections = array();
449
-        foreach ($this->subsections() as $name => $obj) {
450
-            if ($obj instanceof EE_Form_Section_Validatable) {
451
-                $validatable_subsections[ $name ] = $obj;
452
-            }
453
-        }
454
-        return $validatable_subsections;
455
-    }
456
-
457
-
458
-    /**
459
-     * Gets an input by the given name. If not found, or if its not an EE_FOrm_Input_Base child,
460
-     * throw an EE_Error.
461
-     *
462
-     * @param string  $name
463
-     * @param boolean $require_construction_to_be_finalized most client code should
464
-     *                                                      leave this as TRUE so that the inputs will be properly
465
-     *                                                      configured. However, some client code may be ok with
466
-     *                                                      construction finalize being called later
467
-     *                                                      (realizing that the subsections' html names might not be
468
-     *                                                      set yet, etc.)
469
-     * @return EE_Form_Input_Base
470
-     * @throws EE_Error
471
-     */
472
-    public function get_input($name, $require_construction_to_be_finalized = true)
473
-    {
474
-        $subsection = $this->get_subsection(
475
-            $name,
476
-            $require_construction_to_be_finalized
477
-        );
478
-        if (! $subsection instanceof EE_Form_Input_Base) {
479
-            throw new EE_Error(
480
-                sprintf(
481
-                    esc_html__(
482
-                        "Subsection '%s' is not an instanceof EE_Form_Input_Base on form '%s'. It is a '%s'",
483
-                        'event_espresso'
484
-                    ),
485
-                    $name,
486
-                    get_class($this),
487
-                    $subsection ? get_class($subsection) : esc_html__('NULL', 'event_espresso')
488
-                )
489
-            );
490
-        }
491
-        return $subsection;
492
-    }
493
-
494
-
495
-    /**
496
-     * Like get_input(), gets the proper subsection of the form given the name,
497
-     * otherwise throws an EE_Error
498
-     *
499
-     * @param string  $name
500
-     * @param boolean $require_construction_to_be_finalized most client code should
501
-     *                                                      leave this as TRUE so that the inputs will be properly
502
-     *                                                      configured. However, some client code may be ok with
503
-     *                                                      construction finalize being called later
504
-     *                                                      (realizing that the subsections' html names might not be
505
-     *                                                      set yet, etc.)
506
-     * @return EE_Form_Section_Proper
507
-     * @throws EE_Error
508
-     */
509
-    public function get_proper_subsection($name, $require_construction_to_be_finalized = true)
510
-    {
511
-        $subsection = $this->get_subsection(
512
-            $name,
513
-            $require_construction_to_be_finalized
514
-        );
515
-        if (! $subsection instanceof EE_Form_Section_Proper) {
516
-            throw new EE_Error(
517
-                sprintf(
518
-                    esc_html__(
519
-                        "Subsection '%'s is not an instanceof EE_Form_Section_Proper on form '%s'",
520
-                        'event_espresso'
521
-                    ),
522
-                    $name,
523
-                    get_class($this)
524
-                )
525
-            );
526
-        }
527
-        return $subsection;
528
-    }
529
-
530
-
531
-    /**
532
-     * Gets the value of the specified input. Should be called after receive_form_submission()
533
-     * or populate_defaults() on the form, where the normalized value on the input is set.
534
-     *
535
-     * @param string $name
536
-     * @return mixed depending on the input's type and its normalization strategy
537
-     * @throws EE_Error
538
-     */
539
-    public function get_input_value($name)
540
-    {
541
-        $input = $this->get_input($name);
542
-        return $input->normalized_value();
543
-    }
544
-
545
-
546
-    /**
547
-     * Checks if this form section itself is valid, and then checks its subsections
548
-     *
549
-     * @throws EE_Error
550
-     * @return boolean
551
-     */
552
-    public function is_valid()
553
-    {
554
-        if (! $this->has_received_submission()) {
555
-            throw new EE_Error(
556
-                sprintf(
557
-                    esc_html__(
558
-                        'You cannot check if a form is valid before receiving the form submission using receive_form_submission',
559
-                        'event_espresso'
560
-                    )
561
-                )
562
-            );
563
-        }
564
-        if (! parent::is_valid()) {
565
-            return false;
566
-        }
567
-        // ok so no general errors to this entire form section.
568
-        // so let's check the subsections, but only set errors if that hasn't been done yet
569
-        $set_submission_errors = $this->submission_error_message() === '';
570
-        foreach ($this->get_validatable_subsections() as $subsection) {
571
-            if (! $subsection->is_valid() || $subsection->get_validation_error_string() !== '') {
572
-                if ($set_submission_errors) {
573
-                    $this->set_submission_error_message(
574
-                        $subsection->get_validation_error_string()
575
-                    );
576
-                }
577
-                return false;
578
-            }
579
-        }
580
-        return true;
581
-    }
582
-
583
-
584
-    /**
585
-     * gets the default name of this form section if none is specified
586
-     *
587
-     * @return void
588
-     */
589
-    protected function _set_default_name_if_empty()
590
-    {
591
-        if (! $this->_name) {
592
-            $classname    = get_class($this);
593
-            $default_name = str_replace('EE_', '', $classname);
594
-            $this->_name  = $default_name;
595
-        }
596
-    }
597
-
598
-
599
-    /**
600
-     * Returns the HTML for the form, except for the form opening and closing tags
601
-     * (as the form section doesn't know where you necessarily want to send the information to),
602
-     * and except for a submit button. Enqueues JS and CSS; if called early enough we will
603
-     * try to enqueue them in the header, otherwise they'll be enqueued in the footer.
604
-     * Not doing_it_wrong because theoretically this CAN be used properly,
605
-     * provided its used during "wp_enqueue_scripts", or it doesn't need to enqueue
606
-     * any CSS.
607
-     *
608
-     * @throws InvalidArgumentException
609
-     * @throws InvalidInterfaceException
610
-     * @throws InvalidDataTypeException
611
-     * @throws EE_Error
612
-     */
613
-    public function get_html_and_js()
614
-    {
615
-        $this->enqueue_js();
616
-        return $this->get_html();
617
-    }
618
-
619
-
620
-    /**
621
-     * returns HTML for displaying this form section. recursively calls display_section() on all subsections
622
-     *
623
-     * @param bool $display_previously_submitted_data
624
-     * @return string
625
-     * @throws InvalidArgumentException
626
-     * @throws InvalidInterfaceException
627
-     * @throws InvalidDataTypeException
628
-     * @throws EE_Error
629
-     * @throws EE_Error
630
-     * @throws EE_Error
631
-     */
632
-    public function get_html($display_previously_submitted_data = true)
633
-    {
634
-        $this->ensure_construct_finalized_called();
635
-        if ($display_previously_submitted_data) {
636
-            $this->populate_from_session();
637
-        }
638
-        return $this->_form_html_filter
639
-            ? $this->_form_html_filter->filterHtml($this->_layout_strategy->layout_form(), $this)
640
-            : $this->_layout_strategy->layout_form();
641
-    }
642
-
643
-
644
-    /**
645
-     * enqueues JS and CSS for the form.
646
-     * It is preferred to call this before wp_enqueue_scripts so the
647
-     * scripts and styles can be put in the header, but if called later
648
-     * they will be put in the footer (which is OK for JS, but in HTML4 CSS should
649
-     * only be in the header; but in HTML5 its ok in the body.
650
-     * See http://stackoverflow.com/questions/4957446/load-external-css-file-in-body-tag.
651
-     * So if your form enqueues CSS, it's preferred to call this before wp_enqueue_scripts.)
652
-     *
653
-     * @return void
654
-     * @throws EE_Error
655
-     */
656
-    public function enqueue_js()
657
-    {
658
-        $this->_enqueue_and_localize_form_js();
659
-        foreach ($this->subsections() as $subsection) {
660
-            $subsection->enqueue_js();
661
-        }
662
-    }
663
-
664
-
665
-    /**
666
-     * adds a filter so that jquery validate gets enqueued in EE_System::wp_enqueue_scripts().
667
-     * This must be done BEFORE wp_enqueue_scripts() gets called, which is on
668
-     * the wp_enqueue_scripts hook.
669
-     * However, registering the form js and localizing it can happen when we
670
-     * actually output the form (which is preferred, seeing how teh form's fields
671
-     * could change until it's actually outputted)
672
-     *
673
-     * @param boolean $init_form_validation_automatically whether or not we want the form validation
674
-     *                                                    to be triggered automatically or not
675
-     * @return void
676
-     */
677
-    public static function wp_enqueue_scripts($init_form_validation_automatically = true)
678
-    {
679
-        wp_register_script(
680
-            'ee_form_section_validation',
681
-            EE_GLOBAL_ASSETS_URL . 'scripts' . DS . 'form_section_validation.js',
682
-            array('jquery-validate', 'jquery-ui-datepicker', 'jquery-validate-extra-methods'),
683
-            EVENT_ESPRESSO_VERSION,
684
-            true
685
-        );
686
-        wp_localize_script(
687
-            'ee_form_section_validation',
688
-            'ee_form_section_validation_init',
689
-            array('init' => $init_form_validation_automatically ? '1' : '0')
690
-        );
691
-    }
692
-
693
-
694
-    /**
695
-     * gets the variables used by form_section_validation.js.
696
-     * This needs to be called AFTER we've called $this->_enqueue_jquery_validate_script,
697
-     * but before the wordpress hook wp_loaded
698
-     *
699
-     * @throws EE_Error
700
-     */
701
-    public function _enqueue_and_localize_form_js()
702
-    {
703
-        $this->ensure_construct_finalized_called();
704
-        //actually, we don't want to localize just yet. There may be other forms on the page.
705
-        //so we need to add our form section data to a static variable accessible by all form sections
706
-        //and localize it just before the footer
707
-        $this->localize_validation_rules();
708
-        add_action('wp_footer', array('EE_Form_Section_Proper', 'localize_script_for_all_forms'), 2);
709
-        add_action('admin_footer', array('EE_Form_Section_Proper', 'localize_script_for_all_forms'));
710
-    }
711
-
712
-
713
-    /**
714
-     * add our form section data to a static variable accessible by all form sections
715
-     *
716
-     * @param bool $return_for_subsection
717
-     * @return void
718
-     * @throws EE_Error
719
-     */
720
-    public function localize_validation_rules($return_for_subsection = false)
721
-    {
722
-        // we only want to localize vars ONCE for the entire form,
723
-        // so if the form section doesn't have a parent, then it must be the top dog
724
-        if ($return_for_subsection || ! $this->parent_section()) {
725
-            EE_Form_Section_Proper::$_js_localization['form_data'][ $this->html_id() ] = array(
726
-                'form_section_id'  => $this->html_id(true),
727
-                'validation_rules' => $this->get_jquery_validation_rules(),
728
-                'other_data'       => $this->get_other_js_data(),
729
-                'errors'           => $this->subsection_validation_errors_by_html_name(),
730
-            );
731
-            EE_Form_Section_Proper::$_scripts_localized                                = true;
732
-        }
733
-    }
734
-
735
-
736
-    /**
737
-     * Gets an array of extra data that will be useful for client-side javascript.
738
-     * This is primarily data added by inputs and forms in addition to any
739
-     * scripts they might enqueue
740
-     *
741
-     * @param array $form_other_js_data
742
-     * @return array
743
-     * @throws EE_Error
744
-     */
745
-    public function get_other_js_data($form_other_js_data = array())
746
-    {
747
-        foreach ($this->subsections() as $subsection) {
748
-            $form_other_js_data = $subsection->get_other_js_data($form_other_js_data);
749
-        }
750
-        return $form_other_js_data;
751
-    }
752
-
753
-
754
-    /**
755
-     * Gets a flat array of inputs for this form section and its subsections.
756
-     * Keys are their form names, and values are the inputs themselves
757
-     *
758
-     * @return EE_Form_Input_Base
759
-     * @throws EE_Error
760
-     */
761
-    public function inputs_in_subsections()
762
-    {
763
-        $inputs = array();
764
-        foreach ($this->subsections() as $subsection) {
765
-            if ($subsection instanceof EE_Form_Input_Base) {
766
-                $inputs[ $subsection->html_name() ] = $subsection;
767
-            } elseif ($subsection instanceof EE_Form_Section_Proper) {
768
-                $inputs += $subsection->inputs_in_subsections();
769
-            }
770
-        }
771
-        return $inputs;
772
-    }
773
-
774
-
775
-    /**
776
-     * Gets a flat array of all the validation errors.
777
-     * Keys are html names (because those should be unique)
778
-     * and values are a string of all their validation errors
779
-     *
780
-     * @return string[]
781
-     * @throws EE_Error
782
-     */
783
-    public function subsection_validation_errors_by_html_name()
784
-    {
785
-        $inputs = $this->inputs();
786
-        $errors = array();
787
-        foreach ($inputs as $form_input) {
788
-            if ($form_input instanceof EE_Form_Input_Base && $form_input->get_validation_errors()) {
789
-                $errors[ $form_input->html_name() ] = $form_input->get_validation_error_string();
790
-            }
791
-        }
792
-        return $errors;
793
-    }
794
-
795
-
796
-    /**
797
-     * passes all the form data required by the JS to the JS, and enqueues the few required JS files.
798
-     * Should be setup by each form during the _enqueues_and_localize_form_js
799
-     *
800
-     * @throws InvalidArgumentException
801
-     * @throws InvalidInterfaceException
802
-     * @throws InvalidDataTypeException
803
-     */
804
-    public static function localize_script_for_all_forms()
805
-    {
806
-        //allow inputs and stuff to hook in their JS and stuff here
807
-        do_action('AHEE__EE_Form_Section_Proper__localize_script_for_all_forms__begin');
808
-        EE_Form_Section_Proper::$_js_localization['localized_error_messages'] = EE_Form_Section_Proper::_get_localized_error_messages();
809
-        $email_validation_level = isset(EE_Registry::instance()->CFG->registration->email_validation_level)
810
-            ? EE_Registry::instance()->CFG->registration->email_validation_level
811
-            : 'wp_default';
812
-        EE_Form_Section_Proper::$_js_localization['email_validation_level']   = $email_validation_level;
813
-        wp_enqueue_script('ee_form_section_validation');
814
-        wp_localize_script(
815
-            'ee_form_section_validation',
816
-            'ee_form_section_vars',
817
-            EE_Form_Section_Proper::$_js_localization
818
-        );
819
-    }
820
-
821
-
822
-    /**
823
-     * ensure_scripts_localized
824
-     *
825
-     * @throws EE_Error
826
-     */
827
-    public function ensure_scripts_localized()
828
-    {
829
-        if (! EE_Form_Section_Proper::$_scripts_localized) {
830
-            $this->_enqueue_and_localize_form_js();
831
-        }
832
-    }
833
-
834
-
835
-    /**
836
-     * Gets the hard-coded validation error messages to be used in the JS. The convention
837
-     * is that the key here should be the same as the custom validation rule put in the JS file
838
-     *
839
-     * @return array keys are custom validation rules, and values are internationalized strings
840
-     */
841
-    private static function _get_localized_error_messages()
842
-    {
843
-        return array(
844
-            'validUrl' => esc_html__('This is not a valid absolute URL. Eg, http://domain.com/monkey.jpg', 'event_espresso'),
845
-            'regex'    => esc_html__('Please check your input', 'event_espresso'),
846
-        );
847
-    }
848
-
849
-
850
-    /**
851
-     * @return array
852
-     */
853
-    public static function js_localization()
854
-    {
855
-        return self::$_js_localization;
856
-    }
857
-
858
-
859
-    /**
860
-     * @return void
861
-     */
862
-    public static function reset_js_localization()
863
-    {
864
-        self::$_js_localization = array();
865
-    }
866
-
867
-
868
-    /**
869
-     * Gets the JS to put inside the jquery validation rules for subsection of this form section.
870
-     * See parent function for more...
871
-     *
872
-     * @return array
873
-     * @throws EE_Error
874
-     */
875
-    public function get_jquery_validation_rules()
876
-    {
877
-        $jquery_validation_rules = array();
878
-        foreach ($this->get_validatable_subsections() as $subsection) {
879
-            $jquery_validation_rules = array_merge(
880
-                $jquery_validation_rules,
881
-                $subsection->get_jquery_validation_rules()
882
-            );
883
-        }
884
-        return $jquery_validation_rules;
885
-    }
886
-
887
-
888
-    /**
889
-     * Sanitizes all the data and sets the sanitized value of each field
890
-     *
891
-     * @param array $req_data like $_POST
892
-     * @return void
893
-     * @throws EE_Error
894
-     */
895
-    protected function _normalize($req_data)
896
-    {
897
-        $this->_received_submission = true;
898
-        $this->_validation_errors   = array();
899
-        foreach ($this->get_validatable_subsections() as $subsection) {
900
-            try {
901
-                $subsection->_normalize($req_data);
902
-            } catch (EE_Validation_Error $e) {
903
-                $subsection->add_validation_error($e);
904
-            }
905
-        }
906
-    }
907
-
908
-
909
-    /**
910
-     * Performs validation on this form section and its subsections.
911
-     * For each subsection,
912
-     * calls _validate_{subsection_name} on THIS form (if the function exists)
913
-     * and passes it the subsection, then calls _validate on that subsection.
914
-     * If you need to perform validation on the form as a whole (considering multiple)
915
-     * you would be best to override this _validate method,
916
-     * calling parent::_validate() first.
917
-     *
918
-     * @throws EE_Error
919
-     */
920
-    protected function _validate()
921
-    {
922
-        foreach ($this->get_validatable_subsections() as $subsection_name => $subsection) {
923
-            if (method_exists($this, '_validate_' . $subsection_name)) {
924
-                call_user_func_array(array($this, '_validate_' . $subsection_name), array($subsection));
925
-            }
926
-            $subsection->_validate();
927
-        }
928
-    }
929
-
930
-
931
-    /**
932
-     * Gets all the validated inputs for the form section
933
-     *
934
-     * @return array
935
-     * @throws EE_Error
936
-     */
937
-    public function valid_data()
938
-    {
939
-        $inputs = array();
940
-        foreach ($this->subsections() as $subsection_name => $subsection) {
941
-            if ($subsection instanceof EE_Form_Section_Proper) {
942
-                $inputs[ $subsection_name ] = $subsection->valid_data();
943
-            } elseif ($subsection instanceof EE_Form_Input_Base) {
944
-                $inputs[ $subsection_name ] = $subsection->normalized_value();
945
-            }
946
-        }
947
-        return $inputs;
948
-    }
949
-
950
-
951
-    /**
952
-     * Gets all the inputs on this form section
953
-     *
954
-     * @return EE_Form_Input_Base[]
955
-     * @throws EE_Error
956
-     */
957
-    public function inputs()
958
-    {
959
-        $inputs = array();
960
-        foreach ($this->subsections() as $subsection_name => $subsection) {
961
-            if ($subsection instanceof EE_Form_Input_Base) {
962
-                $inputs[ $subsection_name ] = $subsection;
963
-            }
964
-        }
965
-        return $inputs;
966
-    }
967
-
968
-
969
-    /**
970
-     * Gets all the subsections which are a proper form
971
-     *
972
-     * @return EE_Form_Section_Proper[]
973
-     * @throws EE_Error
974
-     */
975
-    public function subforms()
976
-    {
977
-        $form_sections = array();
978
-        foreach ($this->subsections() as $name => $obj) {
979
-            if ($obj instanceof EE_Form_Section_Proper) {
980
-                $form_sections[ $name ] = $obj;
981
-            }
982
-        }
983
-        return $form_sections;
984
-    }
985
-
986
-
987
-    /**
988
-     * Gets all the subsections (inputs, proper subsections, or html-only sections).
989
-     * Consider using inputs() or subforms()
990
-     * if you only want form inputs or proper form sections.
991
-     *
992
-     * @param boolean $require_construction_to_be_finalized most client code should
993
-     *                                                      leave this as TRUE so that the inputs will be properly
994
-     *                                                      configured. However, some client code may be ok with
995
-     *                                                      construction finalize being called later
996
-     *                                                      (realizing that the subsections' html names might not be
997
-     *                                                      set yet, etc.)
998
-     * @return EE_Form_Section_Proper[]
999
-     * @throws EE_Error
1000
-     */
1001
-    public function subsections($require_construction_to_be_finalized = true)
1002
-    {
1003
-        if ($require_construction_to_be_finalized) {
1004
-            $this->ensure_construct_finalized_called();
1005
-        }
1006
-        return $this->_subsections;
1007
-    }
1008
-
1009
-
1010
-    /**
1011
-     * Returns a simple array where keys are input names, and values are their normalized
1012
-     * values. (Similar to calling get_input_value on inputs)
1013
-     *
1014
-     * @param boolean $include_subform_inputs Whether to include inputs from subforms,
1015
-     *                                        or just this forms' direct children inputs
1016
-     * @param boolean $flatten                Whether to force the results into 1-dimensional array,
1017
-     *                                        or allow multidimensional array
1018
-     * @return array if $flatten is TRUE it will always be a 1-dimensional array
1019
-     *                                        with array keys being input names
1020
-     *                                        (regardless of whether they are from a subsection or not),
1021
-     *                                        and if $flatten is FALSE it can be a multidimensional array
1022
-     *                                        where keys are always subsection names and values are either
1023
-     *                                        the input's normalized value, or an array like the top-level array
1024
-     * @throws EE_Error
1025
-     */
1026
-    public function input_values($include_subform_inputs = false, $flatten = false)
1027
-    {
1028
-        return $this->_input_values(false, $include_subform_inputs, $flatten);
1029
-    }
1030
-
1031
-
1032
-    /**
1033
-     * Similar to EE_Form_Section_Proper::input_values(), except this returns the 'display_value'
1034
-     * of each input. On some inputs (especially radio boxes or checkboxes), the value stored
1035
-     * is not necessarily the value we want to display to users. This creates an array
1036
-     * where keys are the input names, and values are their display values
1037
-     *
1038
-     * @param boolean $include_subform_inputs Whether to include inputs from subforms,
1039
-     *                                        or just this forms' direct children inputs
1040
-     * @param boolean $flatten                Whether to force the results into 1-dimensional array,
1041
-     *                                        or allow multidimensional array
1042
-     * @return array if $flatten is TRUE it will always be a 1-dimensional array
1043
-     *                                        with array keys being input names
1044
-     *                                        (regardless of whether they are from a subsection or not),
1045
-     *                                        and if $flatten is FALSE it can be a multidimensional array
1046
-     *                                        where keys are always subsection names and values are either
1047
-     *                                        the input's normalized value, or an array like the top-level array
1048
-     * @throws EE_Error
1049
-     */
1050
-    public function input_pretty_values($include_subform_inputs = false, $flatten = false)
1051
-    {
1052
-        return $this->_input_values(true, $include_subform_inputs, $flatten);
1053
-    }
1054
-
1055
-
1056
-    /**
1057
-     * Gets the input values from the form
1058
-     *
1059
-     * @param boolean $pretty                 Whether to retrieve the pretty value,
1060
-     *                                        or just the normalized value
1061
-     * @param boolean $include_subform_inputs Whether to include inputs from subforms,
1062
-     *                                        or just this forms' direct children inputs
1063
-     * @param boolean $flatten                Whether to force the results into 1-dimensional array,
1064
-     *                                        or allow multidimensional array
1065
-     * @return array if $flatten is TRUE it will always be a 1-dimensional array with array keys being
1066
-     *                                        input names (regardless of whether they are from a subsection or not),
1067
-     *                                        and if $flatten is FALSE it can be a multidimensional array
1068
-     *                                        where keys are always subsection names and values are either
1069
-     *                                        the input's normalized value, or an array like the top-level array
1070
-     * @throws EE_Error
1071
-     */
1072
-    public function _input_values($pretty = false, $include_subform_inputs = false, $flatten = false)
1073
-    {
1074
-        $input_values = array();
1075
-        foreach ($this->subsections() as $subsection_name => $subsection) {
1076
-            if ($subsection instanceof EE_Form_Input_Base) {
1077
-                $input_values[ $subsection_name ] = $pretty
1078
-                    ? $subsection->pretty_value()
1079
-                    : $subsection->normalized_value();
1080
-            } elseif ($subsection instanceof EE_Form_Section_Proper && $include_subform_inputs) {
1081
-                $subform_input_values = $subsection->_input_values(
1082
-                    $pretty,
1083
-                    $include_subform_inputs,
1084
-                    $flatten
1085
-                );
1086
-                if ($flatten) {
1087
-                    $input_values = array_merge($input_values, $subform_input_values);
1088
-                } else {
1089
-                    $input_values[ $subsection_name ] = $subform_input_values;
1090
-                }
1091
-            }
1092
-        }
1093
-        return $input_values;
1094
-    }
1095
-
1096
-
1097
-    /**
1098
-     * Gets the originally submitted input values from the form
1099
-     *
1100
-     * @param boolean $include_subforms  Whether to include inputs from subforms,
1101
-     *                                   or just this forms' direct children inputs
1102
-     * @return array                     if $flatten is TRUE it will always be a 1-dimensional array
1103
-     *                                   with array keys being input names
1104
-     *                                   (regardless of whether they are from a subsection or not),
1105
-     *                                   and if $flatten is FALSE it can be a multidimensional array
1106
-     *                                   where keys are always subsection names and values are either
1107
-     *                                   the input's normalized value, or an array like the top-level array
1108
-     * @throws EE_Error
1109
-     */
1110
-    public function submitted_values($include_subforms = false)
1111
-    {
1112
-        $submitted_values = array();
1113
-        foreach ($this->subsections() as $subsection) {
1114
-            if ($subsection instanceof EE_Form_Input_Base) {
1115
-                // is this input part of an array of inputs?
1116
-                if (strpos($subsection->html_name(), '[') !== false) {
1117
-                    $full_input_name  = EEH_Array::convert_array_values_to_keys(
1118
-                        explode(
1119
-                            '[',
1120
-                            str_replace(']', '', $subsection->html_name())
1121
-                        ),
1122
-                        $subsection->raw_value()
1123
-                    );
1124
-                    $submitted_values = array_replace_recursive($submitted_values, $full_input_name);
1125
-                } else {
1126
-                    $submitted_values[ $subsection->html_name() ] = $subsection->raw_value();
1127
-                }
1128
-            } elseif ($subsection instanceof EE_Form_Section_Proper && $include_subforms) {
1129
-                $subform_input_values = $subsection->submitted_values($include_subforms);
1130
-                $submitted_values     = array_replace_recursive($submitted_values, $subform_input_values);
1131
-            }
1132
-        }
1133
-        return $submitted_values;
1134
-    }
1135
-
1136
-
1137
-    /**
1138
-     * Indicates whether or not this form has received a submission yet
1139
-     * (ie, had receive_form_submission called on it yet)
1140
-     *
1141
-     * @return boolean
1142
-     * @throws EE_Error
1143
-     */
1144
-    public function has_received_submission()
1145
-    {
1146
-        $this->ensure_construct_finalized_called();
1147
-        return $this->_received_submission;
1148
-    }
1149
-
1150
-
1151
-    /**
1152
-     * Equivalent to passing 'exclude' in the constructor's options array.
1153
-     * Removes the listed inputs from the form
1154
-     *
1155
-     * @param array $inputs_to_exclude values are the input names
1156
-     * @return void
1157
-     */
1158
-    public function exclude(array $inputs_to_exclude = array())
1159
-    {
1160
-        foreach ($inputs_to_exclude as $input_to_exclude_name) {
1161
-            unset($this->_subsections[ $input_to_exclude_name ]);
1162
-        }
1163
-    }
1164
-
1165
-
1166
-    /**
1167
-     * @param array $inputs_to_hide
1168
-     * @throws EE_Error
1169
-     */
1170
-    public function hide(array $inputs_to_hide = array())
1171
-    {
1172
-        foreach ($inputs_to_hide as $input_to_hide) {
1173
-            $input = $this->get_input($input_to_hide);
1174
-            $input->set_display_strategy(new EE_Hidden_Display_Strategy());
1175
-        }
1176
-    }
1177
-
1178
-
1179
-    /**
1180
-     * add_subsections
1181
-     * Adds the listed subsections to the form section.
1182
-     * If $subsection_name_to_target is provided,
1183
-     * then new subsections are added before or after that subsection,
1184
-     * otherwise to the start or end of the entire subsections array.
1185
-     *
1186
-     * @param EE_Form_Section_Base[] $new_subsections           array of new form subsections
1187
-     *                                                          where keys are their names
1188
-     * @param string                 $subsection_name_to_target an existing for section that $new_subsections
1189
-     *                                                          should be added before or after
1190
-     *                                                          IF $subsection_name_to_target is null,
1191
-     *                                                          then $new_subsections will be added to
1192
-     *                                                          the beginning or end of the entire subsections array
1193
-     * @param boolean                $add_before                whether to add $new_subsections, before or after
1194
-     *                                                          $subsection_name_to_target,
1195
-     *                                                          or if $subsection_name_to_target is null,
1196
-     *                                                          before or after entire subsections array
1197
-     * @return void
1198
-     * @throws EE_Error
1199
-     */
1200
-    public function add_subsections($new_subsections, $subsection_name_to_target = null, $add_before = true)
1201
-    {
1202
-        foreach ($new_subsections as $subsection_name => $subsection) {
1203
-            if (! $subsection instanceof EE_Form_Section_Base) {
1204
-                EE_Error::add_error(
1205
-                    sprintf(
1206
-                        esc_html__(
1207
-                            "Trying to add a %s as a subsection (it was named '%s') to the form section '%s'. It was removed.",
1208
-                            'event_espresso'
1209
-                        ),
1210
-                        get_class($subsection),
1211
-                        $subsection_name,
1212
-                        $this->name()
1213
-                    )
1214
-                );
1215
-                unset($new_subsections[ $subsection_name ]);
1216
-            }
1217
-        }
1218
-        $this->_subsections = EEH_Array::insert_into_array(
1219
-            $this->_subsections,
1220
-            $new_subsections,
1221
-            $subsection_name_to_target,
1222
-            $add_before
1223
-        );
1224
-        if ($this->_construction_finalized) {
1225
-            foreach ($this->_subsections as $name => $subsection) {
1226
-                $subsection->_construct_finalize($this, $name);
1227
-            }
1228
-        }
1229
-    }
1230
-
1231
-
1232
-    /**
1233
-     * Just gets all validatable subsections to clean their sensitive data
1234
-     *
1235
-     * @throws EE_Error
1236
-     */
1237
-    public function clean_sensitive_data()
1238
-    {
1239
-        foreach ($this->get_validatable_subsections() as $subsection) {
1240
-            $subsection->clean_sensitive_data();
1241
-        }
1242
-    }
1243
-
1244
-
1245
-    /**
1246
-     * @param string $form_submission_error_message
1247
-     */
1248
-    public function set_submission_error_message($form_submission_error_message = '')
1249
-    {
1250
-        $this->_form_submission_error_message .= ! empty($form_submission_error_message)
1251
-            ? $form_submission_error_message
1252
-            : esc_html__('Form submission failed due to errors', 'event_espresso');
1253
-    }
1254
-
1255
-
1256
-    /**
1257
-     * @return string
1258
-     */
1259
-    public function submission_error_message()
1260
-    {
1261
-        return $this->_form_submission_error_message;
1262
-    }
1263
-
1264
-
1265
-    /**
1266
-     * @param string $form_submission_success_message
1267
-     */
1268
-    public function set_submission_success_message($form_submission_success_message)
1269
-    {
1270
-        $this->_form_submission_success_message .= ! empty($form_submission_success_message)
1271
-            ? $form_submission_success_message
1272
-            : esc_html__('Form submitted successfully', 'event_espresso');
1273
-    }
1274
-
1275
-
1276
-    /**
1277
-     * @return string
1278
-     */
1279
-    public function submission_success_message()
1280
-    {
1281
-        return $this->_form_submission_success_message;
1282
-    }
1283
-
1284
-
1285
-    /**
1286
-     * Returns the prefix that should be used on child of this form section for
1287
-     * their html names. If this form section itself has a parent, prepends ITS
1288
-     * prefix onto this form section's prefix. Used primarily by
1289
-     * EE_Form_Input_Base::_set_default_html_name_if_empty
1290
-     *
1291
-     * @return string
1292
-     * @throws EE_Error
1293
-     */
1294
-    public function html_name_prefix()
1295
-    {
1296
-        if ($this->parent_section() instanceof EE_Form_Section_Proper) {
1297
-            return $this->parent_section()->html_name_prefix() . '[' . $this->name() . ']';
1298
-        }
1299
-        return $this->name();
1300
-    }
1301
-
1302
-
1303
-    /**
1304
-     * Gets the name, but first checks _construct_finalize has been called. If not,
1305
-     * calls it (assumes there is no parent and that we want the name to be whatever
1306
-     * was set, which is probably nothing, or the classname)
1307
-     *
1308
-     * @return string
1309
-     * @throws EE_Error
1310
-     */
1311
-    public function name()
1312
-    {
1313
-        $this->ensure_construct_finalized_called();
1314
-        return parent::name();
1315
-    }
1316
-
1317
-
1318
-    /**
1319
-     * @return EE_Form_Section_Proper
1320
-     * @throws EE_Error
1321
-     */
1322
-    public function parent_section()
1323
-    {
1324
-        $this->ensure_construct_finalized_called();
1325
-        return parent::parent_section();
1326
-    }
1327
-
1328
-
1329
-    /**
1330
-     * make sure construction finalized was called, otherwise children might not be ready
1331
-     *
1332
-     * @return void
1333
-     * @throws EE_Error
1334
-     */
1335
-    public function ensure_construct_finalized_called()
1336
-    {
1337
-        if (! $this->_construction_finalized) {
1338
-            $this->_construct_finalize($this->_parent_section, $this->_name);
1339
-        }
1340
-    }
1341
-
1342
-
1343
-    /**
1344
-     * Checks if any of this form section's inputs, or any of its children's inputs,
1345
-     * are in teh form data. If any are found, returns true. Else false
1346
-     *
1347
-     * @param array $req_data
1348
-     * @return boolean
1349
-     * @throws EE_Error
1350
-     */
1351
-    public function form_data_present_in($req_data = null)
1352
-    {
1353
-        if ($req_data === null) {
1354
-            $req_data = $_POST;
1355
-        }
1356
-        foreach ($this->subsections() as $subsection) {
1357
-            if ($subsection instanceof EE_Form_Input_Base) {
1358
-                if ($subsection->form_data_present_in($req_data)) {
1359
-                    return true;
1360
-                }
1361
-            } elseif ($subsection instanceof EE_Form_Section_Proper) {
1362
-                if ($subsection->form_data_present_in($req_data)) {
1363
-                    return true;
1364
-                }
1365
-            }
1366
-        }
1367
-        return false;
1368
-    }
1369
-
1370
-
1371
-    /**
1372
-     * Gets validation errors for this form section and subsections
1373
-     * Similar to EE_Form_Section_Validatable::get_validation_errors() except this
1374
-     * gets the validation errors for ALL subsection
1375
-     *
1376
-     * @return EE_Validation_Error[]
1377
-     * @throws EE_Error
1378
-     */
1379
-    public function get_validation_errors_accumulated()
1380
-    {
1381
-        $validation_errors = $this->get_validation_errors();
1382
-        foreach ($this->get_validatable_subsections() as $subsection) {
1383
-            if ($subsection instanceof EE_Form_Section_Proper) {
1384
-                $validation_errors_on_this_subsection = $subsection->get_validation_errors_accumulated();
1385
-            } else {
1386
-                $validation_errors_on_this_subsection = $subsection->get_validation_errors();
1387
-            }
1388
-            if ($validation_errors_on_this_subsection) {
1389
-                $validation_errors = array_merge($validation_errors, $validation_errors_on_this_subsection);
1390
-            }
1391
-        }
1392
-        return $validation_errors;
1393
-    }
1394
-
1395
-
1396
-    /**
1397
-     * This isn't just the name of an input, it's a path pointing to an input. The
1398
-     * path is similar to a folder path: slash (/) means to descend into a subsection,
1399
-     * dot-dot-slash (../) means to ascend into the parent section.
1400
-     * After a series of slashes and dot-dot-slashes, there should be the name of an input,
1401
-     * which will be returned.
1402
-     * Eg, if you want the related input to be conditional on a sibling input name 'foobar'
1403
-     * just use 'foobar'. If you want it to be conditional on an aunt/uncle input name
1404
-     * 'baz', use '../baz'. If you want it to be conditional on a cousin input,
1405
-     * the child of 'baz_section' named 'baz_child', use '../baz_section/baz_child'.
1406
-     * Etc
1407
-     *
1408
-     * @param string|false $form_section_path we accept false also because substr( '../', '../' ) = false
1409
-     * @return EE_Form_Section_Base
1410
-     * @throws EE_Error
1411
-     */
1412
-    public function find_section_from_path($form_section_path)
1413
-    {
1414
-        //check if we can find the input from purely going straight up the tree
1415
-        $input = parent::find_section_from_path($form_section_path);
1416
-        if ($input instanceof EE_Form_Section_Base) {
1417
-            return $input;
1418
-        }
1419
-        $next_slash_pos = strpos($form_section_path, '/');
1420
-        if ($next_slash_pos !== false) {
1421
-            $child_section_name = substr($form_section_path, 0, $next_slash_pos);
1422
-            $subpath            = substr($form_section_path, $next_slash_pos + 1);
1423
-        } else {
1424
-            $child_section_name = $form_section_path;
1425
-            $subpath            = '';
1426
-        }
1427
-        $child_section = $this->get_subsection($child_section_name);
1428
-        if ($child_section instanceof EE_Form_Section_Base) {
1429
-            return $child_section->find_section_from_path($subpath);
1430
-        }
1431
-        return null;
1432
-    }
17
+	const SUBMITTED_FORM_DATA_SSN_KEY = 'submitted_form_data';
18
+
19
+	/**
20
+	 * Subsections
21
+	 *
22
+	 * @var EE_Form_Section_Validatable[]
23
+	 */
24
+	protected $_subsections = array();
25
+
26
+	/**
27
+	 * Strategy for laying out the form
28
+	 *
29
+	 * @var EE_Form_Section_Layout_Base
30
+	 */
31
+	protected $_layout_strategy;
32
+
33
+	/**
34
+	 * Whether or not this form has received and validated a form submission yet
35
+	 *
36
+	 * @var boolean
37
+	 */
38
+	protected $_received_submission = false;
39
+
40
+	/**
41
+	 * message displayed to users upon successful form submission
42
+	 *
43
+	 * @var string
44
+	 */
45
+	protected $_form_submission_success_message = '';
46
+
47
+	/**
48
+	 * message displayed to users upon unsuccessful form submission
49
+	 *
50
+	 * @var string
51
+	 */
52
+	protected $_form_submission_error_message = '';
53
+
54
+	/**
55
+	 * Stores all the data that will localized for form validation
56
+	 *
57
+	 * @var array
58
+	 */
59
+	static protected $_js_localization = array();
60
+
61
+	/**
62
+	 * whether or not the form's localized validation JS vars have been set
63
+	 *
64
+	 * @type boolean
65
+	 */
66
+	static protected $_scripts_localized = false;
67
+
68
+
69
+	/**
70
+	 * when constructing a proper form section, calls _construct_finalize on children
71
+	 * so that they know who their parent is, and what name they've been given.
72
+	 *
73
+	 * @param array[] $options_array   {
74
+	 * @type          $subsections     EE_Form_Section_Validatable[] where keys are the section's name
75
+	 * @type          $include         string[] numerically-indexed where values are section names to be included,
76
+	 *                                 and in that order. This is handy if you want
77
+	 *                                 the subsections to be ordered differently than the default, and if you override
78
+	 *                                 which fields are shown
79
+	 * @type          $exclude         string[] values are subsections to be excluded. This is handy if you want
80
+	 *                                 to remove certain default subsections (note: if you specify BOTH 'include' AND
81
+	 *                                 'exclude', the inclusions will be applied first, and the exclusions will exclude
82
+	 *                                 items from that list of inclusions)
83
+	 * @type          $layout_strategy EE_Form_Section_Layout_Base strategy for laying out the form
84
+	 *                                 } @see EE_Form_Section_Validatable::__construct()
85
+	 * @throws EE_Error
86
+	 */
87
+	public function __construct($options_array = array())
88
+	{
89
+		$options_array = (array) apply_filters(
90
+			'FHEE__EE_Form_Section_Proper___construct__options_array',
91
+			$options_array,
92
+			$this
93
+		);
94
+		//call parent first, as it may be setting the name
95
+		parent::__construct($options_array);
96
+		//if they've included subsections in the constructor, add them now
97
+		if (isset($options_array['include'])) {
98
+			//we are going to make sure we ONLY have those subsections to include
99
+			//AND we are going to make sure they're in that specified order
100
+			$reordered_subsections = array();
101
+			foreach ($options_array['include'] as $input_name) {
102
+				if (isset($this->_subsections[ $input_name ])) {
103
+					$reordered_subsections[ $input_name ] = $this->_subsections[ $input_name ];
104
+				}
105
+			}
106
+			$this->_subsections = $reordered_subsections;
107
+		}
108
+		if (isset($options_array['exclude'])) {
109
+			$exclude            = $options_array['exclude'];
110
+			$this->_subsections = array_diff_key($this->_subsections, array_flip($exclude));
111
+		}
112
+		if (isset($options_array['layout_strategy'])) {
113
+			$this->_layout_strategy = $options_array['layout_strategy'];
114
+		}
115
+		if (! $this->_layout_strategy) {
116
+			$this->_layout_strategy = is_admin() ? new EE_Admin_Two_Column_Layout() : new EE_Two_Column_Layout();
117
+		}
118
+		$this->_layout_strategy->_construct_finalize($this);
119
+		//ok so we are definitely going to want the forms JS,
120
+		//so enqueue it or remember to enqueue it during wp_enqueue_scripts
121
+		if (did_action('wp_enqueue_scripts') || did_action('admin_enqueue_scripts')) {
122
+			//ok so they've constructed this object after when they should have.
123
+			//just enqueue the generic form scripts and initialize the form immediately in the JS
124
+			EE_Form_Section_Proper::wp_enqueue_scripts(true);
125
+		} else {
126
+			add_action('wp_enqueue_scripts', array('EE_Form_Section_Proper', 'wp_enqueue_scripts'));
127
+			add_action('admin_enqueue_scripts', array('EE_Form_Section_Proper', 'wp_enqueue_scripts'));
128
+		}
129
+		add_action('wp_footer', array($this, 'ensure_scripts_localized'), 1);
130
+		/**
131
+		 * Gives other plugins a chance to hook in before construct finalize is called.
132
+		 * The form probably doesn't yet have a parent form section.
133
+		 * Since 4.9.32, when this action was introduced, this is the best place to add a subsection onto a form,
134
+		 * assuming you don't care what the form section's name, HTML ID, or HTML name etc are.
135
+		 * Also see AHEE__EE_Form_Section_Proper___construct_finalize__end
136
+		 *
137
+		 * @since 4.9.32
138
+		 * @param EE_Form_Section_Proper $this          before __construct is done, but all of its logic,
139
+		 *                                              except maybe calling _construct_finalize has been done
140
+		 * @param array                  $options_array options passed into the constructor
141
+		 */
142
+		do_action(
143
+			'AHEE__EE_Form_Input_Base___construct__before_construct_finalize_called',
144
+			$this,
145
+			$options_array
146
+		);
147
+		if (isset($options_array['name'])) {
148
+			$this->_construct_finalize(null, $options_array['name']);
149
+		}
150
+	}
151
+
152
+
153
+	/**
154
+	 * Finishes construction given the parent form section and this form section's name
155
+	 *
156
+	 * @param EE_Form_Section_Proper $parent_form_section
157
+	 * @param string                 $name
158
+	 * @throws EE_Error
159
+	 */
160
+	public function _construct_finalize($parent_form_section, $name)
161
+	{
162
+		parent::_construct_finalize($parent_form_section, $name);
163
+		$this->_set_default_name_if_empty();
164
+		$this->_set_default_html_id_if_empty();
165
+		foreach ($this->_subsections as $subsection_name => $subsection) {
166
+			if ($subsection instanceof EE_Form_Section_Base) {
167
+				$subsection->_construct_finalize($this, $subsection_name);
168
+			} else {
169
+				throw new EE_Error(
170
+					sprintf(
171
+						esc_html__(
172
+							'Subsection "%s" is not an instanceof EE_Form_Section_Base on form "%s". It is a "%s"',
173
+							'event_espresso'
174
+						),
175
+						$subsection_name,
176
+						get_class($this),
177
+						$subsection ? get_class($subsection) : esc_html__('NULL', 'event_espresso')
178
+					)
179
+				);
180
+			}
181
+		}
182
+		/**
183
+		 * Action performed just after form has been given a name (and HTML ID etc) and is fully constructed.
184
+		 * If you have code that should modify the form and needs it and its subsections to have a name, HTML ID
185
+		 * (or other attributes derived from the name like the HTML label id, etc), this is where it should be done.
186
+		 * This might only happen just before displaying the form, or just before it receives form submission data.
187
+		 * If you need to modify the form or its subsections before _construct_finalize is called on it (and we've
188
+		 * ensured it has a name, HTML IDs, etc
189
+		 *
190
+		 * @param EE_Form_Section_Proper      $this
191
+		 * @param EE_Form_Section_Proper|null $parent_form_section
192
+		 * @param string                      $name
193
+		 */
194
+		do_action(
195
+			'AHEE__EE_Form_Section_Proper___construct_finalize__end',
196
+			$this,
197
+			$parent_form_section,
198
+			$name
199
+		);
200
+	}
201
+
202
+
203
+	/**
204
+	 * Gets the layout strategy for this form section
205
+	 *
206
+	 * @return EE_Form_Section_Layout_Base
207
+	 */
208
+	public function get_layout_strategy()
209
+	{
210
+		return $this->_layout_strategy;
211
+	}
212
+
213
+
214
+	/**
215
+	 * Gets the HTML for a single input for this form section according
216
+	 * to the layout strategy
217
+	 *
218
+	 * @param EE_Form_Input_Base $input
219
+	 * @return string
220
+	 */
221
+	public function get_html_for_input($input)
222
+	{
223
+		return $this->_layout_strategy->layout_input($input);
224
+	}
225
+
226
+
227
+	/**
228
+	 * was_submitted - checks if form inputs are present in request data
229
+	 * Basically an alias for form_data_present_in() (which is used by both
230
+	 * proper form sections and form inputs)
231
+	 *
232
+	 * @param null $form_data
233
+	 * @return boolean
234
+	 * @throws EE_Error
235
+	 */
236
+	public function was_submitted($form_data = null)
237
+	{
238
+		return $this->form_data_present_in($form_data);
239
+	}
240
+
241
+
242
+	/**
243
+	 * After the form section is initially created, call this to sanitize the data in the submission
244
+	 * which relates to this form section, validate it, and set it as properties on the form.
245
+	 *
246
+	 * @param array|null $req_data should usually be $_POST (the default).
247
+	 *                             However, you CAN supply a different array.
248
+	 *                             Consider using set_defaults() instead however.
249
+	 *                             (If you rendered the form in the page using echo $form_x->get_html()
250
+	 *                             the inputs will have the correct name in the request data for this function
251
+	 *                             to find them and populate the form with them.
252
+	 *                             If you have a flat form (with only input subsections),
253
+	 *                             you can supply a flat array where keys
254
+	 *                             are the form input names and values are their values)
255
+	 * @param boolean    $validate whether or not to perform validation on this data. Default is,
256
+	 *                             of course, to validate that data, and set errors on the invalid values.
257
+	 *                             But if the data has already been validated
258
+	 *                             (eg you validated the data then stored it in the DB)
259
+	 *                             you may want to skip this step.
260
+	 * @throws InvalidArgumentException
261
+	 * @throws InvalidInterfaceException
262
+	 * @throws InvalidDataTypeException
263
+	 * @throws EE_Error
264
+	 */
265
+	public function receive_form_submission($req_data = null, $validate = true)
266
+	{
267
+		$req_data = apply_filters(
268
+			'FHEE__EE_Form_Section_Proper__receive_form_submission__req_data',
269
+			$req_data,
270
+			$this,
271
+			$validate
272
+		);
273
+		if ($req_data === null) {
274
+			$req_data = array_merge($_GET, $_POST);
275
+		}
276
+		$req_data = apply_filters(
277
+			'FHEE__EE_Form_Section_Proper__receive_form_submission__request_data',
278
+			$req_data,
279
+			$this
280
+		);
281
+		$this->_normalize($req_data);
282
+		if ($validate) {
283
+			$this->_validate();
284
+			//if it's invalid, we're going to want to re-display so remember what they submitted
285
+			if (! $this->is_valid()) {
286
+				$this->store_submitted_form_data_in_session();
287
+			}
288
+		}
289
+		do_action(
290
+			'AHEE__EE_Form_Section_Proper__receive_form_submission__end',
291
+			$req_data,
292
+			$this,
293
+			$validate
294
+		);
295
+	}
296
+
297
+
298
+	/**
299
+	 * caches the originally submitted input values in the session
300
+	 * so that they can be used to repopulate the form if it failed validation
301
+	 *
302
+	 * @return boolean whether or not the data was successfully stored in the session
303
+	 * @throws InvalidArgumentException
304
+	 * @throws InvalidInterfaceException
305
+	 * @throws InvalidDataTypeException
306
+	 * @throws EE_Error
307
+	 */
308
+	protected function store_submitted_form_data_in_session()
309
+	{
310
+		return EE_Registry::instance()->SSN->set_session_data(
311
+			array(
312
+				EE_Form_Section_Proper::SUBMITTED_FORM_DATA_SSN_KEY => $this->submitted_values(true),
313
+			)
314
+		);
315
+	}
316
+
317
+
318
+	/**
319
+	 * retrieves the originally submitted input values in the session
320
+	 * so that they can be used to repopulate the form if it failed validation
321
+	 *
322
+	 * @return array
323
+	 * @throws InvalidArgumentException
324
+	 * @throws InvalidInterfaceException
325
+	 * @throws InvalidDataTypeException
326
+	 */
327
+	protected function get_submitted_form_data_from_session()
328
+	{
329
+		$session = EE_Registry::instance()->SSN;
330
+		if ($session instanceof EE_Session) {
331
+			return $session->get_session_data(
332
+				EE_Form_Section_Proper::SUBMITTED_FORM_DATA_SSN_KEY
333
+			);
334
+		}
335
+		return array();
336
+	}
337
+
338
+
339
+	/**
340
+	 * flushed the originally submitted input values from the session
341
+	 *
342
+	 * @return boolean whether or not the data was successfully removed from the session
343
+	 * @throws InvalidArgumentException
344
+	 * @throws InvalidInterfaceException
345
+	 * @throws InvalidDataTypeException
346
+	 */
347
+	protected function flush_submitted_form_data_from_session()
348
+	{
349
+		return EE_Registry::instance()->SSN->reset_data(
350
+			array(EE_Form_Section_Proper::SUBMITTED_FORM_DATA_SSN_KEY)
351
+		);
352
+	}
353
+
354
+
355
+	/**
356
+	 * Populates this form and its subsections with data from the session.
357
+	 * (Wrapper for EE_Form_Section_Proper::receive_form_submission, so it shows
358
+	 * validation errors when displaying too)
359
+	 * Returns true if the form was populated from the session, false otherwise
360
+	 *
361
+	 * @return boolean
362
+	 * @throws InvalidArgumentException
363
+	 * @throws InvalidInterfaceException
364
+	 * @throws InvalidDataTypeException
365
+	 * @throws EE_Error
366
+	 */
367
+	public function populate_from_session()
368
+	{
369
+		$form_data_in_session = $this->get_submitted_form_data_from_session();
370
+		if (empty($form_data_in_session)) {
371
+			return false;
372
+		}
373
+		$this->receive_form_submission($form_data_in_session);
374
+		$this->flush_submitted_form_data_from_session();
375
+		if ($this->form_data_present_in($form_data_in_session)) {
376
+			return true;
377
+		}
378
+		return false;
379
+	}
380
+
381
+
382
+	/**
383
+	 * Populates the default data for the form, given an array where keys are
384
+	 * the input names, and values are their values (preferably normalized to be their
385
+	 * proper PHP types, not all strings... although that should be ok too).
386
+	 * Proper subsections are sub-arrays, the key being the subsection's name, and
387
+	 * the value being an array formatted in teh same way
388
+	 *
389
+	 * @param array $default_data
390
+	 * @throws EE_Error
391
+	 */
392
+	public function populate_defaults($default_data)
393
+	{
394
+		foreach ($this->subsections(false) as $subsection_name => $subsection) {
395
+			if (isset($default_data[ $subsection_name ])) {
396
+				if ($subsection instanceof EE_Form_Input_Base) {
397
+					$subsection->set_default($default_data[ $subsection_name ]);
398
+				} elseif ($subsection instanceof EE_Form_Section_Proper) {
399
+					$subsection->populate_defaults($default_data[ $subsection_name ]);
400
+				}
401
+			}
402
+		}
403
+	}
404
+
405
+
406
+	/**
407
+	 * returns true if subsection exists
408
+	 *
409
+	 * @param string $name
410
+	 * @return boolean
411
+	 */
412
+	public function subsection_exists($name)
413
+	{
414
+		return isset($this->_subsections[ $name ]) ? true : false;
415
+	}
416
+
417
+
418
+	/**
419
+	 * Gets the subsection specified by its name
420
+	 *
421
+	 * @param string  $name
422
+	 * @param boolean $require_construction_to_be_finalized most client code should leave this as TRUE
423
+	 *                                                      so that the inputs will be properly configured.
424
+	 *                                                      However, some client code may be ok
425
+	 *                                                      with construction finalize being called later
426
+	 *                                                      (realizing that the subsections' html names
427
+	 *                                                      might not be set yet, etc.)
428
+	 * @return EE_Form_Section_Base
429
+	 * @throws EE_Error
430
+	 */
431
+	public function get_subsection($name, $require_construction_to_be_finalized = true)
432
+	{
433
+		if ($require_construction_to_be_finalized) {
434
+			$this->ensure_construct_finalized_called();
435
+		}
436
+		return $this->subsection_exists($name) ? $this->_subsections[ $name ] : null;
437
+	}
438
+
439
+
440
+	/**
441
+	 * Gets all the validatable subsections of this form section
442
+	 *
443
+	 * @return EE_Form_Section_Validatable[]
444
+	 * @throws EE_Error
445
+	 */
446
+	public function get_validatable_subsections()
447
+	{
448
+		$validatable_subsections = array();
449
+		foreach ($this->subsections() as $name => $obj) {
450
+			if ($obj instanceof EE_Form_Section_Validatable) {
451
+				$validatable_subsections[ $name ] = $obj;
452
+			}
453
+		}
454
+		return $validatable_subsections;
455
+	}
456
+
457
+
458
+	/**
459
+	 * Gets an input by the given name. If not found, or if its not an EE_FOrm_Input_Base child,
460
+	 * throw an EE_Error.
461
+	 *
462
+	 * @param string  $name
463
+	 * @param boolean $require_construction_to_be_finalized most client code should
464
+	 *                                                      leave this as TRUE so that the inputs will be properly
465
+	 *                                                      configured. However, some client code may be ok with
466
+	 *                                                      construction finalize being called later
467
+	 *                                                      (realizing that the subsections' html names might not be
468
+	 *                                                      set yet, etc.)
469
+	 * @return EE_Form_Input_Base
470
+	 * @throws EE_Error
471
+	 */
472
+	public function get_input($name, $require_construction_to_be_finalized = true)
473
+	{
474
+		$subsection = $this->get_subsection(
475
+			$name,
476
+			$require_construction_to_be_finalized
477
+		);
478
+		if (! $subsection instanceof EE_Form_Input_Base) {
479
+			throw new EE_Error(
480
+				sprintf(
481
+					esc_html__(
482
+						"Subsection '%s' is not an instanceof EE_Form_Input_Base on form '%s'. It is a '%s'",
483
+						'event_espresso'
484
+					),
485
+					$name,
486
+					get_class($this),
487
+					$subsection ? get_class($subsection) : esc_html__('NULL', 'event_espresso')
488
+				)
489
+			);
490
+		}
491
+		return $subsection;
492
+	}
493
+
494
+
495
+	/**
496
+	 * Like get_input(), gets the proper subsection of the form given the name,
497
+	 * otherwise throws an EE_Error
498
+	 *
499
+	 * @param string  $name
500
+	 * @param boolean $require_construction_to_be_finalized most client code should
501
+	 *                                                      leave this as TRUE so that the inputs will be properly
502
+	 *                                                      configured. However, some client code may be ok with
503
+	 *                                                      construction finalize being called later
504
+	 *                                                      (realizing that the subsections' html names might not be
505
+	 *                                                      set yet, etc.)
506
+	 * @return EE_Form_Section_Proper
507
+	 * @throws EE_Error
508
+	 */
509
+	public function get_proper_subsection($name, $require_construction_to_be_finalized = true)
510
+	{
511
+		$subsection = $this->get_subsection(
512
+			$name,
513
+			$require_construction_to_be_finalized
514
+		);
515
+		if (! $subsection instanceof EE_Form_Section_Proper) {
516
+			throw new EE_Error(
517
+				sprintf(
518
+					esc_html__(
519
+						"Subsection '%'s is not an instanceof EE_Form_Section_Proper on form '%s'",
520
+						'event_espresso'
521
+					),
522
+					$name,
523
+					get_class($this)
524
+				)
525
+			);
526
+		}
527
+		return $subsection;
528
+	}
529
+
530
+
531
+	/**
532
+	 * Gets the value of the specified input. Should be called after receive_form_submission()
533
+	 * or populate_defaults() on the form, where the normalized value on the input is set.
534
+	 *
535
+	 * @param string $name
536
+	 * @return mixed depending on the input's type and its normalization strategy
537
+	 * @throws EE_Error
538
+	 */
539
+	public function get_input_value($name)
540
+	{
541
+		$input = $this->get_input($name);
542
+		return $input->normalized_value();
543
+	}
544
+
545
+
546
+	/**
547
+	 * Checks if this form section itself is valid, and then checks its subsections
548
+	 *
549
+	 * @throws EE_Error
550
+	 * @return boolean
551
+	 */
552
+	public function is_valid()
553
+	{
554
+		if (! $this->has_received_submission()) {
555
+			throw new EE_Error(
556
+				sprintf(
557
+					esc_html__(
558
+						'You cannot check if a form is valid before receiving the form submission using receive_form_submission',
559
+						'event_espresso'
560
+					)
561
+				)
562
+			);
563
+		}
564
+		if (! parent::is_valid()) {
565
+			return false;
566
+		}
567
+		// ok so no general errors to this entire form section.
568
+		// so let's check the subsections, but only set errors if that hasn't been done yet
569
+		$set_submission_errors = $this->submission_error_message() === '';
570
+		foreach ($this->get_validatable_subsections() as $subsection) {
571
+			if (! $subsection->is_valid() || $subsection->get_validation_error_string() !== '') {
572
+				if ($set_submission_errors) {
573
+					$this->set_submission_error_message(
574
+						$subsection->get_validation_error_string()
575
+					);
576
+				}
577
+				return false;
578
+			}
579
+		}
580
+		return true;
581
+	}
582
+
583
+
584
+	/**
585
+	 * gets the default name of this form section if none is specified
586
+	 *
587
+	 * @return void
588
+	 */
589
+	protected function _set_default_name_if_empty()
590
+	{
591
+		if (! $this->_name) {
592
+			$classname    = get_class($this);
593
+			$default_name = str_replace('EE_', '', $classname);
594
+			$this->_name  = $default_name;
595
+		}
596
+	}
597
+
598
+
599
+	/**
600
+	 * Returns the HTML for the form, except for the form opening and closing tags
601
+	 * (as the form section doesn't know where you necessarily want to send the information to),
602
+	 * and except for a submit button. Enqueues JS and CSS; if called early enough we will
603
+	 * try to enqueue them in the header, otherwise they'll be enqueued in the footer.
604
+	 * Not doing_it_wrong because theoretically this CAN be used properly,
605
+	 * provided its used during "wp_enqueue_scripts", or it doesn't need to enqueue
606
+	 * any CSS.
607
+	 *
608
+	 * @throws InvalidArgumentException
609
+	 * @throws InvalidInterfaceException
610
+	 * @throws InvalidDataTypeException
611
+	 * @throws EE_Error
612
+	 */
613
+	public function get_html_and_js()
614
+	{
615
+		$this->enqueue_js();
616
+		return $this->get_html();
617
+	}
618
+
619
+
620
+	/**
621
+	 * returns HTML for displaying this form section. recursively calls display_section() on all subsections
622
+	 *
623
+	 * @param bool $display_previously_submitted_data
624
+	 * @return string
625
+	 * @throws InvalidArgumentException
626
+	 * @throws InvalidInterfaceException
627
+	 * @throws InvalidDataTypeException
628
+	 * @throws EE_Error
629
+	 * @throws EE_Error
630
+	 * @throws EE_Error
631
+	 */
632
+	public function get_html($display_previously_submitted_data = true)
633
+	{
634
+		$this->ensure_construct_finalized_called();
635
+		if ($display_previously_submitted_data) {
636
+			$this->populate_from_session();
637
+		}
638
+		return $this->_form_html_filter
639
+			? $this->_form_html_filter->filterHtml($this->_layout_strategy->layout_form(), $this)
640
+			: $this->_layout_strategy->layout_form();
641
+	}
642
+
643
+
644
+	/**
645
+	 * enqueues JS and CSS for the form.
646
+	 * It is preferred to call this before wp_enqueue_scripts so the
647
+	 * scripts and styles can be put in the header, but if called later
648
+	 * they will be put in the footer (which is OK for JS, but in HTML4 CSS should
649
+	 * only be in the header; but in HTML5 its ok in the body.
650
+	 * See http://stackoverflow.com/questions/4957446/load-external-css-file-in-body-tag.
651
+	 * So if your form enqueues CSS, it's preferred to call this before wp_enqueue_scripts.)
652
+	 *
653
+	 * @return void
654
+	 * @throws EE_Error
655
+	 */
656
+	public function enqueue_js()
657
+	{
658
+		$this->_enqueue_and_localize_form_js();
659
+		foreach ($this->subsections() as $subsection) {
660
+			$subsection->enqueue_js();
661
+		}
662
+	}
663
+
664
+
665
+	/**
666
+	 * adds a filter so that jquery validate gets enqueued in EE_System::wp_enqueue_scripts().
667
+	 * This must be done BEFORE wp_enqueue_scripts() gets called, which is on
668
+	 * the wp_enqueue_scripts hook.
669
+	 * However, registering the form js and localizing it can happen when we
670
+	 * actually output the form (which is preferred, seeing how teh form's fields
671
+	 * could change until it's actually outputted)
672
+	 *
673
+	 * @param boolean $init_form_validation_automatically whether or not we want the form validation
674
+	 *                                                    to be triggered automatically or not
675
+	 * @return void
676
+	 */
677
+	public static function wp_enqueue_scripts($init_form_validation_automatically = true)
678
+	{
679
+		wp_register_script(
680
+			'ee_form_section_validation',
681
+			EE_GLOBAL_ASSETS_URL . 'scripts' . DS . 'form_section_validation.js',
682
+			array('jquery-validate', 'jquery-ui-datepicker', 'jquery-validate-extra-methods'),
683
+			EVENT_ESPRESSO_VERSION,
684
+			true
685
+		);
686
+		wp_localize_script(
687
+			'ee_form_section_validation',
688
+			'ee_form_section_validation_init',
689
+			array('init' => $init_form_validation_automatically ? '1' : '0')
690
+		);
691
+	}
692
+
693
+
694
+	/**
695
+	 * gets the variables used by form_section_validation.js.
696
+	 * This needs to be called AFTER we've called $this->_enqueue_jquery_validate_script,
697
+	 * but before the wordpress hook wp_loaded
698
+	 *
699
+	 * @throws EE_Error
700
+	 */
701
+	public function _enqueue_and_localize_form_js()
702
+	{
703
+		$this->ensure_construct_finalized_called();
704
+		//actually, we don't want to localize just yet. There may be other forms on the page.
705
+		//so we need to add our form section data to a static variable accessible by all form sections
706
+		//and localize it just before the footer
707
+		$this->localize_validation_rules();
708
+		add_action('wp_footer', array('EE_Form_Section_Proper', 'localize_script_for_all_forms'), 2);
709
+		add_action('admin_footer', array('EE_Form_Section_Proper', 'localize_script_for_all_forms'));
710
+	}
711
+
712
+
713
+	/**
714
+	 * add our form section data to a static variable accessible by all form sections
715
+	 *
716
+	 * @param bool $return_for_subsection
717
+	 * @return void
718
+	 * @throws EE_Error
719
+	 */
720
+	public function localize_validation_rules($return_for_subsection = false)
721
+	{
722
+		// we only want to localize vars ONCE for the entire form,
723
+		// so if the form section doesn't have a parent, then it must be the top dog
724
+		if ($return_for_subsection || ! $this->parent_section()) {
725
+			EE_Form_Section_Proper::$_js_localization['form_data'][ $this->html_id() ] = array(
726
+				'form_section_id'  => $this->html_id(true),
727
+				'validation_rules' => $this->get_jquery_validation_rules(),
728
+				'other_data'       => $this->get_other_js_data(),
729
+				'errors'           => $this->subsection_validation_errors_by_html_name(),
730
+			);
731
+			EE_Form_Section_Proper::$_scripts_localized                                = true;
732
+		}
733
+	}
734
+
735
+
736
+	/**
737
+	 * Gets an array of extra data that will be useful for client-side javascript.
738
+	 * This is primarily data added by inputs and forms in addition to any
739
+	 * scripts they might enqueue
740
+	 *
741
+	 * @param array $form_other_js_data
742
+	 * @return array
743
+	 * @throws EE_Error
744
+	 */
745
+	public function get_other_js_data($form_other_js_data = array())
746
+	{
747
+		foreach ($this->subsections() as $subsection) {
748
+			$form_other_js_data = $subsection->get_other_js_data($form_other_js_data);
749
+		}
750
+		return $form_other_js_data;
751
+	}
752
+
753
+
754
+	/**
755
+	 * Gets a flat array of inputs for this form section and its subsections.
756
+	 * Keys are their form names, and values are the inputs themselves
757
+	 *
758
+	 * @return EE_Form_Input_Base
759
+	 * @throws EE_Error
760
+	 */
761
+	public function inputs_in_subsections()
762
+	{
763
+		$inputs = array();
764
+		foreach ($this->subsections() as $subsection) {
765
+			if ($subsection instanceof EE_Form_Input_Base) {
766
+				$inputs[ $subsection->html_name() ] = $subsection;
767
+			} elseif ($subsection instanceof EE_Form_Section_Proper) {
768
+				$inputs += $subsection->inputs_in_subsections();
769
+			}
770
+		}
771
+		return $inputs;
772
+	}
773
+
774
+
775
+	/**
776
+	 * Gets a flat array of all the validation errors.
777
+	 * Keys are html names (because those should be unique)
778
+	 * and values are a string of all their validation errors
779
+	 *
780
+	 * @return string[]
781
+	 * @throws EE_Error
782
+	 */
783
+	public function subsection_validation_errors_by_html_name()
784
+	{
785
+		$inputs = $this->inputs();
786
+		$errors = array();
787
+		foreach ($inputs as $form_input) {
788
+			if ($form_input instanceof EE_Form_Input_Base && $form_input->get_validation_errors()) {
789
+				$errors[ $form_input->html_name() ] = $form_input->get_validation_error_string();
790
+			}
791
+		}
792
+		return $errors;
793
+	}
794
+
795
+
796
+	/**
797
+	 * passes all the form data required by the JS to the JS, and enqueues the few required JS files.
798
+	 * Should be setup by each form during the _enqueues_and_localize_form_js
799
+	 *
800
+	 * @throws InvalidArgumentException
801
+	 * @throws InvalidInterfaceException
802
+	 * @throws InvalidDataTypeException
803
+	 */
804
+	public static function localize_script_for_all_forms()
805
+	{
806
+		//allow inputs and stuff to hook in their JS and stuff here
807
+		do_action('AHEE__EE_Form_Section_Proper__localize_script_for_all_forms__begin');
808
+		EE_Form_Section_Proper::$_js_localization['localized_error_messages'] = EE_Form_Section_Proper::_get_localized_error_messages();
809
+		$email_validation_level = isset(EE_Registry::instance()->CFG->registration->email_validation_level)
810
+			? EE_Registry::instance()->CFG->registration->email_validation_level
811
+			: 'wp_default';
812
+		EE_Form_Section_Proper::$_js_localization['email_validation_level']   = $email_validation_level;
813
+		wp_enqueue_script('ee_form_section_validation');
814
+		wp_localize_script(
815
+			'ee_form_section_validation',
816
+			'ee_form_section_vars',
817
+			EE_Form_Section_Proper::$_js_localization
818
+		);
819
+	}
820
+
821
+
822
+	/**
823
+	 * ensure_scripts_localized
824
+	 *
825
+	 * @throws EE_Error
826
+	 */
827
+	public function ensure_scripts_localized()
828
+	{
829
+		if (! EE_Form_Section_Proper::$_scripts_localized) {
830
+			$this->_enqueue_and_localize_form_js();
831
+		}
832
+	}
833
+
834
+
835
+	/**
836
+	 * Gets the hard-coded validation error messages to be used in the JS. The convention
837
+	 * is that the key here should be the same as the custom validation rule put in the JS file
838
+	 *
839
+	 * @return array keys are custom validation rules, and values are internationalized strings
840
+	 */
841
+	private static function _get_localized_error_messages()
842
+	{
843
+		return array(
844
+			'validUrl' => esc_html__('This is not a valid absolute URL. Eg, http://domain.com/monkey.jpg', 'event_espresso'),
845
+			'regex'    => esc_html__('Please check your input', 'event_espresso'),
846
+		);
847
+	}
848
+
849
+
850
+	/**
851
+	 * @return array
852
+	 */
853
+	public static function js_localization()
854
+	{
855
+		return self::$_js_localization;
856
+	}
857
+
858
+
859
+	/**
860
+	 * @return void
861
+	 */
862
+	public static function reset_js_localization()
863
+	{
864
+		self::$_js_localization = array();
865
+	}
866
+
867
+
868
+	/**
869
+	 * Gets the JS to put inside the jquery validation rules for subsection of this form section.
870
+	 * See parent function for more...
871
+	 *
872
+	 * @return array
873
+	 * @throws EE_Error
874
+	 */
875
+	public function get_jquery_validation_rules()
876
+	{
877
+		$jquery_validation_rules = array();
878
+		foreach ($this->get_validatable_subsections() as $subsection) {
879
+			$jquery_validation_rules = array_merge(
880
+				$jquery_validation_rules,
881
+				$subsection->get_jquery_validation_rules()
882
+			);
883
+		}
884
+		return $jquery_validation_rules;
885
+	}
886
+
887
+
888
+	/**
889
+	 * Sanitizes all the data and sets the sanitized value of each field
890
+	 *
891
+	 * @param array $req_data like $_POST
892
+	 * @return void
893
+	 * @throws EE_Error
894
+	 */
895
+	protected function _normalize($req_data)
896
+	{
897
+		$this->_received_submission = true;
898
+		$this->_validation_errors   = array();
899
+		foreach ($this->get_validatable_subsections() as $subsection) {
900
+			try {
901
+				$subsection->_normalize($req_data);
902
+			} catch (EE_Validation_Error $e) {
903
+				$subsection->add_validation_error($e);
904
+			}
905
+		}
906
+	}
907
+
908
+
909
+	/**
910
+	 * Performs validation on this form section and its subsections.
911
+	 * For each subsection,
912
+	 * calls _validate_{subsection_name} on THIS form (if the function exists)
913
+	 * and passes it the subsection, then calls _validate on that subsection.
914
+	 * If you need to perform validation on the form as a whole (considering multiple)
915
+	 * you would be best to override this _validate method,
916
+	 * calling parent::_validate() first.
917
+	 *
918
+	 * @throws EE_Error
919
+	 */
920
+	protected function _validate()
921
+	{
922
+		foreach ($this->get_validatable_subsections() as $subsection_name => $subsection) {
923
+			if (method_exists($this, '_validate_' . $subsection_name)) {
924
+				call_user_func_array(array($this, '_validate_' . $subsection_name), array($subsection));
925
+			}
926
+			$subsection->_validate();
927
+		}
928
+	}
929
+
930
+
931
+	/**
932
+	 * Gets all the validated inputs for the form section
933
+	 *
934
+	 * @return array
935
+	 * @throws EE_Error
936
+	 */
937
+	public function valid_data()
938
+	{
939
+		$inputs = array();
940
+		foreach ($this->subsections() as $subsection_name => $subsection) {
941
+			if ($subsection instanceof EE_Form_Section_Proper) {
942
+				$inputs[ $subsection_name ] = $subsection->valid_data();
943
+			} elseif ($subsection instanceof EE_Form_Input_Base) {
944
+				$inputs[ $subsection_name ] = $subsection->normalized_value();
945
+			}
946
+		}
947
+		return $inputs;
948
+	}
949
+
950
+
951
+	/**
952
+	 * Gets all the inputs on this form section
953
+	 *
954
+	 * @return EE_Form_Input_Base[]
955
+	 * @throws EE_Error
956
+	 */
957
+	public function inputs()
958
+	{
959
+		$inputs = array();
960
+		foreach ($this->subsections() as $subsection_name => $subsection) {
961
+			if ($subsection instanceof EE_Form_Input_Base) {
962
+				$inputs[ $subsection_name ] = $subsection;
963
+			}
964
+		}
965
+		return $inputs;
966
+	}
967
+
968
+
969
+	/**
970
+	 * Gets all the subsections which are a proper form
971
+	 *
972
+	 * @return EE_Form_Section_Proper[]
973
+	 * @throws EE_Error
974
+	 */
975
+	public function subforms()
976
+	{
977
+		$form_sections = array();
978
+		foreach ($this->subsections() as $name => $obj) {
979
+			if ($obj instanceof EE_Form_Section_Proper) {
980
+				$form_sections[ $name ] = $obj;
981
+			}
982
+		}
983
+		return $form_sections;
984
+	}
985
+
986
+
987
+	/**
988
+	 * Gets all the subsections (inputs, proper subsections, or html-only sections).
989
+	 * Consider using inputs() or subforms()
990
+	 * if you only want form inputs or proper form sections.
991
+	 *
992
+	 * @param boolean $require_construction_to_be_finalized most client code should
993
+	 *                                                      leave this as TRUE so that the inputs will be properly
994
+	 *                                                      configured. However, some client code may be ok with
995
+	 *                                                      construction finalize being called later
996
+	 *                                                      (realizing that the subsections' html names might not be
997
+	 *                                                      set yet, etc.)
998
+	 * @return EE_Form_Section_Proper[]
999
+	 * @throws EE_Error
1000
+	 */
1001
+	public function subsections($require_construction_to_be_finalized = true)
1002
+	{
1003
+		if ($require_construction_to_be_finalized) {
1004
+			$this->ensure_construct_finalized_called();
1005
+		}
1006
+		return $this->_subsections;
1007
+	}
1008
+
1009
+
1010
+	/**
1011
+	 * Returns a simple array where keys are input names, and values are their normalized
1012
+	 * values. (Similar to calling get_input_value on inputs)
1013
+	 *
1014
+	 * @param boolean $include_subform_inputs Whether to include inputs from subforms,
1015
+	 *                                        or just this forms' direct children inputs
1016
+	 * @param boolean $flatten                Whether to force the results into 1-dimensional array,
1017
+	 *                                        or allow multidimensional array
1018
+	 * @return array if $flatten is TRUE it will always be a 1-dimensional array
1019
+	 *                                        with array keys being input names
1020
+	 *                                        (regardless of whether they are from a subsection or not),
1021
+	 *                                        and if $flatten is FALSE it can be a multidimensional array
1022
+	 *                                        where keys are always subsection names and values are either
1023
+	 *                                        the input's normalized value, or an array like the top-level array
1024
+	 * @throws EE_Error
1025
+	 */
1026
+	public function input_values($include_subform_inputs = false, $flatten = false)
1027
+	{
1028
+		return $this->_input_values(false, $include_subform_inputs, $flatten);
1029
+	}
1030
+
1031
+
1032
+	/**
1033
+	 * Similar to EE_Form_Section_Proper::input_values(), except this returns the 'display_value'
1034
+	 * of each input. On some inputs (especially radio boxes or checkboxes), the value stored
1035
+	 * is not necessarily the value we want to display to users. This creates an array
1036
+	 * where keys are the input names, and values are their display values
1037
+	 *
1038
+	 * @param boolean $include_subform_inputs Whether to include inputs from subforms,
1039
+	 *                                        or just this forms' direct children inputs
1040
+	 * @param boolean $flatten                Whether to force the results into 1-dimensional array,
1041
+	 *                                        or allow multidimensional array
1042
+	 * @return array if $flatten is TRUE it will always be a 1-dimensional array
1043
+	 *                                        with array keys being input names
1044
+	 *                                        (regardless of whether they are from a subsection or not),
1045
+	 *                                        and if $flatten is FALSE it can be a multidimensional array
1046
+	 *                                        where keys are always subsection names and values are either
1047
+	 *                                        the input's normalized value, or an array like the top-level array
1048
+	 * @throws EE_Error
1049
+	 */
1050
+	public function input_pretty_values($include_subform_inputs = false, $flatten = false)
1051
+	{
1052
+		return $this->_input_values(true, $include_subform_inputs, $flatten);
1053
+	}
1054
+
1055
+
1056
+	/**
1057
+	 * Gets the input values from the form
1058
+	 *
1059
+	 * @param boolean $pretty                 Whether to retrieve the pretty value,
1060
+	 *                                        or just the normalized value
1061
+	 * @param boolean $include_subform_inputs Whether to include inputs from subforms,
1062
+	 *                                        or just this forms' direct children inputs
1063
+	 * @param boolean $flatten                Whether to force the results into 1-dimensional array,
1064
+	 *                                        or allow multidimensional array
1065
+	 * @return array if $flatten is TRUE it will always be a 1-dimensional array with array keys being
1066
+	 *                                        input names (regardless of whether they are from a subsection or not),
1067
+	 *                                        and if $flatten is FALSE it can be a multidimensional array
1068
+	 *                                        where keys are always subsection names and values are either
1069
+	 *                                        the input's normalized value, or an array like the top-level array
1070
+	 * @throws EE_Error
1071
+	 */
1072
+	public function _input_values($pretty = false, $include_subform_inputs = false, $flatten = false)
1073
+	{
1074
+		$input_values = array();
1075
+		foreach ($this->subsections() as $subsection_name => $subsection) {
1076
+			if ($subsection instanceof EE_Form_Input_Base) {
1077
+				$input_values[ $subsection_name ] = $pretty
1078
+					? $subsection->pretty_value()
1079
+					: $subsection->normalized_value();
1080
+			} elseif ($subsection instanceof EE_Form_Section_Proper && $include_subform_inputs) {
1081
+				$subform_input_values = $subsection->_input_values(
1082
+					$pretty,
1083
+					$include_subform_inputs,
1084
+					$flatten
1085
+				);
1086
+				if ($flatten) {
1087
+					$input_values = array_merge($input_values, $subform_input_values);
1088
+				} else {
1089
+					$input_values[ $subsection_name ] = $subform_input_values;
1090
+				}
1091
+			}
1092
+		}
1093
+		return $input_values;
1094
+	}
1095
+
1096
+
1097
+	/**
1098
+	 * Gets the originally submitted input values from the form
1099
+	 *
1100
+	 * @param boolean $include_subforms  Whether to include inputs from subforms,
1101
+	 *                                   or just this forms' direct children inputs
1102
+	 * @return array                     if $flatten is TRUE it will always be a 1-dimensional array
1103
+	 *                                   with array keys being input names
1104
+	 *                                   (regardless of whether they are from a subsection or not),
1105
+	 *                                   and if $flatten is FALSE it can be a multidimensional array
1106
+	 *                                   where keys are always subsection names and values are either
1107
+	 *                                   the input's normalized value, or an array like the top-level array
1108
+	 * @throws EE_Error
1109
+	 */
1110
+	public function submitted_values($include_subforms = false)
1111
+	{
1112
+		$submitted_values = array();
1113
+		foreach ($this->subsections() as $subsection) {
1114
+			if ($subsection instanceof EE_Form_Input_Base) {
1115
+				// is this input part of an array of inputs?
1116
+				if (strpos($subsection->html_name(), '[') !== false) {
1117
+					$full_input_name  = EEH_Array::convert_array_values_to_keys(
1118
+						explode(
1119
+							'[',
1120
+							str_replace(']', '', $subsection->html_name())
1121
+						),
1122
+						$subsection->raw_value()
1123
+					);
1124
+					$submitted_values = array_replace_recursive($submitted_values, $full_input_name);
1125
+				} else {
1126
+					$submitted_values[ $subsection->html_name() ] = $subsection->raw_value();
1127
+				}
1128
+			} elseif ($subsection instanceof EE_Form_Section_Proper && $include_subforms) {
1129
+				$subform_input_values = $subsection->submitted_values($include_subforms);
1130
+				$submitted_values     = array_replace_recursive($submitted_values, $subform_input_values);
1131
+			}
1132
+		}
1133
+		return $submitted_values;
1134
+	}
1135
+
1136
+
1137
+	/**
1138
+	 * Indicates whether or not this form has received a submission yet
1139
+	 * (ie, had receive_form_submission called on it yet)
1140
+	 *
1141
+	 * @return boolean
1142
+	 * @throws EE_Error
1143
+	 */
1144
+	public function has_received_submission()
1145
+	{
1146
+		$this->ensure_construct_finalized_called();
1147
+		return $this->_received_submission;
1148
+	}
1149
+
1150
+
1151
+	/**
1152
+	 * Equivalent to passing 'exclude' in the constructor's options array.
1153
+	 * Removes the listed inputs from the form
1154
+	 *
1155
+	 * @param array $inputs_to_exclude values are the input names
1156
+	 * @return void
1157
+	 */
1158
+	public function exclude(array $inputs_to_exclude = array())
1159
+	{
1160
+		foreach ($inputs_to_exclude as $input_to_exclude_name) {
1161
+			unset($this->_subsections[ $input_to_exclude_name ]);
1162
+		}
1163
+	}
1164
+
1165
+
1166
+	/**
1167
+	 * @param array $inputs_to_hide
1168
+	 * @throws EE_Error
1169
+	 */
1170
+	public function hide(array $inputs_to_hide = array())
1171
+	{
1172
+		foreach ($inputs_to_hide as $input_to_hide) {
1173
+			$input = $this->get_input($input_to_hide);
1174
+			$input->set_display_strategy(new EE_Hidden_Display_Strategy());
1175
+		}
1176
+	}
1177
+
1178
+
1179
+	/**
1180
+	 * add_subsections
1181
+	 * Adds the listed subsections to the form section.
1182
+	 * If $subsection_name_to_target is provided,
1183
+	 * then new subsections are added before or after that subsection,
1184
+	 * otherwise to the start or end of the entire subsections array.
1185
+	 *
1186
+	 * @param EE_Form_Section_Base[] $new_subsections           array of new form subsections
1187
+	 *                                                          where keys are their names
1188
+	 * @param string                 $subsection_name_to_target an existing for section that $new_subsections
1189
+	 *                                                          should be added before or after
1190
+	 *                                                          IF $subsection_name_to_target is null,
1191
+	 *                                                          then $new_subsections will be added to
1192
+	 *                                                          the beginning or end of the entire subsections array
1193
+	 * @param boolean                $add_before                whether to add $new_subsections, before or after
1194
+	 *                                                          $subsection_name_to_target,
1195
+	 *                                                          or if $subsection_name_to_target is null,
1196
+	 *                                                          before or after entire subsections array
1197
+	 * @return void
1198
+	 * @throws EE_Error
1199
+	 */
1200
+	public function add_subsections($new_subsections, $subsection_name_to_target = null, $add_before = true)
1201
+	{
1202
+		foreach ($new_subsections as $subsection_name => $subsection) {
1203
+			if (! $subsection instanceof EE_Form_Section_Base) {
1204
+				EE_Error::add_error(
1205
+					sprintf(
1206
+						esc_html__(
1207
+							"Trying to add a %s as a subsection (it was named '%s') to the form section '%s'. It was removed.",
1208
+							'event_espresso'
1209
+						),
1210
+						get_class($subsection),
1211
+						$subsection_name,
1212
+						$this->name()
1213
+					)
1214
+				);
1215
+				unset($new_subsections[ $subsection_name ]);
1216
+			}
1217
+		}
1218
+		$this->_subsections = EEH_Array::insert_into_array(
1219
+			$this->_subsections,
1220
+			$new_subsections,
1221
+			$subsection_name_to_target,
1222
+			$add_before
1223
+		);
1224
+		if ($this->_construction_finalized) {
1225
+			foreach ($this->_subsections as $name => $subsection) {
1226
+				$subsection->_construct_finalize($this, $name);
1227
+			}
1228
+		}
1229
+	}
1230
+
1231
+
1232
+	/**
1233
+	 * Just gets all validatable subsections to clean their sensitive data
1234
+	 *
1235
+	 * @throws EE_Error
1236
+	 */
1237
+	public function clean_sensitive_data()
1238
+	{
1239
+		foreach ($this->get_validatable_subsections() as $subsection) {
1240
+			$subsection->clean_sensitive_data();
1241
+		}
1242
+	}
1243
+
1244
+
1245
+	/**
1246
+	 * @param string $form_submission_error_message
1247
+	 */
1248
+	public function set_submission_error_message($form_submission_error_message = '')
1249
+	{
1250
+		$this->_form_submission_error_message .= ! empty($form_submission_error_message)
1251
+			? $form_submission_error_message
1252
+			: esc_html__('Form submission failed due to errors', 'event_espresso');
1253
+	}
1254
+
1255
+
1256
+	/**
1257
+	 * @return string
1258
+	 */
1259
+	public function submission_error_message()
1260
+	{
1261
+		return $this->_form_submission_error_message;
1262
+	}
1263
+
1264
+
1265
+	/**
1266
+	 * @param string $form_submission_success_message
1267
+	 */
1268
+	public function set_submission_success_message($form_submission_success_message)
1269
+	{
1270
+		$this->_form_submission_success_message .= ! empty($form_submission_success_message)
1271
+			? $form_submission_success_message
1272
+			: esc_html__('Form submitted successfully', 'event_espresso');
1273
+	}
1274
+
1275
+
1276
+	/**
1277
+	 * @return string
1278
+	 */
1279
+	public function submission_success_message()
1280
+	{
1281
+		return $this->_form_submission_success_message;
1282
+	}
1283
+
1284
+
1285
+	/**
1286
+	 * Returns the prefix that should be used on child of this form section for
1287
+	 * their html names. If this form section itself has a parent, prepends ITS
1288
+	 * prefix onto this form section's prefix. Used primarily by
1289
+	 * EE_Form_Input_Base::_set_default_html_name_if_empty
1290
+	 *
1291
+	 * @return string
1292
+	 * @throws EE_Error
1293
+	 */
1294
+	public function html_name_prefix()
1295
+	{
1296
+		if ($this->parent_section() instanceof EE_Form_Section_Proper) {
1297
+			return $this->parent_section()->html_name_prefix() . '[' . $this->name() . ']';
1298
+		}
1299
+		return $this->name();
1300
+	}
1301
+
1302
+
1303
+	/**
1304
+	 * Gets the name, but first checks _construct_finalize has been called. If not,
1305
+	 * calls it (assumes there is no parent and that we want the name to be whatever
1306
+	 * was set, which is probably nothing, or the classname)
1307
+	 *
1308
+	 * @return string
1309
+	 * @throws EE_Error
1310
+	 */
1311
+	public function name()
1312
+	{
1313
+		$this->ensure_construct_finalized_called();
1314
+		return parent::name();
1315
+	}
1316
+
1317
+
1318
+	/**
1319
+	 * @return EE_Form_Section_Proper
1320
+	 * @throws EE_Error
1321
+	 */
1322
+	public function parent_section()
1323
+	{
1324
+		$this->ensure_construct_finalized_called();
1325
+		return parent::parent_section();
1326
+	}
1327
+
1328
+
1329
+	/**
1330
+	 * make sure construction finalized was called, otherwise children might not be ready
1331
+	 *
1332
+	 * @return void
1333
+	 * @throws EE_Error
1334
+	 */
1335
+	public function ensure_construct_finalized_called()
1336
+	{
1337
+		if (! $this->_construction_finalized) {
1338
+			$this->_construct_finalize($this->_parent_section, $this->_name);
1339
+		}
1340
+	}
1341
+
1342
+
1343
+	/**
1344
+	 * Checks if any of this form section's inputs, or any of its children's inputs,
1345
+	 * are in teh form data. If any are found, returns true. Else false
1346
+	 *
1347
+	 * @param array $req_data
1348
+	 * @return boolean
1349
+	 * @throws EE_Error
1350
+	 */
1351
+	public function form_data_present_in($req_data = null)
1352
+	{
1353
+		if ($req_data === null) {
1354
+			$req_data = $_POST;
1355
+		}
1356
+		foreach ($this->subsections() as $subsection) {
1357
+			if ($subsection instanceof EE_Form_Input_Base) {
1358
+				if ($subsection->form_data_present_in($req_data)) {
1359
+					return true;
1360
+				}
1361
+			} elseif ($subsection instanceof EE_Form_Section_Proper) {
1362
+				if ($subsection->form_data_present_in($req_data)) {
1363
+					return true;
1364
+				}
1365
+			}
1366
+		}
1367
+		return false;
1368
+	}
1369
+
1370
+
1371
+	/**
1372
+	 * Gets validation errors for this form section and subsections
1373
+	 * Similar to EE_Form_Section_Validatable::get_validation_errors() except this
1374
+	 * gets the validation errors for ALL subsection
1375
+	 *
1376
+	 * @return EE_Validation_Error[]
1377
+	 * @throws EE_Error
1378
+	 */
1379
+	public function get_validation_errors_accumulated()
1380
+	{
1381
+		$validation_errors = $this->get_validation_errors();
1382
+		foreach ($this->get_validatable_subsections() as $subsection) {
1383
+			if ($subsection instanceof EE_Form_Section_Proper) {
1384
+				$validation_errors_on_this_subsection = $subsection->get_validation_errors_accumulated();
1385
+			} else {
1386
+				$validation_errors_on_this_subsection = $subsection->get_validation_errors();
1387
+			}
1388
+			if ($validation_errors_on_this_subsection) {
1389
+				$validation_errors = array_merge($validation_errors, $validation_errors_on_this_subsection);
1390
+			}
1391
+		}
1392
+		return $validation_errors;
1393
+	}
1394
+
1395
+
1396
+	/**
1397
+	 * This isn't just the name of an input, it's a path pointing to an input. The
1398
+	 * path is similar to a folder path: slash (/) means to descend into a subsection,
1399
+	 * dot-dot-slash (../) means to ascend into the parent section.
1400
+	 * After a series of slashes and dot-dot-slashes, there should be the name of an input,
1401
+	 * which will be returned.
1402
+	 * Eg, if you want the related input to be conditional on a sibling input name 'foobar'
1403
+	 * just use 'foobar'. If you want it to be conditional on an aunt/uncle input name
1404
+	 * 'baz', use '../baz'. If you want it to be conditional on a cousin input,
1405
+	 * the child of 'baz_section' named 'baz_child', use '../baz_section/baz_child'.
1406
+	 * Etc
1407
+	 *
1408
+	 * @param string|false $form_section_path we accept false also because substr( '../', '../' ) = false
1409
+	 * @return EE_Form_Section_Base
1410
+	 * @throws EE_Error
1411
+	 */
1412
+	public function find_section_from_path($form_section_path)
1413
+	{
1414
+		//check if we can find the input from purely going straight up the tree
1415
+		$input = parent::find_section_from_path($form_section_path);
1416
+		if ($input instanceof EE_Form_Section_Base) {
1417
+			return $input;
1418
+		}
1419
+		$next_slash_pos = strpos($form_section_path, '/');
1420
+		if ($next_slash_pos !== false) {
1421
+			$child_section_name = substr($form_section_path, 0, $next_slash_pos);
1422
+			$subpath            = substr($form_section_path, $next_slash_pos + 1);
1423
+		} else {
1424
+			$child_section_name = $form_section_path;
1425
+			$subpath            = '';
1426
+		}
1427
+		$child_section = $this->get_subsection($child_section_name);
1428
+		if ($child_section instanceof EE_Form_Section_Base) {
1429
+			return $child_section->find_section_from_path($subpath);
1430
+		}
1431
+		return null;
1432
+	}
1433 1433
 }
1434 1434
 
Please login to merge, or discard this patch.
Spacing   +38 added lines, -38 removed lines patch added patch discarded remove patch
@@ -99,8 +99,8 @@  discard block
 block discarded – undo
99 99
             //AND we are going to make sure they're in that specified order
100 100
             $reordered_subsections = array();
101 101
             foreach ($options_array['include'] as $input_name) {
102
-                if (isset($this->_subsections[ $input_name ])) {
103
-                    $reordered_subsections[ $input_name ] = $this->_subsections[ $input_name ];
102
+                if (isset($this->_subsections[$input_name])) {
103
+                    $reordered_subsections[$input_name] = $this->_subsections[$input_name];
104 104
                 }
105 105
             }
106 106
             $this->_subsections = $reordered_subsections;
@@ -112,7 +112,7 @@  discard block
 block discarded – undo
112 112
         if (isset($options_array['layout_strategy'])) {
113 113
             $this->_layout_strategy = $options_array['layout_strategy'];
114 114
         }
115
-        if (! $this->_layout_strategy) {
115
+        if ( ! $this->_layout_strategy) {
116 116
             $this->_layout_strategy = is_admin() ? new EE_Admin_Two_Column_Layout() : new EE_Two_Column_Layout();
117 117
         }
118 118
         $this->_layout_strategy->_construct_finalize($this);
@@ -282,7 +282,7 @@  discard block
 block discarded – undo
282 282
         if ($validate) {
283 283
             $this->_validate();
284 284
             //if it's invalid, we're going to want to re-display so remember what they submitted
285
-            if (! $this->is_valid()) {
285
+            if ( ! $this->is_valid()) {
286 286
                 $this->store_submitted_form_data_in_session();
287 287
             }
288 288
         }
@@ -392,11 +392,11 @@  discard block
 block discarded – undo
392 392
     public function populate_defaults($default_data)
393 393
     {
394 394
         foreach ($this->subsections(false) as $subsection_name => $subsection) {
395
-            if (isset($default_data[ $subsection_name ])) {
395
+            if (isset($default_data[$subsection_name])) {
396 396
                 if ($subsection instanceof EE_Form_Input_Base) {
397
-                    $subsection->set_default($default_data[ $subsection_name ]);
397
+                    $subsection->set_default($default_data[$subsection_name]);
398 398
                 } elseif ($subsection instanceof EE_Form_Section_Proper) {
399
-                    $subsection->populate_defaults($default_data[ $subsection_name ]);
399
+                    $subsection->populate_defaults($default_data[$subsection_name]);
400 400
                 }
401 401
             }
402 402
         }
@@ -411,7 +411,7 @@  discard block
 block discarded – undo
411 411
      */
412 412
     public function subsection_exists($name)
413 413
     {
414
-        return isset($this->_subsections[ $name ]) ? true : false;
414
+        return isset($this->_subsections[$name]) ? true : false;
415 415
     }
416 416
 
417 417
 
@@ -433,7 +433,7 @@  discard block
 block discarded – undo
433 433
         if ($require_construction_to_be_finalized) {
434 434
             $this->ensure_construct_finalized_called();
435 435
         }
436
-        return $this->subsection_exists($name) ? $this->_subsections[ $name ] : null;
436
+        return $this->subsection_exists($name) ? $this->_subsections[$name] : null;
437 437
     }
438 438
 
439 439
 
@@ -448,7 +448,7 @@  discard block
 block discarded – undo
448 448
         $validatable_subsections = array();
449 449
         foreach ($this->subsections() as $name => $obj) {
450 450
             if ($obj instanceof EE_Form_Section_Validatable) {
451
-                $validatable_subsections[ $name ] = $obj;
451
+                $validatable_subsections[$name] = $obj;
452 452
             }
453 453
         }
454 454
         return $validatable_subsections;
@@ -475,7 +475,7 @@  discard block
 block discarded – undo
475 475
             $name,
476 476
             $require_construction_to_be_finalized
477 477
         );
478
-        if (! $subsection instanceof EE_Form_Input_Base) {
478
+        if ( ! $subsection instanceof EE_Form_Input_Base) {
479 479
             throw new EE_Error(
480 480
                 sprintf(
481 481
                     esc_html__(
@@ -512,7 +512,7 @@  discard block
 block discarded – undo
512 512
             $name,
513 513
             $require_construction_to_be_finalized
514 514
         );
515
-        if (! $subsection instanceof EE_Form_Section_Proper) {
515
+        if ( ! $subsection instanceof EE_Form_Section_Proper) {
516 516
             throw new EE_Error(
517 517
                 sprintf(
518 518
                     esc_html__(
@@ -551,7 +551,7 @@  discard block
 block discarded – undo
551 551
      */
552 552
     public function is_valid()
553 553
     {
554
-        if (! $this->has_received_submission()) {
554
+        if ( ! $this->has_received_submission()) {
555 555
             throw new EE_Error(
556 556
                 sprintf(
557 557
                     esc_html__(
@@ -561,14 +561,14 @@  discard block
 block discarded – undo
561 561
                 )
562 562
             );
563 563
         }
564
-        if (! parent::is_valid()) {
564
+        if ( ! parent::is_valid()) {
565 565
             return false;
566 566
         }
567 567
         // ok so no general errors to this entire form section.
568 568
         // so let's check the subsections, but only set errors if that hasn't been done yet
569 569
         $set_submission_errors = $this->submission_error_message() === '';
570 570
         foreach ($this->get_validatable_subsections() as $subsection) {
571
-            if (! $subsection->is_valid() || $subsection->get_validation_error_string() !== '') {
571
+            if ( ! $subsection->is_valid() || $subsection->get_validation_error_string() !== '') {
572 572
                 if ($set_submission_errors) {
573 573
                     $this->set_submission_error_message(
574 574
                         $subsection->get_validation_error_string()
@@ -588,7 +588,7 @@  discard block
 block discarded – undo
588 588
      */
589 589
     protected function _set_default_name_if_empty()
590 590
     {
591
-        if (! $this->_name) {
591
+        if ( ! $this->_name) {
592 592
             $classname    = get_class($this);
593 593
             $default_name = str_replace('EE_', '', $classname);
594 594
             $this->_name  = $default_name;
@@ -678,7 +678,7 @@  discard block
 block discarded – undo
678 678
     {
679 679
         wp_register_script(
680 680
             'ee_form_section_validation',
681
-            EE_GLOBAL_ASSETS_URL . 'scripts' . DS . 'form_section_validation.js',
681
+            EE_GLOBAL_ASSETS_URL.'scripts'.DS.'form_section_validation.js',
682 682
             array('jquery-validate', 'jquery-ui-datepicker', 'jquery-validate-extra-methods'),
683 683
             EVENT_ESPRESSO_VERSION,
684 684
             true
@@ -722,13 +722,13 @@  discard block
 block discarded – undo
722 722
         // we only want to localize vars ONCE for the entire form,
723 723
         // so if the form section doesn't have a parent, then it must be the top dog
724 724
         if ($return_for_subsection || ! $this->parent_section()) {
725
-            EE_Form_Section_Proper::$_js_localization['form_data'][ $this->html_id() ] = array(
725
+            EE_Form_Section_Proper::$_js_localization['form_data'][$this->html_id()] = array(
726 726
                 'form_section_id'  => $this->html_id(true),
727 727
                 'validation_rules' => $this->get_jquery_validation_rules(),
728 728
                 'other_data'       => $this->get_other_js_data(),
729 729
                 'errors'           => $this->subsection_validation_errors_by_html_name(),
730 730
             );
731
-            EE_Form_Section_Proper::$_scripts_localized                                = true;
731
+            EE_Form_Section_Proper::$_scripts_localized = true;
732 732
         }
733 733
     }
734 734
 
@@ -763,7 +763,7 @@  discard block
 block discarded – undo
763 763
         $inputs = array();
764 764
         foreach ($this->subsections() as $subsection) {
765 765
             if ($subsection instanceof EE_Form_Input_Base) {
766
-                $inputs[ $subsection->html_name() ] = $subsection;
766
+                $inputs[$subsection->html_name()] = $subsection;
767 767
             } elseif ($subsection instanceof EE_Form_Section_Proper) {
768 768
                 $inputs += $subsection->inputs_in_subsections();
769 769
             }
@@ -786,7 +786,7 @@  discard block
 block discarded – undo
786 786
         $errors = array();
787 787
         foreach ($inputs as $form_input) {
788 788
             if ($form_input instanceof EE_Form_Input_Base && $form_input->get_validation_errors()) {
789
-                $errors[ $form_input->html_name() ] = $form_input->get_validation_error_string();
789
+                $errors[$form_input->html_name()] = $form_input->get_validation_error_string();
790 790
             }
791 791
         }
792 792
         return $errors;
@@ -809,7 +809,7 @@  discard block
 block discarded – undo
809 809
         $email_validation_level = isset(EE_Registry::instance()->CFG->registration->email_validation_level)
810 810
             ? EE_Registry::instance()->CFG->registration->email_validation_level
811 811
             : 'wp_default';
812
-        EE_Form_Section_Proper::$_js_localization['email_validation_level']   = $email_validation_level;
812
+        EE_Form_Section_Proper::$_js_localization['email_validation_level'] = $email_validation_level;
813 813
         wp_enqueue_script('ee_form_section_validation');
814 814
         wp_localize_script(
815 815
             'ee_form_section_validation',
@@ -826,7 +826,7 @@  discard block
 block discarded – undo
826 826
      */
827 827
     public function ensure_scripts_localized()
828 828
     {
829
-        if (! EE_Form_Section_Proper::$_scripts_localized) {
829
+        if ( ! EE_Form_Section_Proper::$_scripts_localized) {
830 830
             $this->_enqueue_and_localize_form_js();
831 831
         }
832 832
     }
@@ -920,8 +920,8 @@  discard block
 block discarded – undo
920 920
     protected function _validate()
921 921
     {
922 922
         foreach ($this->get_validatable_subsections() as $subsection_name => $subsection) {
923
-            if (method_exists($this, '_validate_' . $subsection_name)) {
924
-                call_user_func_array(array($this, '_validate_' . $subsection_name), array($subsection));
923
+            if (method_exists($this, '_validate_'.$subsection_name)) {
924
+                call_user_func_array(array($this, '_validate_'.$subsection_name), array($subsection));
925 925
             }
926 926
             $subsection->_validate();
927 927
         }
@@ -939,9 +939,9 @@  discard block
 block discarded – undo
939 939
         $inputs = array();
940 940
         foreach ($this->subsections() as $subsection_name => $subsection) {
941 941
             if ($subsection instanceof EE_Form_Section_Proper) {
942
-                $inputs[ $subsection_name ] = $subsection->valid_data();
942
+                $inputs[$subsection_name] = $subsection->valid_data();
943 943
             } elseif ($subsection instanceof EE_Form_Input_Base) {
944
-                $inputs[ $subsection_name ] = $subsection->normalized_value();
944
+                $inputs[$subsection_name] = $subsection->normalized_value();
945 945
             }
946 946
         }
947 947
         return $inputs;
@@ -959,7 +959,7 @@  discard block
 block discarded – undo
959 959
         $inputs = array();
960 960
         foreach ($this->subsections() as $subsection_name => $subsection) {
961 961
             if ($subsection instanceof EE_Form_Input_Base) {
962
-                $inputs[ $subsection_name ] = $subsection;
962
+                $inputs[$subsection_name] = $subsection;
963 963
             }
964 964
         }
965 965
         return $inputs;
@@ -977,7 +977,7 @@  discard block
 block discarded – undo
977 977
         $form_sections = array();
978 978
         foreach ($this->subsections() as $name => $obj) {
979 979
             if ($obj instanceof EE_Form_Section_Proper) {
980
-                $form_sections[ $name ] = $obj;
980
+                $form_sections[$name] = $obj;
981 981
             }
982 982
         }
983 983
         return $form_sections;
@@ -1074,7 +1074,7 @@  discard block
 block discarded – undo
1074 1074
         $input_values = array();
1075 1075
         foreach ($this->subsections() as $subsection_name => $subsection) {
1076 1076
             if ($subsection instanceof EE_Form_Input_Base) {
1077
-                $input_values[ $subsection_name ] = $pretty
1077
+                $input_values[$subsection_name] = $pretty
1078 1078
                     ? $subsection->pretty_value()
1079 1079
                     : $subsection->normalized_value();
1080 1080
             } elseif ($subsection instanceof EE_Form_Section_Proper && $include_subform_inputs) {
@@ -1086,7 +1086,7 @@  discard block
 block discarded – undo
1086 1086
                 if ($flatten) {
1087 1087
                     $input_values = array_merge($input_values, $subform_input_values);
1088 1088
                 } else {
1089
-                    $input_values[ $subsection_name ] = $subform_input_values;
1089
+                    $input_values[$subsection_name] = $subform_input_values;
1090 1090
                 }
1091 1091
             }
1092 1092
         }
@@ -1114,7 +1114,7 @@  discard block
 block discarded – undo
1114 1114
             if ($subsection instanceof EE_Form_Input_Base) {
1115 1115
                 // is this input part of an array of inputs?
1116 1116
                 if (strpos($subsection->html_name(), '[') !== false) {
1117
-                    $full_input_name  = EEH_Array::convert_array_values_to_keys(
1117
+                    $full_input_name = EEH_Array::convert_array_values_to_keys(
1118 1118
                         explode(
1119 1119
                             '[',
1120 1120
                             str_replace(']', '', $subsection->html_name())
@@ -1123,7 +1123,7 @@  discard block
 block discarded – undo
1123 1123
                     );
1124 1124
                     $submitted_values = array_replace_recursive($submitted_values, $full_input_name);
1125 1125
                 } else {
1126
-                    $submitted_values[ $subsection->html_name() ] = $subsection->raw_value();
1126
+                    $submitted_values[$subsection->html_name()] = $subsection->raw_value();
1127 1127
                 }
1128 1128
             } elseif ($subsection instanceof EE_Form_Section_Proper && $include_subforms) {
1129 1129
                 $subform_input_values = $subsection->submitted_values($include_subforms);
@@ -1158,7 +1158,7 @@  discard block
 block discarded – undo
1158 1158
     public function exclude(array $inputs_to_exclude = array())
1159 1159
     {
1160 1160
         foreach ($inputs_to_exclude as $input_to_exclude_name) {
1161
-            unset($this->_subsections[ $input_to_exclude_name ]);
1161
+            unset($this->_subsections[$input_to_exclude_name]);
1162 1162
         }
1163 1163
     }
1164 1164
 
@@ -1200,7 +1200,7 @@  discard block
 block discarded – undo
1200 1200
     public function add_subsections($new_subsections, $subsection_name_to_target = null, $add_before = true)
1201 1201
     {
1202 1202
         foreach ($new_subsections as $subsection_name => $subsection) {
1203
-            if (! $subsection instanceof EE_Form_Section_Base) {
1203
+            if ( ! $subsection instanceof EE_Form_Section_Base) {
1204 1204
                 EE_Error::add_error(
1205 1205
                     sprintf(
1206 1206
                         esc_html__(
@@ -1212,7 +1212,7 @@  discard block
 block discarded – undo
1212 1212
                         $this->name()
1213 1213
                     )
1214 1214
                 );
1215
-                unset($new_subsections[ $subsection_name ]);
1215
+                unset($new_subsections[$subsection_name]);
1216 1216
             }
1217 1217
         }
1218 1218
         $this->_subsections = EEH_Array::insert_into_array(
@@ -1294,7 +1294,7 @@  discard block
 block discarded – undo
1294 1294
     public function html_name_prefix()
1295 1295
     {
1296 1296
         if ($this->parent_section() instanceof EE_Form_Section_Proper) {
1297
-            return $this->parent_section()->html_name_prefix() . '[' . $this->name() . ']';
1297
+            return $this->parent_section()->html_name_prefix().'['.$this->name().']';
1298 1298
         }
1299 1299
         return $this->name();
1300 1300
     }
@@ -1334,7 +1334,7 @@  discard block
 block discarded – undo
1334 1334
      */
1335 1335
     public function ensure_construct_finalized_called()
1336 1336
     {
1337
-        if (! $this->_construction_finalized) {
1337
+        if ( ! $this->_construction_finalized) {
1338 1338
             $this->_construct_finalize($this->_parent_section, $this->_name);
1339 1339
         }
1340 1340
     }
Please login to merge, or discard this patch.
espresso.php 1 patch
Indentation   +191 added lines, -191 removed lines patch added patch discarded remove patch
@@ -38,216 +38,216 @@
 block discarded – undo
38 38
  * @since       4.0
39 39
  */
40 40
 if (function_exists('espresso_version')) {
41
-    if (! function_exists('espresso_duplicate_plugin_error')) {
42
-        /**
43
-         *    espresso_duplicate_plugin_error
44
-         *    displays if more than one version of EE is activated at the same time
45
-         */
46
-        function espresso_duplicate_plugin_error()
47
-        {
48
-            ?>
41
+	if (! function_exists('espresso_duplicate_plugin_error')) {
42
+		/**
43
+		 *    espresso_duplicate_plugin_error
44
+		 *    displays if more than one version of EE is activated at the same time
45
+		 */
46
+		function espresso_duplicate_plugin_error()
47
+		{
48
+			?>
49 49
             <div class="error">
50 50
                 <p>
51 51
                     <?php
52
-                    echo esc_html__(
53
-                        'Can not run multiple versions of Event Espresso! One version has been automatically deactivated. Please verify that you have the correct version you want still active.',
54
-                        'event_espresso'
55
-                    ); ?>
52
+					echo esc_html__(
53
+						'Can not run multiple versions of Event Espresso! One version has been automatically deactivated. Please verify that you have the correct version you want still active.',
54
+						'event_espresso'
55
+					); ?>
56 56
                 </p>
57 57
             </div>
58 58
             <?php
59
-            espresso_deactivate_plugin(plugin_basename(__FILE__));
60
-        }
61
-    }
62
-    add_action('admin_notices', 'espresso_duplicate_plugin_error', 1);
59
+			espresso_deactivate_plugin(plugin_basename(__FILE__));
60
+		}
61
+	}
62
+	add_action('admin_notices', 'espresso_duplicate_plugin_error', 1);
63 63
 
64 64
 } else {
65
-    define('EE_MIN_PHP_VER_REQUIRED', '5.3.9');
66
-    if (! version_compare(PHP_VERSION, EE_MIN_PHP_VER_REQUIRED, '>=')) {
67
-        /**
68
-         * espresso_minimum_php_version_error
69
-         * @return void
70
-         */
71
-        function espresso_minimum_php_version_error()
72
-        {
73
-            ?>
65
+	define('EE_MIN_PHP_VER_REQUIRED', '5.3.9');
66
+	if (! version_compare(PHP_VERSION, EE_MIN_PHP_VER_REQUIRED, '>=')) {
67
+		/**
68
+		 * espresso_minimum_php_version_error
69
+		 * @return void
70
+		 */
71
+		function espresso_minimum_php_version_error()
72
+		{
73
+			?>
74 74
             <div class="error">
75 75
                 <p>
76 76
                     <?php
77
-                    printf(
78
-                        esc_html__(
79
-                            'We\'re sorry, but Event Espresso requires PHP version %1$s or greater in order to operate. You are currently running version %2$s.%3$sIn order to update your version of PHP, you will need to contact your current hosting provider.%3$sFor information on stable PHP versions, please go to %4$s.',
80
-                            'event_espresso'
81
-                        ),
82
-                        EE_MIN_PHP_VER_REQUIRED,
83
-                        PHP_VERSION,
84
-                        '<br/>',
85
-                        '<a href="http://php.net/downloads.php">http://php.net/downloads.php</a>'
86
-                    );
87
-                    ?>
77
+					printf(
78
+						esc_html__(
79
+							'We\'re sorry, but Event Espresso requires PHP version %1$s or greater in order to operate. You are currently running version %2$s.%3$sIn order to update your version of PHP, you will need to contact your current hosting provider.%3$sFor information on stable PHP versions, please go to %4$s.',
80
+							'event_espresso'
81
+						),
82
+						EE_MIN_PHP_VER_REQUIRED,
83
+						PHP_VERSION,
84
+						'<br/>',
85
+						'<a href="http://php.net/downloads.php">http://php.net/downloads.php</a>'
86
+					);
87
+					?>
88 88
                 </p>
89 89
             </div>
90 90
             <?php
91
-            espresso_deactivate_plugin(plugin_basename(__FILE__));
92
-        }
91
+			espresso_deactivate_plugin(plugin_basename(__FILE__));
92
+		}
93 93
 
94
-        add_action('admin_notices', 'espresso_minimum_php_version_error', 1);
95
-    } else {
96
-        define('EVENT_ESPRESSO_MAIN_FILE', __FILE__);
97
-        /**
98
-         * espresso_version
99
-         * Returns the plugin version
100
-         *
101
-         * @return string
102
-         */
103
-        function espresso_version()
104
-        {
105
-            return apply_filters('FHEE__espresso__espresso_version', '4.9.58.rc.007');
106
-        }
94
+		add_action('admin_notices', 'espresso_minimum_php_version_error', 1);
95
+	} else {
96
+		define('EVENT_ESPRESSO_MAIN_FILE', __FILE__);
97
+		/**
98
+		 * espresso_version
99
+		 * Returns the plugin version
100
+		 *
101
+		 * @return string
102
+		 */
103
+		function espresso_version()
104
+		{
105
+			return apply_filters('FHEE__espresso__espresso_version', '4.9.58.rc.007');
106
+		}
107 107
 
108
-        /**
109
-         * espresso_plugin_activation
110
-         * adds a wp-option to indicate that EE has been activated via the WP admin plugins page
111
-         */
112
-        function espresso_plugin_activation()
113
-        {
114
-            update_option('ee_espresso_activation', true);
115
-        }
108
+		/**
109
+		 * espresso_plugin_activation
110
+		 * adds a wp-option to indicate that EE has been activated via the WP admin plugins page
111
+		 */
112
+		function espresso_plugin_activation()
113
+		{
114
+			update_option('ee_espresso_activation', true);
115
+		}
116 116
 
117
-        register_activation_hook(EVENT_ESPRESSO_MAIN_FILE, 'espresso_plugin_activation');
118
-        /**
119
-         *    espresso_load_error_handling
120
-         *    this function loads EE's class for handling exceptions and errors
121
-         */
122
-        function espresso_load_error_handling()
123
-        {
124
-            static $error_handling_loaded = false;
125
-            if ($error_handling_loaded) {
126
-                return;
127
-            }
128
-            // load debugging tools
129
-            if (WP_DEBUG === true && is_readable(EE_HELPERS . 'EEH_Debug_Tools.helper.php')) {
130
-                require_once   EE_HELPERS . 'EEH_Debug_Tools.helper.php';
131
-                \EEH_Debug_Tools::instance();
132
-            }
133
-            // load error handling
134
-            if (is_readable(EE_CORE . 'EE_Error.core.php')) {
135
-                require_once EE_CORE . 'EE_Error.core.php';
136
-            } else {
137
-                wp_die(esc_html__('The EE_Error core class could not be loaded.', 'event_espresso'));
138
-            }
139
-            $error_handling_loaded = true;
140
-        }
117
+		register_activation_hook(EVENT_ESPRESSO_MAIN_FILE, 'espresso_plugin_activation');
118
+		/**
119
+		 *    espresso_load_error_handling
120
+		 *    this function loads EE's class for handling exceptions and errors
121
+		 */
122
+		function espresso_load_error_handling()
123
+		{
124
+			static $error_handling_loaded = false;
125
+			if ($error_handling_loaded) {
126
+				return;
127
+			}
128
+			// load debugging tools
129
+			if (WP_DEBUG === true && is_readable(EE_HELPERS . 'EEH_Debug_Tools.helper.php')) {
130
+				require_once   EE_HELPERS . 'EEH_Debug_Tools.helper.php';
131
+				\EEH_Debug_Tools::instance();
132
+			}
133
+			// load error handling
134
+			if (is_readable(EE_CORE . 'EE_Error.core.php')) {
135
+				require_once EE_CORE . 'EE_Error.core.php';
136
+			} else {
137
+				wp_die(esc_html__('The EE_Error core class could not be loaded.', 'event_espresso'));
138
+			}
139
+			$error_handling_loaded = true;
140
+		}
141 141
 
142
-        /**
143
-         *    espresso_load_required
144
-         *    given a class name and path, this function will load that file or throw an exception
145
-         *
146
-         * @param    string $classname
147
-         * @param    string $full_path_to_file
148
-         * @throws    EE_Error
149
-         */
150
-        function espresso_load_required($classname, $full_path_to_file)
151
-        {
152
-            if (is_readable($full_path_to_file)) {
153
-                require_once $full_path_to_file;
154
-            } else {
155
-                throw new \EE_Error (
156
-                    sprintf(
157
-                        esc_html__(
158
-                            'The %s class file could not be located or is not readable due to file permissions.',
159
-                            'event_espresso'
160
-                        ),
161
-                        $classname
162
-                    )
163
-                );
164
-            }
165
-        }
142
+		/**
143
+		 *    espresso_load_required
144
+		 *    given a class name and path, this function will load that file or throw an exception
145
+		 *
146
+		 * @param    string $classname
147
+		 * @param    string $full_path_to_file
148
+		 * @throws    EE_Error
149
+		 */
150
+		function espresso_load_required($classname, $full_path_to_file)
151
+		{
152
+			if (is_readable($full_path_to_file)) {
153
+				require_once $full_path_to_file;
154
+			} else {
155
+				throw new \EE_Error (
156
+					sprintf(
157
+						esc_html__(
158
+							'The %s class file could not be located or is not readable due to file permissions.',
159
+							'event_espresso'
160
+						),
161
+						$classname
162
+					)
163
+				);
164
+			}
165
+		}
166 166
 
167
-        /**
168
-         * @since 4.9.27
169
-         * @throws \EE_Error
170
-         * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
171
-         * @throws \EventEspresso\core\exceptions\InvalidEntityException
172
-         * @throws \EventEspresso\core\exceptions\InvalidIdentifierException
173
-         * @throws \EventEspresso\core\exceptions\InvalidClassException
174
-         * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
175
-         * @throws \EventEspresso\core\services\container\exceptions\ServiceExistsException
176
-         * @throws \EventEspresso\core\services\container\exceptions\ServiceNotFoundException
177
-         * @throws \OutOfBoundsException
178
-         */
179
-        function bootstrap_espresso()
180
-        {
181
-            require_once __DIR__ . '/core/espresso_definitions.php';
182
-            try {
183
-                espresso_load_error_handling();
184
-                espresso_load_required(
185
-                    'EEH_Base',
186
-                    EE_CORE . 'helpers' . DS . 'EEH_Base.helper.php'
187
-                );
188
-                espresso_load_required(
189
-                    'EEH_File',
190
-                    EE_CORE . 'interfaces' . DS . 'EEHI_File.interface.php'
191
-                );
192
-                espresso_load_required(
193
-                    'EEH_File',
194
-                    EE_CORE . 'helpers' . DS . 'EEH_File.helper.php'
195
-                );
196
-                espresso_load_required(
197
-                    'EEH_Array',
198
-                    EE_CORE . 'helpers' . DS . 'EEH_Array.helper.php'
199
-                );
200
-                // instantiate and configure PSR4 autoloader
201
-                espresso_load_required(
202
-                    'Psr4Autoloader',
203
-                    EE_CORE . 'Psr4Autoloader.php'
204
-                );
205
-                espresso_load_required(
206
-                    'EE_Psr4AutoloaderInit',
207
-                    EE_CORE . 'EE_Psr4AutoloaderInit.core.php'
208
-                );
209
-                $AutoloaderInit = new EE_Psr4AutoloaderInit();
210
-                $AutoloaderInit->initializeAutoloader();
211
-                espresso_load_required(
212
-                    'EE_Request',
213
-                    EE_CORE . 'request_stack' . DS . 'EE_Request.core.php'
214
-                );
215
-                espresso_load_required(
216
-                    'EE_Response',
217
-                    EE_CORE . 'request_stack' . DS . 'EE_Response.core.php'
218
-                );
219
-                espresso_load_required(
220
-                    'EE_Bootstrap',
221
-                    EE_CORE . 'EE_Bootstrap.core.php'
222
-                );
223
-                // bootstrap EE and the request stack
224
-                new EE_Bootstrap(
225
-                    new EE_Request($_GET, $_POST, $_COOKIE),
226
-                    new EE_Response()
227
-                );
228
-            } catch (Exception $e) {
229
-                require_once EE_CORE . 'exceptions' . DS . 'ExceptionStackTraceDisplay.php';
230
-                new EventEspresso\core\exceptions\ExceptionStackTraceDisplay($e);
231
-            }
232
-        }
233
-        bootstrap_espresso();
234
-    }
167
+		/**
168
+		 * @since 4.9.27
169
+		 * @throws \EE_Error
170
+		 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
171
+		 * @throws \EventEspresso\core\exceptions\InvalidEntityException
172
+		 * @throws \EventEspresso\core\exceptions\InvalidIdentifierException
173
+		 * @throws \EventEspresso\core\exceptions\InvalidClassException
174
+		 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
175
+		 * @throws \EventEspresso\core\services\container\exceptions\ServiceExistsException
176
+		 * @throws \EventEspresso\core\services\container\exceptions\ServiceNotFoundException
177
+		 * @throws \OutOfBoundsException
178
+		 */
179
+		function bootstrap_espresso()
180
+		{
181
+			require_once __DIR__ . '/core/espresso_definitions.php';
182
+			try {
183
+				espresso_load_error_handling();
184
+				espresso_load_required(
185
+					'EEH_Base',
186
+					EE_CORE . 'helpers' . DS . 'EEH_Base.helper.php'
187
+				);
188
+				espresso_load_required(
189
+					'EEH_File',
190
+					EE_CORE . 'interfaces' . DS . 'EEHI_File.interface.php'
191
+				);
192
+				espresso_load_required(
193
+					'EEH_File',
194
+					EE_CORE . 'helpers' . DS . 'EEH_File.helper.php'
195
+				);
196
+				espresso_load_required(
197
+					'EEH_Array',
198
+					EE_CORE . 'helpers' . DS . 'EEH_Array.helper.php'
199
+				);
200
+				// instantiate and configure PSR4 autoloader
201
+				espresso_load_required(
202
+					'Psr4Autoloader',
203
+					EE_CORE . 'Psr4Autoloader.php'
204
+				);
205
+				espresso_load_required(
206
+					'EE_Psr4AutoloaderInit',
207
+					EE_CORE . 'EE_Psr4AutoloaderInit.core.php'
208
+				);
209
+				$AutoloaderInit = new EE_Psr4AutoloaderInit();
210
+				$AutoloaderInit->initializeAutoloader();
211
+				espresso_load_required(
212
+					'EE_Request',
213
+					EE_CORE . 'request_stack' . DS . 'EE_Request.core.php'
214
+				);
215
+				espresso_load_required(
216
+					'EE_Response',
217
+					EE_CORE . 'request_stack' . DS . 'EE_Response.core.php'
218
+				);
219
+				espresso_load_required(
220
+					'EE_Bootstrap',
221
+					EE_CORE . 'EE_Bootstrap.core.php'
222
+				);
223
+				// bootstrap EE and the request stack
224
+				new EE_Bootstrap(
225
+					new EE_Request($_GET, $_POST, $_COOKIE),
226
+					new EE_Response()
227
+				);
228
+			} catch (Exception $e) {
229
+				require_once EE_CORE . 'exceptions' . DS . 'ExceptionStackTraceDisplay.php';
230
+				new EventEspresso\core\exceptions\ExceptionStackTraceDisplay($e);
231
+			}
232
+		}
233
+		bootstrap_espresso();
234
+	}
235 235
 }
236 236
 if (! function_exists('espresso_deactivate_plugin')) {
237
-    /**
238
-     *    deactivate_plugin
239
-     * usage:  espresso_deactivate_plugin( plugin_basename( __FILE__ ));
240
-     *
241
-     * @access public
242
-     * @param string $plugin_basename - the results of plugin_basename( __FILE__ ) for the plugin's main file
243
-     * @return    void
244
-     */
245
-    function espresso_deactivate_plugin($plugin_basename = '')
246
-    {
247
-        if (! function_exists('deactivate_plugins')) {
248
-            require_once ABSPATH . 'wp-admin/includes/plugin.php';
249
-        }
250
-        unset($_GET['activate'], $_REQUEST['activate']);
251
-        deactivate_plugins($plugin_basename);
252
-    }
237
+	/**
238
+	 *    deactivate_plugin
239
+	 * usage:  espresso_deactivate_plugin( plugin_basename( __FILE__ ));
240
+	 *
241
+	 * @access public
242
+	 * @param string $plugin_basename - the results of plugin_basename( __FILE__ ) for the plugin's main file
243
+	 * @return    void
244
+	 */
245
+	function espresso_deactivate_plugin($plugin_basename = '')
246
+	{
247
+		if (! function_exists('deactivate_plugins')) {
248
+			require_once ABSPATH . 'wp-admin/includes/plugin.php';
249
+		}
250
+		unset($_GET['activate'], $_REQUEST['activate']);
251
+		deactivate_plugins($plugin_basename);
252
+	}
253 253
 }
Please login to merge, or discard this patch.
core/libraries/messages/EE_Messages_Queue.lib.php 2 patches
Indentation   +689 added lines, -689 removed lines patch added patch discarded remove patch
@@ -2,7 +2,7 @@  discard block
 block discarded – undo
2 2
 use \EventEspresso\core\exceptions\SendMessageException;
3 3
 
4 4
 if (! defined('EVENT_ESPRESSO_VERSION')) {
5
-    exit('No direct script access allowed');
5
+	exit('No direct script access allowed');
6 6
 }
7 7
 
8 8
 /**
@@ -18,693 +18,693 @@  discard block
 block discarded – undo
18 18
 {
19 19
 
20 20
 
21
-    /**
22
-     * @type    string  reference for sending action
23
-     */
24
-    const action_sending = 'sending';
25
-
26
-    /**
27
-     * @type    string  reference for generation action
28
-     */
29
-    const action_generating = 'generation';
30
-
31
-
32
-    /**
33
-     * @type EE_Message_Repository $_message_repository
34
-     */
35
-    protected $_message_repository;
36
-
37
-    /**
38
-     * Sets the limit of how many messages are generated per process.
39
-     *
40
-     * @type int
41
-     */
42
-    protected $_batch_count;
43
-
44
-
45
-    /**
46
-     * This is an array of cached queue items being stored in this object.
47
-     * The array keys will be the ID of the EE_Message in the db if saved.  If the EE_Message
48
-     * is not saved to the db then its key will be an increment of "UNS" (i.e. UNS1, UNS2 etc.)
49
-     *
50
-     * @type EE_Message[]
51
-     */
52
-    protected $_cached_queue_items;
53
-
54
-    /**
55
-     * Tracks the number of unsaved queue items.
56
-     *
57
-     * @type int
58
-     */
59
-    protected $_unsaved_count = 0;
60
-
61
-    /**
62
-     * used to record if a do_messenger_hooks has already been called for a message type.  This prevents multiple
63
-     * hooks getting fired if users have setup their action/filter hooks to prevent duplicate calls.
64
-     *
65
-     * @type array
66
-     */
67
-    protected $_did_hook = array();
68
-
69
-
70
-    /**
71
-     * Constructor.
72
-     * Setup all the initial properties and load a EE_Message_Repository.
73
-     *
74
-     * @param \EE_Message_Repository $message_repository
75
-     */
76
-    public function __construct(EE_Message_Repository $message_repository)
77
-    {
78
-        $this->_batch_count        = apply_filters('FHEE__EE_Messages_Queue___batch_count', 50);
79
-        $this->_message_repository = $message_repository;
80
-    }
81
-
82
-
83
-    /**
84
-     * Add a EE_Message object to the queue
85
-     *
86
-     * @param EE_Message $message
87
-     * @param array      $data         This will be an array of data to attach to the object in the repository.  If the
88
-     *                                 object is persisted, this data will be saved on an extra_meta object related to
89
-     *                                 EE_Message.
90
-     * @param  bool      $preview      Whether this EE_Message represents a preview or not.
91
-     * @param  bool      $test_send    This indicates whether to do a test send instead of actual send. A test send will
92
-     *                                 use the messenger send method but typically is based on preview data.
93
-     * @return bool          Whether the message was successfully added to the repository or not.
94
-     */
95
-    public function add(EE_Message $message, $data = array(), $preview = false, $test_send = false)
96
-    {
97
-        $data['preview']   = $preview;
98
-        $data['test_send'] = $test_send;
99
-        return $this->_message_repository->add($message, $data);
100
-    }
101
-
102
-
103
-    /**
104
-     * Removes EE_Message from _queue that matches the given EE_Message if the pointer is on a matching EE_Message
105
-     *
106
-     * @param EE_Message $message The message to detach from the queue
107
-     * @param bool       $persist This flag indicates whether to attempt to delete the object from the db as well.
108
-     * @return bool
109
-     */
110
-    public function remove(EE_Message $message, $persist = false)
111
-    {
112
-        if ($persist && $this->_message_repository->current() !== $message) {
113
-            //get pointer on right message
114
-            if ($this->_message_repository->has($message)) {
115
-                $this->_message_repository->rewind();
116
-                while ($this->_message_repository->valid()) {
117
-                    if ($this->_message_repository->current() === $message) {
118
-                        break;
119
-                    }
120
-                    $this->_message_repository->next();
121
-                }
122
-            } else {
123
-                return false;
124
-            }
125
-        }
126
-        return $persist ? $this->_message_repository->delete() : $this->_message_repository->remove($message);
127
-    }
128
-
129
-
130
-    /**
131
-     * Persists all queued EE_Message objects to the db.
132
-     *
133
-     * @param bool $do_hooks_only       @see EE_Message_Repository::saveAll
134
-     * @return array @see EE_Messages_Repository::saveAll() for return values.
135
-     */
136
-    public function save($do_hooks_only = false)
137
-    {
138
-        return $this->_message_repository->saveAll($do_hooks_only);
139
-    }
140
-
141
-
142
-    /**
143
-     * @return EE_Message_Repository
144
-     */
145
-    public function get_message_repository()
146
-    {
147
-        return $this->_message_repository;
148
-    }
149
-
150
-
151
-    /**
152
-     * This does the following things:
153
-     * 1. Checks if there is a lock on generation (prevents race conditions).  If there is a lock then exits (return
154
-     * false).
155
-     * 2. If no lock, sets lock, then retrieves a batch of non-generated EE_Message objects and adds to queue
156
-     * 3. Returns bool.  True = batch ready.  False = no batch ready (or nothing available for generation).
157
-     * Note: Callers should make sure they release the lock otherwise batch generation will be prevented from
158
-     * continuing. The lock is on a transient that is set to expire after one hour as a fallback in case locks are not
159
-     * removed.
160
-     *
161
-     * @return bool  true if successfully retrieved batch, false no batch ready.
162
-     */
163
-    public function get_batch_to_generate()
164
-    {
165
-        if ($this->is_locked(EE_Messages_Queue::action_generating)) {
166
-            return false;
167
-        }
168
-
169
-        //lock batch generation to prevent race conditions.
170
-        $this->lock_queue(EE_Messages_Queue::action_generating);
171
-
172
-        $query_args = array(
173
-            // key 0 = where conditions
174
-            0          => array('STS_ID' => EEM_Message::status_incomplete),
175
-            'order_by' => $this->_get_priority_orderby(),
176
-            'limit'    => $this->_batch_count,
177
-        );
178
-        $messages   = EEM_Message::instance()->get_all($query_args);
179
-
180
-        if ( ! $messages) {
181
-            return false; //nothing to generate
182
-        }
183
-
184
-        foreach ($messages as $message) {
185
-            if ($message instanceof EE_Message) {
186
-                $data = $message->all_extra_meta_array();
187
-                $this->add($message, $data);
188
-            }
189
-        }
190
-        return true;
191
-    }
192
-
193
-
194
-    /**
195
-     * This does the following things:
196
-     * 1. Checks if there is a lock on sending (prevents race conditions).  If there is a lock then exits (return
197
-     * false).
198
-     * 2. Grabs the allowed number of messages to send for the rate_limit.  If cannot send any more messages, then
199
-     * return false.
200
-     * 2. If no lock, sets lock, then retrieves a batch of EE_Message objects, adds to queue and triggers execution.
201
-     * 3. On success or unsuccessful send, sets status appropriately.
202
-     * 4. Saves messages via the queue
203
-     * 5. Releases lock.
204
-     *
205
-     * @return bool  true on success, false if something preventing sending (i.e. lock set).  Note: true does not
206
-     *               necessarily mean that all messages were successfully sent.  It just means that this method
207
-     *               successfully completed. On true, client may want to call $this->count_STS_in_queue(
208
-     *               EEM_Message::status_failed ) to see if any failed EE_Message objects.  Each failed message object
209
-     *               will also have a saved error message on it to assist with notifying user.
210
-     */
211
-    public function get_to_send_batch_and_send()
212
-    {
213
-        $rate_limit = $this->get_rate_limit();
214
-        if ($rate_limit < 1 || $this->is_locked(EE_Messages_Queue::action_sending)) {
215
-            return false;
216
-        }
217
-
218
-        $this->lock_queue(EE_Messages_Queue::action_sending);
219
-
220
-        $batch = $this->_batch_count < $rate_limit ? $this->_batch_count : $rate_limit;
221
-
222
-        $query_args = array(
223
-            // key 0 = where conditions
224
-            0          => array('STS_ID' => array('IN', EEM_Message::instance()->stati_indicating_to_send())),
225
-            'order_by' => $this->_get_priority_orderby(),
226
-            'limit'    => $batch,
227
-        );
228
-
229
-        $messages_to_send = EEM_Message::instance()->get_all($query_args);
230
-
231
-
232
-        //any to send?
233
-        if ( ! $messages_to_send) {
234
-            $this->unlock_queue(EE_Messages_Queue::action_sending);
235
-            return false;
236
-        }
237
-
238
-        $queue_count = 0;
239
-
240
-        //add to queue.
241
-        foreach ($messages_to_send as $message) {
242
-            if ($message instanceof EE_Message) {
243
-                $queue_count++;
244
-                $this->add($message);
245
-            }
246
-        }
247
-
248
-        //send messages  (this also updates the rate limit)
249
-        $this->execute();
250
-
251
-        //release lock
252
-        $this->unlock_queue(EE_Messages_Queue::action_sending);
253
-        //update rate limit
254
-        $this->set_rate_limit($queue_count);
255
-        return true;
256
-    }
257
-
258
-
259
-    /**
260
-     * Locks the queue so that no other queues can call the "batch" methods.
261
-     *
262
-     * @param   string $type The type of queue being locked.
263
-     */
264
-    public function lock_queue($type = EE_Messages_Queue::action_generating)
265
-    {
266
-        update_option($this->_get_lock_key($type), $this->_get_lock_expiry($type));
267
-    }
268
-
269
-
270
-    /**
271
-     * Unlocks the queue so that batch methods can be used.
272
-     *
273
-     * @param   string $type The type of queue being unlocked.
274
-     */
275
-    public function unlock_queue($type = EE_Messages_Queue::action_generating)
276
-    {
277
-        delete_option($this->_get_lock_key($type));
278
-    }
279
-
280
-
281
-    /**
282
-     * Retrieve the key used for the lock transient.
283
-     *
284
-     * @param string $type The type of lock.
285
-     * @return string
286
-     */
287
-    protected function _get_lock_key($type = EE_Messages_Queue::action_generating)
288
-    {
289
-        return '_ee_lock_' . $type;
290
-    }
291
-
292
-
293
-    /**
294
-     * Retrieve the expiry time for the lock transient.
295
-     *
296
-     * @param string $type The type of lock
297
-     * @return int   time to expiry in seconds.
298
-     */
299
-    protected function _get_lock_expiry($type = EE_Messages_Queue::action_generating)
300
-    {
301
-        return time() + (int) apply_filters('FHEE__EE_Messages_Queue__lock_expiry', HOUR_IN_SECONDS, $type);
302
-    }
303
-
304
-
305
-    /**
306
-     * Returns the key used for rate limit transient.
307
-     *
308
-     * @return string
309
-     */
310
-    protected function _get_rate_limit_key()
311
-    {
312
-        return '_ee_rate_limit';
313
-    }
314
-
315
-
316
-    /**
317
-     * Returns the rate limit expiry time.
318
-     *
319
-     * @return int
320
-     */
321
-    protected function _get_rate_limit_expiry()
322
-    {
323
-        return time() + (int) apply_filters('FHEE__EE_Messages_Queue__rate_limit_expiry', HOUR_IN_SECONDS);
324
-    }
325
-
326
-
327
-    /**
328
-     * Returns the default rate limit for sending messages.
329
-     *
330
-     * @return int
331
-     */
332
-    protected function _default_rate_limit()
333
-    {
334
-        return (int) apply_filters('FHEE__EE_Messages_Queue___rate_limit', 200);
335
-    }
336
-
337
-
338
-    /**
339
-     * Return the orderby array for priority.
340
-     *
341
-     * @return array
342
-     */
343
-    protected function _get_priority_orderby()
344
-    {
345
-        return array(
346
-            'MSG_priority' => 'ASC',
347
-            'MSG_modified' => 'DESC',
348
-        );
349
-    }
350
-
351
-
352
-    /**
353
-     * Returns whether batch methods are "locked" or not.
354
-     *
355
-     * @param  string $type The type of lock being checked for.
356
-     * @return bool
357
-     */
358
-    public function is_locked($type = EE_Messages_Queue::action_generating)
359
-    {
360
-        $lock = (int) get_option($this->_get_lock_key($type), 0);
361
-        /**
362
-         * This filters the default is_locked behaviour.
363
-         */
364
-        $is_locked = filter_var(
365
-            apply_filters(
366
-                'FHEE__EE_Messages_Queue__is_locked',
367
-                $lock > time(),
368
-                $this
369
-            ),
370
-            FILTER_VALIDATE_BOOLEAN
371
-        );
372
-
373
-        /**
374
-         * @see usage of this filter in EE_Messages_Queue::initiate_request_by_priority() method.
375
-         *            Also implemented here because messages processed on the same request should not have any locks applied.
376
-         */
377
-        if (
378
-            apply_filters('FHEE__EE_Messages_Processor__initiate_request_by_priority__do_immediate_processing', false)
379
-            || EE_Registry::instance()->NET_CFG->core->do_messages_on_same_request
380
-        ) {
381
-            $is_locked = false;
382
-        }
383
-
384
-
385
-        return $is_locked;
386
-    }
387
-
388
-
389
-    /**
390
-     * Retrieves the rate limit that may be cached as a transient.
391
-     * If the rate limit is not set, then this sets the default rate limit and expiry and returns it.
392
-     *
393
-     * @param bool $return_expiry  If true then return the expiry time not the rate_limit.
394
-     * @return int
395
-     */
396
-    protected function get_rate_limit($return_expiry = false)
397
-    {
398
-        $stored_rate_info = get_option($this->_get_rate_limit_key(), array());
399
-        $rate_limit = isset($stored_rate_info[0])
400
-            ? (int) $stored_rate_info[0]
401
-            : 0;
402
-        $expiry = isset($stored_rate_info[1])
403
-            ? (int) $stored_rate_info[1]
404
-            : 0;
405
-        //set the default for tracking?
406
-        if (empty($stored_rate_info) || time() > $expiry) {
407
-            $expiry = $this->_get_rate_limit_expiry();
408
-            $rate_limit = $this->_default_rate_limit();
409
-            update_option($this->_get_rate_limit_key(), array($rate_limit, $expiry));
410
-        }
411
-        return $return_expiry ? $expiry : $rate_limit;
412
-    }
413
-
414
-
415
-    /**
416
-     * This updates existing rate limit with the new limit which is the old minus the batch.
417
-     *
418
-     * @param int $batch_completed This sets the new rate limit based on the given batch that was completed.
419
-     */
420
-    protected function set_rate_limit($batch_completed)
421
-    {
422
-        //first get the most up to date rate limit (in case its expired and reset)
423
-        $rate_limit = $this->get_rate_limit();
424
-        $expiry = $this->get_rate_limit(true);
425
-        $new_limit  = $rate_limit - $batch_completed;
426
-        //updating the transient option directly to avoid resetting the expiry.
427
-
428
-        update_option($this->_get_rate_limit_key(), array($new_limit, $expiry));
429
-    }
430
-
431
-
432
-    /**
433
-     * This method checks the queue for ANY EE_Message objects with a priority matching the given priority passed in.
434
-     * If that exists, then we immediately initiate a non-blocking request to do the requested action type.
435
-     * Note: Keep in mind that there is the possibility that the request will not execute if there is already another
436
-     * request running on a queue for the given task.
437
-     *
438
-     * @param string $task     This indicates what type of request is going to be initiated.
439
-     * @param int    $priority This indicates the priority that triggers initiating the request.
440
-     */
441
-    public function initiate_request_by_priority($task = 'generate', $priority = EEM_Message::priority_high)
442
-    {
443
-        //determine what status is matched with the priority as part of the trigger conditions.
444
-        $status = $task == 'generate'
445
-            ? EEM_Message::status_incomplete
446
-            : EEM_Message::instance()->stati_indicating_to_send();
447
-        // always make sure we save because either this will get executed immediately on a separate request
448
-        // or remains in the queue for the regularly scheduled queue batch.
449
-        $this->save();
450
-        /**
451
-         * This filter/option allows users to override processing of messages on separate requests and instead have everything
452
-         * happen on the same request.  If this is utilized remember:
453
-         * - message priorities don't matter
454
-         * - existing unprocessed messages in the queue will not get processed unless manually triggered.
455
-         * - things will be perceived to take longer to happen for end users (i.e. registrations) because of the additional
456
-         *   processing happening on the same request.
457
-         * - any race condition protection (locks) are removed because they don't apply when things are processed on
458
-         *   the same request.
459
-         */
460
-        if (
461
-            apply_filters('FHEE__EE_Messages_Processor__initiate_request_by_priority__do_immediate_processing', false)
462
-            || EE_Registry::instance()->NET_CFG->core->do_messages_on_same_request
463
-        ) {
464
-            $messages_processor = EE_Registry::instance()->load_lib('Messages_Processor');
465
-            if ($messages_processor instanceof EE_Messages_Processor) {
466
-                return $messages_processor->process_immediately_from_queue($this);
467
-            }
468
-            //if we get here then that means the messages processor couldn't be loaded so messages will just remain
469
-            //queued for manual triggering by end user.
470
-        }
471
-
472
-        if ($this->_message_repository->count_by_priority_and_status($priority, $status)) {
473
-            EE_Messages_Scheduler::initiate_scheduled_non_blocking_request($task);
474
-        }
475
-    }
476
-
477
-
478
-    /**
479
-     *  Loops through the EE_Message objects in the _queue and calls the messenger send methods for each message.
480
-     *
481
-     * @param   bool     $save                    Used to indicate whether to save the message queue after sending
482
-     *                                            (default will save).
483
-     * @param   mixed    $sending_messenger       (optional) When the sending messenger is different than
484
-     *                                            what is on the EE_Message object in the queue.
485
-     *                                            For instance, showing the browser view of an email message,
486
-     *                                            or giving a pdf generated view of an html document.
487
-     *                                            This should be an instance of EE_messenger but if you call this
488
-     *                                            method
489
-     *                                            intending it to be a sending messenger but a valid one could not be
490
-     *                                            retrieved then send in an instance of EE_Error that contains the
491
-     *                                            related error message.
492
-     * @param   bool|int $by_priority             When set, this indicates that only messages
493
-     *                                            matching the given priority should be executed.
494
-     * @return int        Number of messages sent.  Note, 0 does not mean that no messages were processed.
495
-     *                                            Also, if the messenger is an request type messenger (or a preview),
496
-     *                                            its entirely possible that the messenger will exit before
497
-     */
498
-    public function execute($save = true, $sending_messenger = null, $by_priority = false)
499
-    {
500
-        $messages_sent   = 0;
501
-        $this->_did_hook = array();
502
-        $this->_message_repository->rewind();
503
-
504
-        while ($this->_message_repository->valid()) {
505
-            $error_messages = array();
506
-            /** @type EE_Message $message */
507
-            $message = $this->_message_repository->current();
508
-            //only process things that are queued for sending
509
-            if (! in_array($message->STS_ID(), EEM_Message::instance()->stati_indicating_to_send())) {
510
-                $this->_message_repository->next();
511
-                continue;
512
-            }
513
-            //if $by_priority is set and does not match then continue;
514
-            if ($by_priority && $by_priority != $message->priority()) {
515
-                $this->_message_repository->next();
516
-                continue;
517
-            }
518
-            //error checking
519
-            if (! $message->valid_messenger()) {
520
-                $error_messages[] = sprintf(
521
-                    __('The %s messenger is not active at time of sending.', 'event_espresso'),
522
-                    $message->messenger()
523
-                );
524
-            }
525
-            if (! $message->valid_message_type()) {
526
-                $error_messages[] = sprintf(
527
-                    __('The %s message type is not active at the time of sending.', 'event_espresso'),
528
-                    $message->message_type()
529
-                );
530
-            }
531
-            // if there was supposed to be a sending messenger for this message, but it was invalid/inactive,
532
-            // then it will instead be an EE_Error object, so let's check for that
533
-            if ($sending_messenger instanceof EE_Error) {
534
-                $error_messages[] = $sending_messenger->getMessage();
535
-            }
536
-            // if there are no errors, then let's process the message
537
-            if (empty($error_messages)) {
538
-                if ($save) {
539
-                    $message->set_messenger_is_executing();
540
-                }
541
-                if ($this->_process_message($message, $sending_messenger)) {
542
-                    $messages_sent++;
543
-                }
544
-            }
545
-            $this->_set_error_message($message, $error_messages);
546
-            //add modified time
547
-            $message->set_modified(time());
548
-            //we save each message after its processed to make sure its status persists in case PHP times-out or runs
549
-            //out of memory. @see https://events.codebasehq.com/projects/event-espresso/tickets/10281
550
-            if ($save) {
551
-                $message->save();
552
-            }
553
-
554
-            $this->_message_repository->next();
555
-        }
556
-        if ($save) {
557
-            $this->save(true);
558
-        }
559
-        return $messages_sent;
560
-    }
561
-
562
-
563
-    /**
564
-     * _process_message
565
-     *
566
-     * @param EE_Message $message
567
-     * @param mixed      $sending_messenger (optional)
568
-     * @return bool
569
-     */
570
-    protected function _process_message(EE_Message $message, $sending_messenger = null)
571
-    {
572
-        // these *should* have been validated in the execute() method above
573
-        $messenger    = $message->messenger_object();
574
-        $message_type = $message->message_type_object();
575
-        //do actions for sending messenger if it differs from generating messenger and swap values.
576
-        if (
577
-            $sending_messenger instanceof EE_messenger
578
-            && $messenger instanceof EE_messenger
579
-            && $sending_messenger->name != $messenger->name
580
-        ) {
581
-            $messenger->do_secondary_messenger_hooks($sending_messenger->name);
582
-            $messenger = $sending_messenger;
583
-        }
584
-        // send using messenger, but double check objects
585
-        if ($messenger instanceof EE_messenger && $message_type instanceof EE_message_type) {
586
-            //set hook for message type (but only if not using another messenger to send).
587
-            if ( ! isset($this->_did_hook[$message_type->name])) {
588
-                $message_type->do_messenger_hooks($messenger);
589
-                $this->_did_hook[$message_type->name] = 1;
590
-            }
591
-            //if preview then use preview method
592
-            return $this->_message_repository->is_preview()
593
-                ? $this->_do_preview($message, $messenger, $message_type, $this->_message_repository->is_test_send())
594
-                : $this->_do_send($message, $messenger, $message_type);
595
-        }
596
-        return false;
597
-    }
598
-
599
-
600
-    /**
601
-     * The intention of this method is to count how many EE_Message objects
602
-     * are in the queue with a given status.
603
-     * Example usage:
604
-     * After a caller calls the "EE_Message_Queue::execute()" method, the caller can check if there were any failed
605
-     * sends by calling $queue->count_STS_in_queue( EEM_Message_Queue::status_failed ).
606
-     *
607
-     * @param array|string $status Stati to check for in queue
608
-     * @return int  Count of EE_Message's matching the given status.
609
-     */
610
-    public function count_STS_in_queue($status)
611
-    {
612
-        $count  = 0;
613
-        $status = is_array($status) ? $status : array($status);
614
-        $this->_message_repository->rewind();
615
-        foreach ($this->_message_repository as $message) {
616
-            if (in_array($message->STS_ID(), $status)) {
617
-                $count++;
618
-            }
619
-        }
620
-        return $count;
621
-    }
622
-
623
-
624
-    /**
625
-     * Executes the get_preview method on the provided messenger.
626
-     *
627
-     * @param EE_Message      $message
628
-     * @param EE_messenger    $messenger
629
-     * @param EE_message_type $message_type
630
-     * @param                 $test_send
631
-     * @return bool   true means all went well, false means, not so much.
632
-     */
633
-    protected function _do_preview(
634
-        EE_Message $message,
635
-        EE_messenger $messenger,
636
-        EE_message_type $message_type,
637
-        $test_send
638
-    ) {
639
-        if ($preview = $messenger->get_preview($message, $message_type, $test_send)) {
640
-            if ( ! $test_send) {
641
-                $message->set_content($preview);
642
-            }
643
-            $message->set_STS_ID(EEM_Message::status_sent);
644
-            return true;
645
-        } else {
646
-            $message->set_STS_ID(EEM_Message::status_failed);
647
-            return false;
648
-        }
649
-    }
650
-
651
-
652
-    /**
653
-     * Executes the send method on the provided messenger
654
-     * EE_Messengers are expected to:
655
-     * - return true if the send was successful.
656
-     * - return false if the send was unsuccessful but can be tried again.
657
-     * - throw an Exception if the send was unsuccessful and cannot be tried again.
658
-     *
659
-     * @param EE_Message      $message
660
-     * @param EE_messenger    $messenger
661
-     * @param EE_message_type $message_type
662
-     * @return bool true means all went well, false means, not so much.
663
-     */
664
-    protected function _do_send(EE_Message $message, EE_messenger $messenger, EE_message_type $message_type)
665
-    {
666
-        try {
667
-            if ($messenger->send_message($message, $message_type)) {
668
-                $message->set_STS_ID(EEM_Message::status_sent);
669
-                return true;
670
-            } else {
671
-                $message->set_STS_ID(EEM_Message::status_retry);
672
-                return false;
673
-            }
674
-        } catch (SendMessageException $e) {
675
-            $message->set_STS_ID(EEM_Message::status_failed);
676
-            $message->set_error_message($e->getMessage());
677
-            return false;
678
-        }
679
-    }
680
-
681
-
682
-    /**
683
-     * This sets any necessary error messages on the message object and its status to failed.
684
-     *
685
-     * @param EE_Message $message
686
-     * @param array      $error_messages the response from the messenger.
687
-     */
688
-    protected function _set_error_message(EE_Message $message, $error_messages)
689
-    {
690
-        $error_messages = (array)$error_messages;
691
-        if (in_array($message->STS_ID(), EEM_Message::instance()->stati_indicating_failed_sending())) {
692
-            $notices          = EE_Error::has_notices();
693
-            $error_messages[] = __(
694
-                'Messenger and Message Type were valid and active, but the messenger send method failed.',
695
-                'event_espresso'
696
-            );
697
-            if ($notices === 1) {
698
-                $notices           = EE_Error::get_vanilla_notices();
699
-                $notices['errors'] = isset($notices['errors']) ? $notices['errors'] : array();
700
-                $error_messages[]  = implode("\n", $notices['errors']);
701
-            }
702
-        }
703
-        if (count($error_messages) > 0) {
704
-            $msg = __('Message was not executed successfully.', 'event_espresso');
705
-            $msg = $msg . "\n" . implode("\n", $error_messages);
706
-            $message->set_error_message($msg);
707
-        }
708
-    }
21
+	/**
22
+	 * @type    string  reference for sending action
23
+	 */
24
+	const action_sending = 'sending';
25
+
26
+	/**
27
+	 * @type    string  reference for generation action
28
+	 */
29
+	const action_generating = 'generation';
30
+
31
+
32
+	/**
33
+	 * @type EE_Message_Repository $_message_repository
34
+	 */
35
+	protected $_message_repository;
36
+
37
+	/**
38
+	 * Sets the limit of how many messages are generated per process.
39
+	 *
40
+	 * @type int
41
+	 */
42
+	protected $_batch_count;
43
+
44
+
45
+	/**
46
+	 * This is an array of cached queue items being stored in this object.
47
+	 * The array keys will be the ID of the EE_Message in the db if saved.  If the EE_Message
48
+	 * is not saved to the db then its key will be an increment of "UNS" (i.e. UNS1, UNS2 etc.)
49
+	 *
50
+	 * @type EE_Message[]
51
+	 */
52
+	protected $_cached_queue_items;
53
+
54
+	/**
55
+	 * Tracks the number of unsaved queue items.
56
+	 *
57
+	 * @type int
58
+	 */
59
+	protected $_unsaved_count = 0;
60
+
61
+	/**
62
+	 * used to record if a do_messenger_hooks has already been called for a message type.  This prevents multiple
63
+	 * hooks getting fired if users have setup their action/filter hooks to prevent duplicate calls.
64
+	 *
65
+	 * @type array
66
+	 */
67
+	protected $_did_hook = array();
68
+
69
+
70
+	/**
71
+	 * Constructor.
72
+	 * Setup all the initial properties and load a EE_Message_Repository.
73
+	 *
74
+	 * @param \EE_Message_Repository $message_repository
75
+	 */
76
+	public function __construct(EE_Message_Repository $message_repository)
77
+	{
78
+		$this->_batch_count        = apply_filters('FHEE__EE_Messages_Queue___batch_count', 50);
79
+		$this->_message_repository = $message_repository;
80
+	}
81
+
82
+
83
+	/**
84
+	 * Add a EE_Message object to the queue
85
+	 *
86
+	 * @param EE_Message $message
87
+	 * @param array      $data         This will be an array of data to attach to the object in the repository.  If the
88
+	 *                                 object is persisted, this data will be saved on an extra_meta object related to
89
+	 *                                 EE_Message.
90
+	 * @param  bool      $preview      Whether this EE_Message represents a preview or not.
91
+	 * @param  bool      $test_send    This indicates whether to do a test send instead of actual send. A test send will
92
+	 *                                 use the messenger send method but typically is based on preview data.
93
+	 * @return bool          Whether the message was successfully added to the repository or not.
94
+	 */
95
+	public function add(EE_Message $message, $data = array(), $preview = false, $test_send = false)
96
+	{
97
+		$data['preview']   = $preview;
98
+		$data['test_send'] = $test_send;
99
+		return $this->_message_repository->add($message, $data);
100
+	}
101
+
102
+
103
+	/**
104
+	 * Removes EE_Message from _queue that matches the given EE_Message if the pointer is on a matching EE_Message
105
+	 *
106
+	 * @param EE_Message $message The message to detach from the queue
107
+	 * @param bool       $persist This flag indicates whether to attempt to delete the object from the db as well.
108
+	 * @return bool
109
+	 */
110
+	public function remove(EE_Message $message, $persist = false)
111
+	{
112
+		if ($persist && $this->_message_repository->current() !== $message) {
113
+			//get pointer on right message
114
+			if ($this->_message_repository->has($message)) {
115
+				$this->_message_repository->rewind();
116
+				while ($this->_message_repository->valid()) {
117
+					if ($this->_message_repository->current() === $message) {
118
+						break;
119
+					}
120
+					$this->_message_repository->next();
121
+				}
122
+			} else {
123
+				return false;
124
+			}
125
+		}
126
+		return $persist ? $this->_message_repository->delete() : $this->_message_repository->remove($message);
127
+	}
128
+
129
+
130
+	/**
131
+	 * Persists all queued EE_Message objects to the db.
132
+	 *
133
+	 * @param bool $do_hooks_only       @see EE_Message_Repository::saveAll
134
+	 * @return array @see EE_Messages_Repository::saveAll() for return values.
135
+	 */
136
+	public function save($do_hooks_only = false)
137
+	{
138
+		return $this->_message_repository->saveAll($do_hooks_only);
139
+	}
140
+
141
+
142
+	/**
143
+	 * @return EE_Message_Repository
144
+	 */
145
+	public function get_message_repository()
146
+	{
147
+		return $this->_message_repository;
148
+	}
149
+
150
+
151
+	/**
152
+	 * This does the following things:
153
+	 * 1. Checks if there is a lock on generation (prevents race conditions).  If there is a lock then exits (return
154
+	 * false).
155
+	 * 2. If no lock, sets lock, then retrieves a batch of non-generated EE_Message objects and adds to queue
156
+	 * 3. Returns bool.  True = batch ready.  False = no batch ready (or nothing available for generation).
157
+	 * Note: Callers should make sure they release the lock otherwise batch generation will be prevented from
158
+	 * continuing. The lock is on a transient that is set to expire after one hour as a fallback in case locks are not
159
+	 * removed.
160
+	 *
161
+	 * @return bool  true if successfully retrieved batch, false no batch ready.
162
+	 */
163
+	public function get_batch_to_generate()
164
+	{
165
+		if ($this->is_locked(EE_Messages_Queue::action_generating)) {
166
+			return false;
167
+		}
168
+
169
+		//lock batch generation to prevent race conditions.
170
+		$this->lock_queue(EE_Messages_Queue::action_generating);
171
+
172
+		$query_args = array(
173
+			// key 0 = where conditions
174
+			0          => array('STS_ID' => EEM_Message::status_incomplete),
175
+			'order_by' => $this->_get_priority_orderby(),
176
+			'limit'    => $this->_batch_count,
177
+		);
178
+		$messages   = EEM_Message::instance()->get_all($query_args);
179
+
180
+		if ( ! $messages) {
181
+			return false; //nothing to generate
182
+		}
183
+
184
+		foreach ($messages as $message) {
185
+			if ($message instanceof EE_Message) {
186
+				$data = $message->all_extra_meta_array();
187
+				$this->add($message, $data);
188
+			}
189
+		}
190
+		return true;
191
+	}
192
+
193
+
194
+	/**
195
+	 * This does the following things:
196
+	 * 1. Checks if there is a lock on sending (prevents race conditions).  If there is a lock then exits (return
197
+	 * false).
198
+	 * 2. Grabs the allowed number of messages to send for the rate_limit.  If cannot send any more messages, then
199
+	 * return false.
200
+	 * 2. If no lock, sets lock, then retrieves a batch of EE_Message objects, adds to queue and triggers execution.
201
+	 * 3. On success or unsuccessful send, sets status appropriately.
202
+	 * 4. Saves messages via the queue
203
+	 * 5. Releases lock.
204
+	 *
205
+	 * @return bool  true on success, false if something preventing sending (i.e. lock set).  Note: true does not
206
+	 *               necessarily mean that all messages were successfully sent.  It just means that this method
207
+	 *               successfully completed. On true, client may want to call $this->count_STS_in_queue(
208
+	 *               EEM_Message::status_failed ) to see if any failed EE_Message objects.  Each failed message object
209
+	 *               will also have a saved error message on it to assist with notifying user.
210
+	 */
211
+	public function get_to_send_batch_and_send()
212
+	{
213
+		$rate_limit = $this->get_rate_limit();
214
+		if ($rate_limit < 1 || $this->is_locked(EE_Messages_Queue::action_sending)) {
215
+			return false;
216
+		}
217
+
218
+		$this->lock_queue(EE_Messages_Queue::action_sending);
219
+
220
+		$batch = $this->_batch_count < $rate_limit ? $this->_batch_count : $rate_limit;
221
+
222
+		$query_args = array(
223
+			// key 0 = where conditions
224
+			0          => array('STS_ID' => array('IN', EEM_Message::instance()->stati_indicating_to_send())),
225
+			'order_by' => $this->_get_priority_orderby(),
226
+			'limit'    => $batch,
227
+		);
228
+
229
+		$messages_to_send = EEM_Message::instance()->get_all($query_args);
230
+
231
+
232
+		//any to send?
233
+		if ( ! $messages_to_send) {
234
+			$this->unlock_queue(EE_Messages_Queue::action_sending);
235
+			return false;
236
+		}
237
+
238
+		$queue_count = 0;
239
+
240
+		//add to queue.
241
+		foreach ($messages_to_send as $message) {
242
+			if ($message instanceof EE_Message) {
243
+				$queue_count++;
244
+				$this->add($message);
245
+			}
246
+		}
247
+
248
+		//send messages  (this also updates the rate limit)
249
+		$this->execute();
250
+
251
+		//release lock
252
+		$this->unlock_queue(EE_Messages_Queue::action_sending);
253
+		//update rate limit
254
+		$this->set_rate_limit($queue_count);
255
+		return true;
256
+	}
257
+
258
+
259
+	/**
260
+	 * Locks the queue so that no other queues can call the "batch" methods.
261
+	 *
262
+	 * @param   string $type The type of queue being locked.
263
+	 */
264
+	public function lock_queue($type = EE_Messages_Queue::action_generating)
265
+	{
266
+		update_option($this->_get_lock_key($type), $this->_get_lock_expiry($type));
267
+	}
268
+
269
+
270
+	/**
271
+	 * Unlocks the queue so that batch methods can be used.
272
+	 *
273
+	 * @param   string $type The type of queue being unlocked.
274
+	 */
275
+	public function unlock_queue($type = EE_Messages_Queue::action_generating)
276
+	{
277
+		delete_option($this->_get_lock_key($type));
278
+	}
279
+
280
+
281
+	/**
282
+	 * Retrieve the key used for the lock transient.
283
+	 *
284
+	 * @param string $type The type of lock.
285
+	 * @return string
286
+	 */
287
+	protected function _get_lock_key($type = EE_Messages_Queue::action_generating)
288
+	{
289
+		return '_ee_lock_' . $type;
290
+	}
291
+
292
+
293
+	/**
294
+	 * Retrieve the expiry time for the lock transient.
295
+	 *
296
+	 * @param string $type The type of lock
297
+	 * @return int   time to expiry in seconds.
298
+	 */
299
+	protected function _get_lock_expiry($type = EE_Messages_Queue::action_generating)
300
+	{
301
+		return time() + (int) apply_filters('FHEE__EE_Messages_Queue__lock_expiry', HOUR_IN_SECONDS, $type);
302
+	}
303
+
304
+
305
+	/**
306
+	 * Returns the key used for rate limit transient.
307
+	 *
308
+	 * @return string
309
+	 */
310
+	protected function _get_rate_limit_key()
311
+	{
312
+		return '_ee_rate_limit';
313
+	}
314
+
315
+
316
+	/**
317
+	 * Returns the rate limit expiry time.
318
+	 *
319
+	 * @return int
320
+	 */
321
+	protected function _get_rate_limit_expiry()
322
+	{
323
+		return time() + (int) apply_filters('FHEE__EE_Messages_Queue__rate_limit_expiry', HOUR_IN_SECONDS);
324
+	}
325
+
326
+
327
+	/**
328
+	 * Returns the default rate limit for sending messages.
329
+	 *
330
+	 * @return int
331
+	 */
332
+	protected function _default_rate_limit()
333
+	{
334
+		return (int) apply_filters('FHEE__EE_Messages_Queue___rate_limit', 200);
335
+	}
336
+
337
+
338
+	/**
339
+	 * Return the orderby array for priority.
340
+	 *
341
+	 * @return array
342
+	 */
343
+	protected function _get_priority_orderby()
344
+	{
345
+		return array(
346
+			'MSG_priority' => 'ASC',
347
+			'MSG_modified' => 'DESC',
348
+		);
349
+	}
350
+
351
+
352
+	/**
353
+	 * Returns whether batch methods are "locked" or not.
354
+	 *
355
+	 * @param  string $type The type of lock being checked for.
356
+	 * @return bool
357
+	 */
358
+	public function is_locked($type = EE_Messages_Queue::action_generating)
359
+	{
360
+		$lock = (int) get_option($this->_get_lock_key($type), 0);
361
+		/**
362
+		 * This filters the default is_locked behaviour.
363
+		 */
364
+		$is_locked = filter_var(
365
+			apply_filters(
366
+				'FHEE__EE_Messages_Queue__is_locked',
367
+				$lock > time(),
368
+				$this
369
+			),
370
+			FILTER_VALIDATE_BOOLEAN
371
+		);
372
+
373
+		/**
374
+		 * @see usage of this filter in EE_Messages_Queue::initiate_request_by_priority() method.
375
+		 *            Also implemented here because messages processed on the same request should not have any locks applied.
376
+		 */
377
+		if (
378
+			apply_filters('FHEE__EE_Messages_Processor__initiate_request_by_priority__do_immediate_processing', false)
379
+			|| EE_Registry::instance()->NET_CFG->core->do_messages_on_same_request
380
+		) {
381
+			$is_locked = false;
382
+		}
383
+
384
+
385
+		return $is_locked;
386
+	}
387
+
388
+
389
+	/**
390
+	 * Retrieves the rate limit that may be cached as a transient.
391
+	 * If the rate limit is not set, then this sets the default rate limit and expiry and returns it.
392
+	 *
393
+	 * @param bool $return_expiry  If true then return the expiry time not the rate_limit.
394
+	 * @return int
395
+	 */
396
+	protected function get_rate_limit($return_expiry = false)
397
+	{
398
+		$stored_rate_info = get_option($this->_get_rate_limit_key(), array());
399
+		$rate_limit = isset($stored_rate_info[0])
400
+			? (int) $stored_rate_info[0]
401
+			: 0;
402
+		$expiry = isset($stored_rate_info[1])
403
+			? (int) $stored_rate_info[1]
404
+			: 0;
405
+		//set the default for tracking?
406
+		if (empty($stored_rate_info) || time() > $expiry) {
407
+			$expiry = $this->_get_rate_limit_expiry();
408
+			$rate_limit = $this->_default_rate_limit();
409
+			update_option($this->_get_rate_limit_key(), array($rate_limit, $expiry));
410
+		}
411
+		return $return_expiry ? $expiry : $rate_limit;
412
+	}
413
+
414
+
415
+	/**
416
+	 * This updates existing rate limit with the new limit which is the old minus the batch.
417
+	 *
418
+	 * @param int $batch_completed This sets the new rate limit based on the given batch that was completed.
419
+	 */
420
+	protected function set_rate_limit($batch_completed)
421
+	{
422
+		//first get the most up to date rate limit (in case its expired and reset)
423
+		$rate_limit = $this->get_rate_limit();
424
+		$expiry = $this->get_rate_limit(true);
425
+		$new_limit  = $rate_limit - $batch_completed;
426
+		//updating the transient option directly to avoid resetting the expiry.
427
+
428
+		update_option($this->_get_rate_limit_key(), array($new_limit, $expiry));
429
+	}
430
+
431
+
432
+	/**
433
+	 * This method checks the queue for ANY EE_Message objects with a priority matching the given priority passed in.
434
+	 * If that exists, then we immediately initiate a non-blocking request to do the requested action type.
435
+	 * Note: Keep in mind that there is the possibility that the request will not execute if there is already another
436
+	 * request running on a queue for the given task.
437
+	 *
438
+	 * @param string $task     This indicates what type of request is going to be initiated.
439
+	 * @param int    $priority This indicates the priority that triggers initiating the request.
440
+	 */
441
+	public function initiate_request_by_priority($task = 'generate', $priority = EEM_Message::priority_high)
442
+	{
443
+		//determine what status is matched with the priority as part of the trigger conditions.
444
+		$status = $task == 'generate'
445
+			? EEM_Message::status_incomplete
446
+			: EEM_Message::instance()->stati_indicating_to_send();
447
+		// always make sure we save because either this will get executed immediately on a separate request
448
+		// or remains in the queue for the regularly scheduled queue batch.
449
+		$this->save();
450
+		/**
451
+		 * This filter/option allows users to override processing of messages on separate requests and instead have everything
452
+		 * happen on the same request.  If this is utilized remember:
453
+		 * - message priorities don't matter
454
+		 * - existing unprocessed messages in the queue will not get processed unless manually triggered.
455
+		 * - things will be perceived to take longer to happen for end users (i.e. registrations) because of the additional
456
+		 *   processing happening on the same request.
457
+		 * - any race condition protection (locks) are removed because they don't apply when things are processed on
458
+		 *   the same request.
459
+		 */
460
+		if (
461
+			apply_filters('FHEE__EE_Messages_Processor__initiate_request_by_priority__do_immediate_processing', false)
462
+			|| EE_Registry::instance()->NET_CFG->core->do_messages_on_same_request
463
+		) {
464
+			$messages_processor = EE_Registry::instance()->load_lib('Messages_Processor');
465
+			if ($messages_processor instanceof EE_Messages_Processor) {
466
+				return $messages_processor->process_immediately_from_queue($this);
467
+			}
468
+			//if we get here then that means the messages processor couldn't be loaded so messages will just remain
469
+			//queued for manual triggering by end user.
470
+		}
471
+
472
+		if ($this->_message_repository->count_by_priority_and_status($priority, $status)) {
473
+			EE_Messages_Scheduler::initiate_scheduled_non_blocking_request($task);
474
+		}
475
+	}
476
+
477
+
478
+	/**
479
+	 *  Loops through the EE_Message objects in the _queue and calls the messenger send methods for each message.
480
+	 *
481
+	 * @param   bool     $save                    Used to indicate whether to save the message queue after sending
482
+	 *                                            (default will save).
483
+	 * @param   mixed    $sending_messenger       (optional) When the sending messenger is different than
484
+	 *                                            what is on the EE_Message object in the queue.
485
+	 *                                            For instance, showing the browser view of an email message,
486
+	 *                                            or giving a pdf generated view of an html document.
487
+	 *                                            This should be an instance of EE_messenger but if you call this
488
+	 *                                            method
489
+	 *                                            intending it to be a sending messenger but a valid one could not be
490
+	 *                                            retrieved then send in an instance of EE_Error that contains the
491
+	 *                                            related error message.
492
+	 * @param   bool|int $by_priority             When set, this indicates that only messages
493
+	 *                                            matching the given priority should be executed.
494
+	 * @return int        Number of messages sent.  Note, 0 does not mean that no messages were processed.
495
+	 *                                            Also, if the messenger is an request type messenger (or a preview),
496
+	 *                                            its entirely possible that the messenger will exit before
497
+	 */
498
+	public function execute($save = true, $sending_messenger = null, $by_priority = false)
499
+	{
500
+		$messages_sent   = 0;
501
+		$this->_did_hook = array();
502
+		$this->_message_repository->rewind();
503
+
504
+		while ($this->_message_repository->valid()) {
505
+			$error_messages = array();
506
+			/** @type EE_Message $message */
507
+			$message = $this->_message_repository->current();
508
+			//only process things that are queued for sending
509
+			if (! in_array($message->STS_ID(), EEM_Message::instance()->stati_indicating_to_send())) {
510
+				$this->_message_repository->next();
511
+				continue;
512
+			}
513
+			//if $by_priority is set and does not match then continue;
514
+			if ($by_priority && $by_priority != $message->priority()) {
515
+				$this->_message_repository->next();
516
+				continue;
517
+			}
518
+			//error checking
519
+			if (! $message->valid_messenger()) {
520
+				$error_messages[] = sprintf(
521
+					__('The %s messenger is not active at time of sending.', 'event_espresso'),
522
+					$message->messenger()
523
+				);
524
+			}
525
+			if (! $message->valid_message_type()) {
526
+				$error_messages[] = sprintf(
527
+					__('The %s message type is not active at the time of sending.', 'event_espresso'),
528
+					$message->message_type()
529
+				);
530
+			}
531
+			// if there was supposed to be a sending messenger for this message, but it was invalid/inactive,
532
+			// then it will instead be an EE_Error object, so let's check for that
533
+			if ($sending_messenger instanceof EE_Error) {
534
+				$error_messages[] = $sending_messenger->getMessage();
535
+			}
536
+			// if there are no errors, then let's process the message
537
+			if (empty($error_messages)) {
538
+				if ($save) {
539
+					$message->set_messenger_is_executing();
540
+				}
541
+				if ($this->_process_message($message, $sending_messenger)) {
542
+					$messages_sent++;
543
+				}
544
+			}
545
+			$this->_set_error_message($message, $error_messages);
546
+			//add modified time
547
+			$message->set_modified(time());
548
+			//we save each message after its processed to make sure its status persists in case PHP times-out or runs
549
+			//out of memory. @see https://events.codebasehq.com/projects/event-espresso/tickets/10281
550
+			if ($save) {
551
+				$message->save();
552
+			}
553
+
554
+			$this->_message_repository->next();
555
+		}
556
+		if ($save) {
557
+			$this->save(true);
558
+		}
559
+		return $messages_sent;
560
+	}
561
+
562
+
563
+	/**
564
+	 * _process_message
565
+	 *
566
+	 * @param EE_Message $message
567
+	 * @param mixed      $sending_messenger (optional)
568
+	 * @return bool
569
+	 */
570
+	protected function _process_message(EE_Message $message, $sending_messenger = null)
571
+	{
572
+		// these *should* have been validated in the execute() method above
573
+		$messenger    = $message->messenger_object();
574
+		$message_type = $message->message_type_object();
575
+		//do actions for sending messenger if it differs from generating messenger and swap values.
576
+		if (
577
+			$sending_messenger instanceof EE_messenger
578
+			&& $messenger instanceof EE_messenger
579
+			&& $sending_messenger->name != $messenger->name
580
+		) {
581
+			$messenger->do_secondary_messenger_hooks($sending_messenger->name);
582
+			$messenger = $sending_messenger;
583
+		}
584
+		// send using messenger, but double check objects
585
+		if ($messenger instanceof EE_messenger && $message_type instanceof EE_message_type) {
586
+			//set hook for message type (but only if not using another messenger to send).
587
+			if ( ! isset($this->_did_hook[$message_type->name])) {
588
+				$message_type->do_messenger_hooks($messenger);
589
+				$this->_did_hook[$message_type->name] = 1;
590
+			}
591
+			//if preview then use preview method
592
+			return $this->_message_repository->is_preview()
593
+				? $this->_do_preview($message, $messenger, $message_type, $this->_message_repository->is_test_send())
594
+				: $this->_do_send($message, $messenger, $message_type);
595
+		}
596
+		return false;
597
+	}
598
+
599
+
600
+	/**
601
+	 * The intention of this method is to count how many EE_Message objects
602
+	 * are in the queue with a given status.
603
+	 * Example usage:
604
+	 * After a caller calls the "EE_Message_Queue::execute()" method, the caller can check if there were any failed
605
+	 * sends by calling $queue->count_STS_in_queue( EEM_Message_Queue::status_failed ).
606
+	 *
607
+	 * @param array|string $status Stati to check for in queue
608
+	 * @return int  Count of EE_Message's matching the given status.
609
+	 */
610
+	public function count_STS_in_queue($status)
611
+	{
612
+		$count  = 0;
613
+		$status = is_array($status) ? $status : array($status);
614
+		$this->_message_repository->rewind();
615
+		foreach ($this->_message_repository as $message) {
616
+			if (in_array($message->STS_ID(), $status)) {
617
+				$count++;
618
+			}
619
+		}
620
+		return $count;
621
+	}
622
+
623
+
624
+	/**
625
+	 * Executes the get_preview method on the provided messenger.
626
+	 *
627
+	 * @param EE_Message      $message
628
+	 * @param EE_messenger    $messenger
629
+	 * @param EE_message_type $message_type
630
+	 * @param                 $test_send
631
+	 * @return bool   true means all went well, false means, not so much.
632
+	 */
633
+	protected function _do_preview(
634
+		EE_Message $message,
635
+		EE_messenger $messenger,
636
+		EE_message_type $message_type,
637
+		$test_send
638
+	) {
639
+		if ($preview = $messenger->get_preview($message, $message_type, $test_send)) {
640
+			if ( ! $test_send) {
641
+				$message->set_content($preview);
642
+			}
643
+			$message->set_STS_ID(EEM_Message::status_sent);
644
+			return true;
645
+		} else {
646
+			$message->set_STS_ID(EEM_Message::status_failed);
647
+			return false;
648
+		}
649
+	}
650
+
651
+
652
+	/**
653
+	 * Executes the send method on the provided messenger
654
+	 * EE_Messengers are expected to:
655
+	 * - return true if the send was successful.
656
+	 * - return false if the send was unsuccessful but can be tried again.
657
+	 * - throw an Exception if the send was unsuccessful and cannot be tried again.
658
+	 *
659
+	 * @param EE_Message      $message
660
+	 * @param EE_messenger    $messenger
661
+	 * @param EE_message_type $message_type
662
+	 * @return bool true means all went well, false means, not so much.
663
+	 */
664
+	protected function _do_send(EE_Message $message, EE_messenger $messenger, EE_message_type $message_type)
665
+	{
666
+		try {
667
+			if ($messenger->send_message($message, $message_type)) {
668
+				$message->set_STS_ID(EEM_Message::status_sent);
669
+				return true;
670
+			} else {
671
+				$message->set_STS_ID(EEM_Message::status_retry);
672
+				return false;
673
+			}
674
+		} catch (SendMessageException $e) {
675
+			$message->set_STS_ID(EEM_Message::status_failed);
676
+			$message->set_error_message($e->getMessage());
677
+			return false;
678
+		}
679
+	}
680
+
681
+
682
+	/**
683
+	 * This sets any necessary error messages on the message object and its status to failed.
684
+	 *
685
+	 * @param EE_Message $message
686
+	 * @param array      $error_messages the response from the messenger.
687
+	 */
688
+	protected function _set_error_message(EE_Message $message, $error_messages)
689
+	{
690
+		$error_messages = (array)$error_messages;
691
+		if (in_array($message->STS_ID(), EEM_Message::instance()->stati_indicating_failed_sending())) {
692
+			$notices          = EE_Error::has_notices();
693
+			$error_messages[] = __(
694
+				'Messenger and Message Type were valid and active, but the messenger send method failed.',
695
+				'event_espresso'
696
+			);
697
+			if ($notices === 1) {
698
+				$notices           = EE_Error::get_vanilla_notices();
699
+				$notices['errors'] = isset($notices['errors']) ? $notices['errors'] : array();
700
+				$error_messages[]  = implode("\n", $notices['errors']);
701
+			}
702
+		}
703
+		if (count($error_messages) > 0) {
704
+			$msg = __('Message was not executed successfully.', 'event_espresso');
705
+			$msg = $msg . "\n" . implode("\n", $error_messages);
706
+			$message->set_error_message($msg);
707
+		}
708
+	}
709 709
 
710 710
 } //end EE_Messages_Queue class
Please login to merge, or discard this patch.
Spacing   +8 added lines, -8 removed lines patch added patch discarded remove patch
@@ -1,7 +1,7 @@  discard block
 block discarded – undo
1 1
 <?php
2 2
 use \EventEspresso\core\exceptions\SendMessageException;
3 3
 
4
-if (! defined('EVENT_ESPRESSO_VERSION')) {
4
+if ( ! defined('EVENT_ESPRESSO_VERSION')) {
5 5
     exit('No direct script access allowed');
6 6
 }
7 7
 
@@ -175,7 +175,7 @@  discard block
 block discarded – undo
175 175
             'order_by' => $this->_get_priority_orderby(),
176 176
             'limit'    => $this->_batch_count,
177 177
         );
178
-        $messages   = EEM_Message::instance()->get_all($query_args);
178
+        $messages = EEM_Message::instance()->get_all($query_args);
179 179
 
180 180
         if ( ! $messages) {
181 181
             return false; //nothing to generate
@@ -286,7 +286,7 @@  discard block
 block discarded – undo
286 286
      */
287 287
     protected function _get_lock_key($type = EE_Messages_Queue::action_generating)
288 288
     {
289
-        return '_ee_lock_' . $type;
289
+        return '_ee_lock_'.$type;
290 290
     }
291 291
 
292 292
 
@@ -506,7 +506,7 @@  discard block
 block discarded – undo
506 506
             /** @type EE_Message $message */
507 507
             $message = $this->_message_repository->current();
508 508
             //only process things that are queued for sending
509
-            if (! in_array($message->STS_ID(), EEM_Message::instance()->stati_indicating_to_send())) {
509
+            if ( ! in_array($message->STS_ID(), EEM_Message::instance()->stati_indicating_to_send())) {
510 510
                 $this->_message_repository->next();
511 511
                 continue;
512 512
             }
@@ -516,13 +516,13 @@  discard block
 block discarded – undo
516 516
                 continue;
517 517
             }
518 518
             //error checking
519
-            if (! $message->valid_messenger()) {
519
+            if ( ! $message->valid_messenger()) {
520 520
                 $error_messages[] = sprintf(
521 521
                     __('The %s messenger is not active at time of sending.', 'event_espresso'),
522 522
                     $message->messenger()
523 523
                 );
524 524
             }
525
-            if (! $message->valid_message_type()) {
525
+            if ( ! $message->valid_message_type()) {
526 526
                 $error_messages[] = sprintf(
527 527
                     __('The %s message type is not active at the time of sending.', 'event_espresso'),
528 528
                     $message->message_type()
@@ -687,7 +687,7 @@  discard block
 block discarded – undo
687 687
      */
688 688
     protected function _set_error_message(EE_Message $message, $error_messages)
689 689
     {
690
-        $error_messages = (array)$error_messages;
690
+        $error_messages = (array) $error_messages;
691 691
         if (in_array($message->STS_ID(), EEM_Message::instance()->stati_indicating_failed_sending())) {
692 692
             $notices          = EE_Error::has_notices();
693 693
             $error_messages[] = __(
@@ -702,7 +702,7 @@  discard block
 block discarded – undo
702 702
         }
703 703
         if (count($error_messages) > 0) {
704 704
             $msg = __('Message was not executed successfully.', 'event_espresso');
705
-            $msg = $msg . "\n" . implode("\n", $error_messages);
705
+            $msg = $msg."\n".implode("\n", $error_messages);
706 706
             $message->set_error_message($msg);
707 707
         }
708 708
     }
Please login to merge, or discard this patch.