Completed
Branch FET/reg-form-builder/extract-a... (6e8a58)
by
unknown
35:36 queued 25:38
created

RegFormHandler::processRegistrations()   B

Complexity

Conditions 8
Paths 10

Size

Total Lines 50

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 8
nc 10
nop 2
dl 0
loc 50
rs 7.8464
c 0
b 0
f 0
1
<?php
2
3
namespace EventEspresso\core\domain\services\registration\form\v1;
4
5
use EE_Checkout;
6
use EE_Error;
7
use EE_Registration;
8
use EE_Registration_Processor;
9
use EventEspresso\core\domain\entities\contexts\Context;
10
use EventEspresso\core\exceptions\EntityNotFoundException;
11
use EventEspresso\core\exceptions\InvalidDataTypeException;
12
use EventEspresso\core\exceptions\InvalidInterfaceException;
13
use EventEspresso\core\services\loaders\LoaderFactory;
14
use InvalidArgumentException;
15
use ReflectionException;
16
use RuntimeException;
17
18
class RegFormHandler
19
{
20
21
    /**
22
     * @var EE_Checkout
23
     */
24
    public $checkout;
25
26
    /**
27
     * @var RegFormInputHandler
28
     */
29
    public $input_handler;
30
31
    /**
32
     * @var array
33
     */
34
    private $non_input_form_sections;
35
36
    /**
37
     * @var RegFormAttendeeFactory
38
     */
39
    private $attendee_factory;
40
41
    /**
42
     * @var RegistrantData
43
     */
44
    private $registrant_data;
45
46
    /**
47
     * @var EE_Registration_Processor
48
     */
49
    private $registration_processor;
50
51
    /**
52
     * @var bool
53
     */
54
    private $valid;
55
56
57
    /**
58
     * RegFormHandler constructor.
59
     */
60
    public function __construct(
61
        EE_Checkout $checkout,
62
        RegistrantData $registrant_data,
63
        RegFormAttendeeFactory $attendee_factory,
64
        EE_Registration_Processor $registration_processor
65
    ) {
66
        $this->checkout                = $checkout;
67
        $this->registrant_data         = $registrant_data;
68
        $this->attendee_factory        = $attendee_factory;
69
        $this->registration_processor  = $registration_processor;
70
        // reg form sections that do not contain inputs
71
        $this->non_input_form_sections = [
72
            'primary_registrant_data',
73
            'additional_attendee_reg_info',
74
            'spco_copy_attendee_chk',
75
        ];
76
        $this->initializeInputHandler();
77
    }
78
79
80
    private function initializeInputHandler()
81
    {
82
        $reg_form = $this->checkout->current_step->reg_form;
83
        $required_questions = $reg_form instanceof RegForm ? $reg_form->requiredQuestions() : [];
84
        $this->input_handler = LoaderFactory::getShared(
85
            RegFormInputHandler::class,
86
            [ $this->checkout->reg_url_link, $required_questions ]
87
        );
88
89
    }
90
91
92
    /**
93
     * @return int
94
     */
95
    public function attendeeCount(): int
96
    {
97
        return $this->registrant_data->attendeeCount();
98
    }
99
100
101
    /**
102
     * @return bool
103
     */
104
    private function isInvalid(): bool
105
    {
106
        $this->valid = false;
107
        return $this->valid;
108
    }
109
110
111
    /**
112
     * @param EE_Registration[] $registrations
113
     * @param array[][]         $reg_form_data
114
     * @return bool
115
     * @throws EntityNotFoundException
116
     * @throws EE_Error
117
     * @throws InvalidArgumentException
118
     * @throws ReflectionException
119
     * @throws RuntimeException
120
     * @throws InvalidDataTypeException
121
     * @throws InvalidInterfaceException
122
     */
123
    public function processRegistrations(array $registrations, array $reg_form_data): bool
124
    {
125
        // start off optimistic, then trip this to false if anything goes wrong
126
        $this->valid = true;
127
        foreach ($registrations as $registration) {
128
            // verify EE_Registration object
129
            if (! $this->isValidRegistration($registration)) {
130
                return $this->isInvalid();
131
            }
132
            $reg_url_link = $registration->reg_url_link();
133
            // reg_url_link exists ?
134
            if (! $this->isValidRegUrlLink($reg_url_link)) {
135
                return $this->isInvalid();
136
            }
137
            // should this registration be processed during this visit ?
138
            if (! $this->checkout->visit_allows_processing_of_this_registration($registration)) {
139
                continue;
140
            }
141
            // if NOT revisiting, then let's save the registration now,
142
            // so that we have a REG_ID to use when generating other objects
143
            if (! $this->checkout->revisit) {
144
                $registration->save();
145
            }
146
            /**
147
             * This allows plugins to trigger a fail on processing of a
148
             * registration for any conditions they may have for it to pass.
149
             *
150
             * @var bool if true is returned by the plugin then the registration processing is halted.
151
             */
152
            if (
153
                apply_filters(
154
                    'FHEE__EE_SPCO_Reg_Step_Attendee_Information___process_registrations__pre_registration_process',
155
                    false,
156
                    $this->registrant_data->attendeeCount(),
157
                    $registration,
158
                    $registrations,
159
                    $reg_form_data,
160
                    $this
161
                )
162
            ) {
163
                return $this->isInvalid();
164
            }
165
166
            // Houston, we have a registration!
167
            if (! $this->processRegistration($registration, $reg_url_link, $reg_form_data)) {
168
                return $this->isInvalid();
169
            }
170
        }
171
        return $this->valid;
172
    }
173
174
175
    /**
176
     * @param string $reg_url_link
177
     * @return bool
178
     */
179 View Code Duplication
    private function isValidRegUrlLink(string $reg_url_link): bool
180
    {
181
        if (! empty($reg_url_link)) {
182
            return true;
183
        }
184
        EE_Error::add_error(
185
            esc_html__(
186
                'An invalid or missing line item ID was encountered while attempting to process the registration form.',
187
                'event_espresso'
188
            ),
189
            __FILE__,
190
            __FUNCTION__,
191
            __LINE__
192
        );
193
        return false;
194
    }
195
196
197
    /**
198
     * @param EE_Registration $registration
199
     * @return bool
200
     */
201 View Code Duplication
    private function isValidRegistration(EE_Registration $registration): bool
202
    {
203
        // verify EE_Registration object
204
        if ($registration instanceof EE_Registration) {
205
            return true;
206
        }
207
        EE_Error::add_error(
208
            esc_html__(
209
                'An invalid Registration object was discovered when attempting to process your registration information.',
210
                'event_espresso'
211
            ),
212
            __FILE__,
213
            __FUNCTION__,
214
            __LINE__
215
        );
216
        return false;
217
    }
218
219
220
    /**
221
     * @param EE_Registration $registration
222
     * @param string          $reg_url_link
223
     * @param array[][]       $reg_form_data
224
     * @return bool
225
     * @throws EE_Error
226
     * @throws ReflectionException
227
     */
228
    private function processRegistration(
229
        EE_Registration $registration,
230
        string $reg_url_link,
231
        array $reg_form_data
232
    ): bool {
233
        $this->registrant_data->initializeRegistrantData($registration);
234
        if (! $this->processRegFormData($registration, $reg_url_link, $reg_form_data)) {
235
            return false;
236
        }
237
        // RegFormAttendeeFactory
238
        if (! $this->attendee_factory->create($registration, $reg_url_link)) {
239
            return false;
240
        }
241
        // at this point, we should have enough details about the registrant to consider the registration
242
        // NOT incomplete
243
        $this->registration_processor->toggle_incomplete_registration_status_to_default(
244
            $registration,
245
            false,
246
            new Context(
247
                'spco_reg_step_attendee_information_process_registrations',
248
                esc_html__(
249
                    'Finished populating registration with details from the registration form after submitting the Attendee Information Reg Step.',
250
                    'event_espresso'
251
                )
252
            )
253
        );
254
        // we can also consider the TXN to not have been failed, so temporarily upgrade it's status to
255
        // abandoned
256
        $this->checkout->transaction->toggle_failed_transaction_status();
257
        // if we've gotten this far, then let's save what we have
258
        $registration->save();
259
        // add relation between TXN and registration
260
        $this->associateRegistrationWithTransaction($registration);
261
        return true;
262
    }
263
264
265
    /**
266
     * @param EE_Registration $registration
267
     * @param string          $reg_url_link
268
     * @param array           $reg_form_data
269
     * @return bool
270
     * @throws EE_Error
271
     * @throws ReflectionException
272
     */
273
    private function processRegFormData(EE_Registration $registration, string $reg_url_link, array $reg_form_data): bool
274
    {
275
        if (isset($reg_form_data[ $reg_url_link ])) {
276
            // do we need to copy basic info from primary attendee ?
277
            $copy_primary = isset($reg_form_data[ $reg_url_link ]['additional_attendee_reg_info'])
278
                                  && absint($reg_form_data[ $reg_url_link ]['additional_attendee_reg_info']) === 0;
279
            $this->registrant_data->setCopyPrimary($copy_primary);
280
            // filter form input data for this registration
281
            $reg_form_data[ $reg_url_link ] = (array) apply_filters(
282
                'FHEE__EE_Single_Page_Checkout__process_attendee_information__valid_data_line_item',
283
                $reg_form_data[ $reg_url_link ]
284
            );
285
            if (isset($reg_form_data['primary_attendee'])) {
286
                $primary_reg_url_link = $reg_form_data['primary_attendee'] ?? '';
287
                $this->registrant_data->addPrimaryRegistrantDataValue('reg_url_link', $primary_reg_url_link);
288
                unset($reg_form_data['primary_attendee']);
289
            }
290
            // now loop through our array of valid post data && process attendee reg forms
291
            foreach ($reg_form_data[ $reg_url_link ] as $form_section => $form_inputs) {
0 ignored issues
show
Bug introduced by
The expression $reg_form_data[$reg_url_link] of type array|null is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
292
                if (in_array($form_section, $this->non_input_form_sections, true)) {
293
                    continue;
294
                }
295
                foreach ($form_inputs as $form_input => $input_value) {
296
                    $input_processed = $this->input_handler->processFormInput(
297
                        $registration,
298
                        $reg_url_link,
299
                        $form_input,
300
                        $input_value
301
                    );
302
                    if (! $input_processed) {
303
                        return false;
304
                    }
305
                }
306
            }
307
        }
308
        return true;
309
    }
310
311
312
    /**
313
     * @param EE_Registration $registration
314
     * @return void
315
     * @throws EE_Error
316
     * @throws InvalidArgumentException
317
     * @throws ReflectionException
318
     * @throws InvalidDataTypeException
319
     * @throws InvalidInterfaceException
320
     */
321
    private function associateRegistrationWithTransaction(EE_Registration $registration)
322
    {
323
        // add relation to registration
324
        $this->checkout->transaction->_add_relation_to($registration, 'Registration');
325
        $this->checkout->transaction->update_cache_after_object_save('Registration', $registration);
326
    }
327
}
328