Completed
Branch master (c63335)
by
unknown
17:58 queued 13:20
created
core/services/json/JsonDataWordpressOption.php 1 patch
Indentation   +90 added lines, -90 removed lines patch added patch discarded remove patch
@@ -15,94 +15,94 @@
 block discarded – undo
15 15
  */
16 16
 abstract class JsonDataWordpressOption extends WordPressOption
17 17
 {
18
-    private JsonDataHandler $json_data_handler;
19
-
20
-    /**
21
-     * @var array|mixed|stdClass
22
-     */
23
-    private $options = [];
24
-
25
-
26
-    /**
27
-     * JsonDataWordpressOption constructor.
28
-     *
29
-     * @param JsonDataHandler $json_data_handler
30
-     * @param string          $option_name
31
-     * @param                 $default_value
32
-     * @param bool            $autoload
33
-     */
34
-    public function __construct(
35
-        JsonDataHandler $json_data_handler,
36
-        string $option_name,
37
-        $default_value,
38
-        bool $autoload = false
39
-    ) {
40
-        $this->json_data_handler = $json_data_handler;
41
-        if (! $this->json_data_handler->dataType()) {
42
-            $this->json_data_handler->configure(JsonDataHandler::DATA_TYPE_OBJECT);
43
-        }
44
-        parent::__construct($option_name, $default_value, $autoload);
45
-    }
46
-
47
-
48
-    /**
49
-     * @param $value
50
-     * @return int
51
-     */
52
-    public function updateOption($value): int
53
-    {
54
-        $update = parent::updateOption($this->json_data_handler->encodeData($value));
55
-        if ($update === WordPressOption::UPDATE_SUCCESS) {
56
-            $this->options = $value;
57
-        }
58
-        return $update;
59
-    }
60
-
61
-
62
-    /**
63
-     * @param string $property
64
-     * @param mixed  $value
65
-     * @return void
66
-     */
67
-    public function addProperty(string $property, $value)
68
-    {
69
-        $options              = $this->getAll();
70
-        $options->{$property} = $value;
71
-        $this->updateOption($options);
72
-    }
73
-
74
-
75
-    /**
76
-     * @param string $property
77
-     * @return mixed
78
-     */
79
-    public function getProperty(string $property)
80
-    {
81
-        $options = $this->getAll();
82
-        return property_exists($options, $property) ? $options->{$property} : null;
83
-    }
84
-
85
-
86
-    /**
87
-     * @return array|mixed|stdClass
88
-     */
89
-    public function getAll()
90
-    {
91
-        if (empty($this->options)) {
92
-            $this->options = $this->json_data_handler->decodeJson($this->loadOption());
93
-        }
94
-        return $this->options;
95
-    }
96
-
97
-
98
-    /**
99
-     * @param string $property
100
-     * @return void
101
-     */
102
-    public function removeProperty(string $property)
103
-    {
104
-        $options = $this->getAll();
105
-        unset($options->{$property});
106
-        $this->updateOption($options);
107
-    }
18
+	private JsonDataHandler $json_data_handler;
19
+
20
+	/**
21
+	 * @var array|mixed|stdClass
22
+	 */
23
+	private $options = [];
24
+
25
+
26
+	/**
27
+	 * JsonDataWordpressOption constructor.
28
+	 *
29
+	 * @param JsonDataHandler $json_data_handler
30
+	 * @param string          $option_name
31
+	 * @param                 $default_value
32
+	 * @param bool            $autoload
33
+	 */
34
+	public function __construct(
35
+		JsonDataHandler $json_data_handler,
36
+		string $option_name,
37
+		$default_value,
38
+		bool $autoload = false
39
+	) {
40
+		$this->json_data_handler = $json_data_handler;
41
+		if (! $this->json_data_handler->dataType()) {
42
+			$this->json_data_handler->configure(JsonDataHandler::DATA_TYPE_OBJECT);
43
+		}
44
+		parent::__construct($option_name, $default_value, $autoload);
45
+	}
46
+
47
+
48
+	/**
49
+	 * @param $value
50
+	 * @return int
51
+	 */
52
+	public function updateOption($value): int
53
+	{
54
+		$update = parent::updateOption($this->json_data_handler->encodeData($value));
55
+		if ($update === WordPressOption::UPDATE_SUCCESS) {
56
+			$this->options = $value;
57
+		}
58
+		return $update;
59
+	}
60
+
61
+
62
+	/**
63
+	 * @param string $property
64
+	 * @param mixed  $value
65
+	 * @return void
66
+	 */
67
+	public function addProperty(string $property, $value)
68
+	{
69
+		$options              = $this->getAll();
70
+		$options->{$property} = $value;
71
+		$this->updateOption($options);
72
+	}
73
+
74
+
75
+	/**
76
+	 * @param string $property
77
+	 * @return mixed
78
+	 */
79
+	public function getProperty(string $property)
80
+	{
81
+		$options = $this->getAll();
82
+		return property_exists($options, $property) ? $options->{$property} : null;
83
+	}
84
+
85
+
86
+	/**
87
+	 * @return array|mixed|stdClass
88
+	 */
89
+	public function getAll()
90
+	{
91
+		if (empty($this->options)) {
92
+			$this->options = $this->json_data_handler->decodeJson($this->loadOption());
93
+		}
94
+		return $this->options;
95
+	}
96
+
97
+
98
+	/**
99
+	 * @param string $property
100
+	 * @return void
101
+	 */
102
+	public function removeProperty(string $property)
103
+	{
104
+		$options = $this->getAll();
105
+		unset($options->{$property});
106
+		$this->updateOption($options);
107
+	}
108 108
 }
Please login to merge, or discard this patch.
core/services/json/JsonDataHandler.php 1 patch
Indentation   +327 added lines, -327 removed lines patch added patch discarded remove patch
@@ -14,331 +14,331 @@
 block discarded – undo
14 14
  */
15 15
 class JsonDataHandler
16 16
 {
17
-    const DATA_TYPE_ARRAY     = 'array';
18
-
19
-    const DATA_TYPE_OBJECT    = 'object';
20
-
21
-    const DATA_TYPE_USE_FLAGS = 'flags';
22
-
23
-    const NO_ERROR_MSG        = 'No error';
24
-
25
-    private string $data_type = JsonDataHandler::DATA_TYPE_USE_FLAGS;
26
-
27
-    /**
28
-     * @var array|stdClass|null
29
-     */
30
-    private $decoded_data = null;
31
-
32
-    /**
33
-     * JSON_BIGINT_AS_STRING,
34
-     * JSON_INVALID_UTF8_IGNORE,
35
-     * JSON_INVALID_UTF8_SUBSTITUTE,
36
-     * JSON_OBJECT_AS_ARRAY,
37
-     * JSON_THROW_ON_ERROR
38
-     *
39
-     * @var int
40
-     */
41
-    private int $decode_flags = 0;
42
-
43
-    private int $depth = 512;
44
-
45
-    private string $encoded_data = '';
46
-
47
-    /**
48
-     * JSON_FORCE_OBJECT,
49
-     * JSON_HEX_QUOT,
50
-     * JSON_HEX_TAG,
51
-     * JSON_HEX_AMP,
52
-     * JSON_HEX_APOS,
53
-     * JSON_INVALID_UTF8_IGNORE,
54
-     * JSON_INVALID_UTF8_SUBSTITUTE,
55
-     * JSON_NUMERIC_CHECK,
56
-     * JSON_PARTIAL_OUTPUT_ON_ERROR,
57
-     * JSON_PRESERVE_ZERO_FRACTION,
58
-     * JSON_PRETTY_PRINT,
59
-     * JSON_UNESCAPED_LINE_TERMINATORS,
60
-     * JSON_UNESCAPED_SLASHES,
61
-     * JSON_UNESCAPED_UNICODE,
62
-     * JSON_THROW_ON_ERROR.
63
-     *
64
-     * @var int
65
-     */
66
-    private int $encode_flags = 0;
67
-
68
-    private int $last_error_code = JSON_ERROR_NONE;
69
-
70
-    private string $last_error_msg = JsonDataHandler::NO_ERROR_MSG;
71
-
72
-
73
-    /**
74
-     * JsonDataHandler constructor.
75
-     */
76
-    public function __construct()
77
-    {
78
-        if (! defined('JSON_INVALID_UTF8_IGNORE')) {
79
-            define('JSON_INVALID_UTF8_IGNORE', 1048576);
80
-        }
81
-        if (! defined('JSON_INVALID_UTF8_SUBSTITUTE')) {
82
-            define('JSON_INVALID_UTF8_SUBSTITUTE', 2097152);
83
-        }
84
-        if (! defined('JSON_THROW_ON_ERROR')) {
85
-            define('JSON_THROW_ON_ERROR', 4194304);
86
-        }
87
-    }
88
-
89
-
90
-    /**
91
-     * set $data_type, $decode_flags, $encode_flags, and depth all in one shot
92
-     *
93
-     * @param string $data_type
94
-     * @param int    $decode_flags
95
-     * @param int    $encode_flags
96
-     * @param int    $depth
97
-     */
98
-    public function configure(
99
-        string $data_type = JsonDataHandler::DATA_TYPE_USE_FLAGS,
100
-        int $decode_flags = 0,
101
-        int $encode_flags = 0,
102
-        int $depth = 512
103
-    ) {
104
-        $this->setDataType($data_type);
105
-        $this->setDecodeFlags($decode_flags);
106
-        $this->setDepth($depth);
107
-        $this->setEncodeFlags($encode_flags);
108
-    }
109
-
110
-
111
-    /**
112
-     * @param string $data_type
113
-     */
114
-    public function setDataType(string $data_type): void
115
-    {
116
-        $this->data_type = $data_type === JsonDataHandler::DATA_TYPE_ARRAY
117
-                           || $data_type === JsonDataHandler::DATA_TYPE_OBJECT
118
-                           || $data_type === JsonDataHandler::DATA_TYPE_USE_FLAGS
119
-            ? $data_type
120
-            : JsonDataHandler::DATA_TYPE_USE_FLAGS;
121
-    }
122
-
123
-
124
-    /**
125
-     * One or more Bitmask values:
126
-     * JSON_BIGINT_AS_STRING,
127
-     * JSON_INVALID_UTF8_IGNORE,        PHP >= 7.2
128
-     * JSON_INVALID_UTF8_SUBSTITUTE,    PHP >= 7.2
129
-     * JSON_OBJECT_AS_ARRAY,
130
-     * JSON_THROW_ON_ERROR              PHP >= 7.3
131
-     *
132
-     * pass multiple values separated with |
133
-     * ex: JSON_BIGINT_AS_STRING | JSON_INVALID_UTF8_IGNORE | JSON_OBJECT_AS_ARRAY
134
-     *
135
-     * @param int $decode_flags
136
-     */
137
-    public function setDecodeFlags(int $decode_flags): void
138
-    {
139
-        $this->decode_flags = $decode_flags === JSON_BIGINT_AS_STRING
140
-                              || $decode_flags === JSON_OBJECT_AS_ARRAY
141
-                              // phpcs:ignore PHPCompatibility.Constants.NewConstants.json_invalid_utf8_ignoreFound
142
-                              || $decode_flags === JSON_INVALID_UTF8_IGNORE
143
-                              // phpcs:ignore PHPCompatibility.Constants.NewConstants.json_invalid_utf8_substituteFound
144
-                              || $decode_flags === JSON_INVALID_UTF8_SUBSTITUTE
145
-                              // phpcs:ignore PHPCompatibility.Constants.NewConstants.json_throw_on_errorFound
146
-                              || $decode_flags === JSON_THROW_ON_ERROR
147
-            ? $decode_flags
148
-            : 0;
149
-    }
150
-
151
-
152
-    /**
153
-     * @param int $depth
154
-     */
155
-    public function setDepth(int $depth): void
156
-    {
157
-        $depth       = absint($depth);
158
-        $this->depth = $depth ?: 512;
159
-    }
160
-
161
-
162
-    /**
163
-     * One or more Bitmask values:
164
-     * JSON_FORCE_OBJECT,
165
-     * JSON_HEX_QUOT,
166
-     * JSON_HEX_TAG,
167
-     * JSON_HEX_AMP,
168
-     * JSON_HEX_APOS,
169
-     * JSON_INVALID_UTF8_IGNORE,        PHP >= 7.2
170
-     * JSON_INVALID_UTF8_SUBSTITUTE,    PHP >= 7.2
171
-     * JSON_NUMERIC_CHECK,
172
-     * JSON_PARTIAL_OUTPUT_ON_ERROR,
173
-     * JSON_PRESERVE_ZERO_FRACTION,
174
-     * JSON_PRETTY_PRINT,
175
-     * JSON_UNESCAPED_LINE_TERMINATORS,
176
-     * JSON_UNESCAPED_SLASHES,
177
-     * JSON_UNESCAPED_UNICODE,
178
-     * JSON_THROW_ON_ERROR.             PHP >= 7.3
179
-     *
180
-     * pass multiple values separated with |
181
-     * ex: JSON_FORCE_OBJECT | JSON_INVALID_UTF8_IGNORE | JSON_THROW_ON_ERROR
182
-     *
183
-     * @param int $encode_flags
184
-     */
185
-    public function setEncodeFlags(int $encode_flags): void
186
-    {
187
-        $this->encode_flags = $encode_flags === JSON_FORCE_OBJECT
188
-                              || $encode_flags === JSON_HEX_QUOT
189
-                              || $encode_flags === JSON_HEX_TAG
190
-                              || $encode_flags === JSON_HEX_AMP
191
-                              || $encode_flags === JSON_HEX_APOS
192
-                              || $encode_flags === JSON_NUMERIC_CHECK
193
-                              || $encode_flags === JSON_PARTIAL_OUTPUT_ON_ERROR
194
-                              || $encode_flags === JSON_PRESERVE_ZERO_FRACTION
195
-                              || $encode_flags === JSON_PRETTY_PRINT
196
-                              || $encode_flags === JSON_UNESCAPED_LINE_TERMINATORS
197
-                              || $encode_flags === JSON_UNESCAPED_SLASHES
198
-                              || $encode_flags === JSON_UNESCAPED_UNICODE
199
-                              // phpcs:ignore PHPCompatibility.Constants.NewConstants.json_invalid_utf8_ignoreFound
200
-                              || $encode_flags === JSON_INVALID_UTF8_IGNORE
201
-                              // phpcs:ignore PHPCompatibility.Constants.NewConstants.json_invalid_utf8_substituteFound
202
-                              || $encode_flags === JSON_INVALID_UTF8_SUBSTITUTE
203
-                              // phpcs:ignore PHPCompatibility.Constants.NewConstants.json_throw_on_errorFound
204
-                              || $encode_flags === JSON_THROW_ON_ERROR
205
-            ? $encode_flags
206
-            : 0;
207
-    }
208
-
209
-
210
-    /**
211
-     * @return string|null
212
-     */
213
-    public function dataType(): ?string
214
-    {
215
-        return $this->data_type;
216
-    }
217
-
218
-
219
-    /**
220
-     * @return bool|null
221
-     */
222
-    private function asAssociative(): ?bool
223
-    {
224
-        switch ($this->data_type) {
225
-            case JsonDataHandler::DATA_TYPE_ARRAY:
226
-                return true;
227
-            case JsonDataHandler::DATA_TYPE_OBJECT:
228
-                return false;
229
-            case JsonDataHandler::DATA_TYPE_USE_FLAGS:
230
-                return null;
231
-        }
232
-        return null;
233
-    }
234
-
235
-
236
-    /**
237
-     * @param array|string $json
238
-     * @return array|mixed|stdClass
239
-     */
240
-    public function decodeJson($json)
241
-    {
242
-        $this->resetErrors();
243
-        if ($this->isJson($json)) {
244
-            $this->decoded_data    = json_decode($json, $this->asAssociative(), $this->depth, $this->decode_flags);
245
-            $this->last_error_code = json_last_error();
246
-            $this->last_error_msg  = json_last_error_msg();
247
-        } else {
248
-            $this->decoded_data    = $json;
249
-            $this->last_error_code = JSON_ERROR_NONE;
250
-            $this->last_error_msg  = JsonDataHandler::NO_ERROR_MSG;
251
-        }
252
-        return $this->decoded_data;
253
-    }
254
-
255
-
256
-    /**
257
-     * @param $data
258
-     * @return string
259
-     */
260
-    public function encodeData($data): string
261
-    {
262
-        $this->resetErrors();
263
-        if ($this->isJson($data)) {
264
-            $this->encoded_data    = $data;
265
-            $this->last_error_code = JSON_ERROR_NONE;
266
-            $this->last_error_msg  = JsonDataHandler::NO_ERROR_MSG;
267
-        } else {
268
-            $this->encoded_data    = json_encode($data, $this->encode_flags, $this->depth);
269
-            $this->last_error_code = json_last_error();
270
-            $this->last_error_msg  = json_last_error_msg();
271
-        }
272
-        return $this->encoded_data ?: '{}';
273
-    }
274
-
275
-
276
-    /**
277
-     * @return array|stdClass
278
-     */
279
-    public function getDecodedData()
280
-    {
281
-        return $this->decoded_data;
282
-    }
283
-
284
-
285
-    /**
286
-     * @return string
287
-     */
288
-    public function getEncodedData(): string
289
-    {
290
-        return $this->encoded_data;
291
-    }
292
-
293
-
294
-    /**
295
-     * @param bool $reset
296
-     * @return int
297
-     */
298
-    public function getLastErrorCode(bool $reset = false): int
299
-    {
300
-        $last_error = $this->last_error_code;
301
-        if ($reset) {
302
-            $this->resetErrors();
303
-        }
304
-        return $last_error;
305
-    }
306
-
307
-
308
-    /**
309
-     * @param bool $reset
310
-     * @return string
311
-     */
312
-    public function getLastErrorMessage(bool $reset = false): string
313
-    {
314
-        $last_error = $this->last_error_msg;
315
-        if ($reset) {
316
-            $this->resetErrors();
317
-        }
318
-        return $last_error;
319
-    }
320
-
321
-
322
-    /**
323
-     * @param array|string $maybe_json
324
-     * @return bool
325
-     */
326
-    public function isJson($maybe_json): bool
327
-    {
328
-        if (! is_string($maybe_json)) {
329
-            return false;
330
-        }
331
-        $decoded = json_decode($maybe_json, $this->asAssociative(), $this->depth, $this->decode_flags);
332
-        return json_last_error() === JSON_ERROR_NONE && ! ($decoded === null && ! empty($maybe_json));
333
-    }
334
-
335
-
336
-    /**
337
-     * @since 5.0.0.p
338
-     */
339
-    public function resetErrors()
340
-    {
341
-        $this->last_error_code = JSON_ERROR_NONE;
342
-        $this->last_error_msg  = JsonDataHandler::NO_ERROR_MSG;
343
-    }
17
+	const DATA_TYPE_ARRAY     = 'array';
18
+
19
+	const DATA_TYPE_OBJECT    = 'object';
20
+
21
+	const DATA_TYPE_USE_FLAGS = 'flags';
22
+
23
+	const NO_ERROR_MSG        = 'No error';
24
+
25
+	private string $data_type = JsonDataHandler::DATA_TYPE_USE_FLAGS;
26
+
27
+	/**
28
+	 * @var array|stdClass|null
29
+	 */
30
+	private $decoded_data = null;
31
+
32
+	/**
33
+	 * JSON_BIGINT_AS_STRING,
34
+	 * JSON_INVALID_UTF8_IGNORE,
35
+	 * JSON_INVALID_UTF8_SUBSTITUTE,
36
+	 * JSON_OBJECT_AS_ARRAY,
37
+	 * JSON_THROW_ON_ERROR
38
+	 *
39
+	 * @var int
40
+	 */
41
+	private int $decode_flags = 0;
42
+
43
+	private int $depth = 512;
44
+
45
+	private string $encoded_data = '';
46
+
47
+	/**
48
+	 * JSON_FORCE_OBJECT,
49
+	 * JSON_HEX_QUOT,
50
+	 * JSON_HEX_TAG,
51
+	 * JSON_HEX_AMP,
52
+	 * JSON_HEX_APOS,
53
+	 * JSON_INVALID_UTF8_IGNORE,
54
+	 * JSON_INVALID_UTF8_SUBSTITUTE,
55
+	 * JSON_NUMERIC_CHECK,
56
+	 * JSON_PARTIAL_OUTPUT_ON_ERROR,
57
+	 * JSON_PRESERVE_ZERO_FRACTION,
58
+	 * JSON_PRETTY_PRINT,
59
+	 * JSON_UNESCAPED_LINE_TERMINATORS,
60
+	 * JSON_UNESCAPED_SLASHES,
61
+	 * JSON_UNESCAPED_UNICODE,
62
+	 * JSON_THROW_ON_ERROR.
63
+	 *
64
+	 * @var int
65
+	 */
66
+	private int $encode_flags = 0;
67
+
68
+	private int $last_error_code = JSON_ERROR_NONE;
69
+
70
+	private string $last_error_msg = JsonDataHandler::NO_ERROR_MSG;
71
+
72
+
73
+	/**
74
+	 * JsonDataHandler constructor.
75
+	 */
76
+	public function __construct()
77
+	{
78
+		if (! defined('JSON_INVALID_UTF8_IGNORE')) {
79
+			define('JSON_INVALID_UTF8_IGNORE', 1048576);
80
+		}
81
+		if (! defined('JSON_INVALID_UTF8_SUBSTITUTE')) {
82
+			define('JSON_INVALID_UTF8_SUBSTITUTE', 2097152);
83
+		}
84
+		if (! defined('JSON_THROW_ON_ERROR')) {
85
+			define('JSON_THROW_ON_ERROR', 4194304);
86
+		}
87
+	}
88
+
89
+
90
+	/**
91
+	 * set $data_type, $decode_flags, $encode_flags, and depth all in one shot
92
+	 *
93
+	 * @param string $data_type
94
+	 * @param int    $decode_flags
95
+	 * @param int    $encode_flags
96
+	 * @param int    $depth
97
+	 */
98
+	public function configure(
99
+		string $data_type = JsonDataHandler::DATA_TYPE_USE_FLAGS,
100
+		int $decode_flags = 0,
101
+		int $encode_flags = 0,
102
+		int $depth = 512
103
+	) {
104
+		$this->setDataType($data_type);
105
+		$this->setDecodeFlags($decode_flags);
106
+		$this->setDepth($depth);
107
+		$this->setEncodeFlags($encode_flags);
108
+	}
109
+
110
+
111
+	/**
112
+	 * @param string $data_type
113
+	 */
114
+	public function setDataType(string $data_type): void
115
+	{
116
+		$this->data_type = $data_type === JsonDataHandler::DATA_TYPE_ARRAY
117
+						   || $data_type === JsonDataHandler::DATA_TYPE_OBJECT
118
+						   || $data_type === JsonDataHandler::DATA_TYPE_USE_FLAGS
119
+			? $data_type
120
+			: JsonDataHandler::DATA_TYPE_USE_FLAGS;
121
+	}
122
+
123
+
124
+	/**
125
+	 * One or more Bitmask values:
126
+	 * JSON_BIGINT_AS_STRING,
127
+	 * JSON_INVALID_UTF8_IGNORE,        PHP >= 7.2
128
+	 * JSON_INVALID_UTF8_SUBSTITUTE,    PHP >= 7.2
129
+	 * JSON_OBJECT_AS_ARRAY,
130
+	 * JSON_THROW_ON_ERROR              PHP >= 7.3
131
+	 *
132
+	 * pass multiple values separated with |
133
+	 * ex: JSON_BIGINT_AS_STRING | JSON_INVALID_UTF8_IGNORE | JSON_OBJECT_AS_ARRAY
134
+	 *
135
+	 * @param int $decode_flags
136
+	 */
137
+	public function setDecodeFlags(int $decode_flags): void
138
+	{
139
+		$this->decode_flags = $decode_flags === JSON_BIGINT_AS_STRING
140
+							  || $decode_flags === JSON_OBJECT_AS_ARRAY
141
+							  // phpcs:ignore PHPCompatibility.Constants.NewConstants.json_invalid_utf8_ignoreFound
142
+							  || $decode_flags === JSON_INVALID_UTF8_IGNORE
143
+							  // phpcs:ignore PHPCompatibility.Constants.NewConstants.json_invalid_utf8_substituteFound
144
+							  || $decode_flags === JSON_INVALID_UTF8_SUBSTITUTE
145
+							  // phpcs:ignore PHPCompatibility.Constants.NewConstants.json_throw_on_errorFound
146
+							  || $decode_flags === JSON_THROW_ON_ERROR
147
+			? $decode_flags
148
+			: 0;
149
+	}
150
+
151
+
152
+	/**
153
+	 * @param int $depth
154
+	 */
155
+	public function setDepth(int $depth): void
156
+	{
157
+		$depth       = absint($depth);
158
+		$this->depth = $depth ?: 512;
159
+	}
160
+
161
+
162
+	/**
163
+	 * One or more Bitmask values:
164
+	 * JSON_FORCE_OBJECT,
165
+	 * JSON_HEX_QUOT,
166
+	 * JSON_HEX_TAG,
167
+	 * JSON_HEX_AMP,
168
+	 * JSON_HEX_APOS,
169
+	 * JSON_INVALID_UTF8_IGNORE,        PHP >= 7.2
170
+	 * JSON_INVALID_UTF8_SUBSTITUTE,    PHP >= 7.2
171
+	 * JSON_NUMERIC_CHECK,
172
+	 * JSON_PARTIAL_OUTPUT_ON_ERROR,
173
+	 * JSON_PRESERVE_ZERO_FRACTION,
174
+	 * JSON_PRETTY_PRINT,
175
+	 * JSON_UNESCAPED_LINE_TERMINATORS,
176
+	 * JSON_UNESCAPED_SLASHES,
177
+	 * JSON_UNESCAPED_UNICODE,
178
+	 * JSON_THROW_ON_ERROR.             PHP >= 7.3
179
+	 *
180
+	 * pass multiple values separated with |
181
+	 * ex: JSON_FORCE_OBJECT | JSON_INVALID_UTF8_IGNORE | JSON_THROW_ON_ERROR
182
+	 *
183
+	 * @param int $encode_flags
184
+	 */
185
+	public function setEncodeFlags(int $encode_flags): void
186
+	{
187
+		$this->encode_flags = $encode_flags === JSON_FORCE_OBJECT
188
+							  || $encode_flags === JSON_HEX_QUOT
189
+							  || $encode_flags === JSON_HEX_TAG
190
+							  || $encode_flags === JSON_HEX_AMP
191
+							  || $encode_flags === JSON_HEX_APOS
192
+							  || $encode_flags === JSON_NUMERIC_CHECK
193
+							  || $encode_flags === JSON_PARTIAL_OUTPUT_ON_ERROR
194
+							  || $encode_flags === JSON_PRESERVE_ZERO_FRACTION
195
+							  || $encode_flags === JSON_PRETTY_PRINT
196
+							  || $encode_flags === JSON_UNESCAPED_LINE_TERMINATORS
197
+							  || $encode_flags === JSON_UNESCAPED_SLASHES
198
+							  || $encode_flags === JSON_UNESCAPED_UNICODE
199
+							  // phpcs:ignore PHPCompatibility.Constants.NewConstants.json_invalid_utf8_ignoreFound
200
+							  || $encode_flags === JSON_INVALID_UTF8_IGNORE
201
+							  // phpcs:ignore PHPCompatibility.Constants.NewConstants.json_invalid_utf8_substituteFound
202
+							  || $encode_flags === JSON_INVALID_UTF8_SUBSTITUTE
203
+							  // phpcs:ignore PHPCompatibility.Constants.NewConstants.json_throw_on_errorFound
204
+							  || $encode_flags === JSON_THROW_ON_ERROR
205
+			? $encode_flags
206
+			: 0;
207
+	}
208
+
209
+
210
+	/**
211
+	 * @return string|null
212
+	 */
213
+	public function dataType(): ?string
214
+	{
215
+		return $this->data_type;
216
+	}
217
+
218
+
219
+	/**
220
+	 * @return bool|null
221
+	 */
222
+	private function asAssociative(): ?bool
223
+	{
224
+		switch ($this->data_type) {
225
+			case JsonDataHandler::DATA_TYPE_ARRAY:
226
+				return true;
227
+			case JsonDataHandler::DATA_TYPE_OBJECT:
228
+				return false;
229
+			case JsonDataHandler::DATA_TYPE_USE_FLAGS:
230
+				return null;
231
+		}
232
+		return null;
233
+	}
234
+
235
+
236
+	/**
237
+	 * @param array|string $json
238
+	 * @return array|mixed|stdClass
239
+	 */
240
+	public function decodeJson($json)
241
+	{
242
+		$this->resetErrors();
243
+		if ($this->isJson($json)) {
244
+			$this->decoded_data    = json_decode($json, $this->asAssociative(), $this->depth, $this->decode_flags);
245
+			$this->last_error_code = json_last_error();
246
+			$this->last_error_msg  = json_last_error_msg();
247
+		} else {
248
+			$this->decoded_data    = $json;
249
+			$this->last_error_code = JSON_ERROR_NONE;
250
+			$this->last_error_msg  = JsonDataHandler::NO_ERROR_MSG;
251
+		}
252
+		return $this->decoded_data;
253
+	}
254
+
255
+
256
+	/**
257
+	 * @param $data
258
+	 * @return string
259
+	 */
260
+	public function encodeData($data): string
261
+	{
262
+		$this->resetErrors();
263
+		if ($this->isJson($data)) {
264
+			$this->encoded_data    = $data;
265
+			$this->last_error_code = JSON_ERROR_NONE;
266
+			$this->last_error_msg  = JsonDataHandler::NO_ERROR_MSG;
267
+		} else {
268
+			$this->encoded_data    = json_encode($data, $this->encode_flags, $this->depth);
269
+			$this->last_error_code = json_last_error();
270
+			$this->last_error_msg  = json_last_error_msg();
271
+		}
272
+		return $this->encoded_data ?: '{}';
273
+	}
274
+
275
+
276
+	/**
277
+	 * @return array|stdClass
278
+	 */
279
+	public function getDecodedData()
280
+	{
281
+		return $this->decoded_data;
282
+	}
283
+
284
+
285
+	/**
286
+	 * @return string
287
+	 */
288
+	public function getEncodedData(): string
289
+	{
290
+		return $this->encoded_data;
291
+	}
292
+
293
+
294
+	/**
295
+	 * @param bool $reset
296
+	 * @return int
297
+	 */
298
+	public function getLastErrorCode(bool $reset = false): int
299
+	{
300
+		$last_error = $this->last_error_code;
301
+		if ($reset) {
302
+			$this->resetErrors();
303
+		}
304
+		return $last_error;
305
+	}
306
+
307
+
308
+	/**
309
+	 * @param bool $reset
310
+	 * @return string
311
+	 */
312
+	public function getLastErrorMessage(bool $reset = false): string
313
+	{
314
+		$last_error = $this->last_error_msg;
315
+		if ($reset) {
316
+			$this->resetErrors();
317
+		}
318
+		return $last_error;
319
+	}
320
+
321
+
322
+	/**
323
+	 * @param array|string $maybe_json
324
+	 * @return bool
325
+	 */
326
+	public function isJson($maybe_json): bool
327
+	{
328
+		if (! is_string($maybe_json)) {
329
+			return false;
330
+		}
331
+		$decoded = json_decode($maybe_json, $this->asAssociative(), $this->depth, $this->decode_flags);
332
+		return json_last_error() === JSON_ERROR_NONE && ! ($decoded === null && ! empty($maybe_json));
333
+	}
334
+
335
+
336
+	/**
337
+	 * @since 5.0.0.p
338
+	 */
339
+	public function resetErrors()
340
+	{
341
+		$this->last_error_code = JSON_ERROR_NONE;
342
+		$this->last_error_msg  = JsonDataHandler::NO_ERROR_MSG;
343
+	}
344 344
 }
Please login to merge, or discard this patch.
core/services/notifications/PersistentAdminNoticeManager.php 2 patches
Indentation   +371 added lines, -371 removed lines patch added patch discarded remove patch
@@ -29,375 +29,375 @@
 block discarded – undo
29 29
  */
30 30
 class PersistentAdminNoticeManager
31 31
 {
32
-    const WP_OPTION_KEY = 'ee_pers_admin_notices';
33
-
34
-    private CapabilitiesChecker $capabilities_checker;
35
-
36
-    private RequestInterface $request;
37
-
38
-    /**
39
-     * @var Collection|PersistentAdminNotice[]|null $notice_collection
40
-     */
41
-    private ?Collection $notice_collection = null;
42
-
43
-    /**
44
-     * if AJAX is not enabled, then the return URL will be used for redirecting back to the admin page where the
45
-     * persistent admin notice was displayed, and ultimately dismissed from.
46
-     *
47
-     * @var string $return_url
48
-     */
49
-    private string $return_url;
50
-
51
-
52
-
53
-    /**
54
-     * PersistentAdminNoticeManager constructor
55
-     *
56
-     * @param CapabilitiesChecker $capabilities_checker
57
-     * @param RequestInterface    $request
58
-     * @param string              $return_url where to  redirect to after dismissing notices
59
-     */
60
-    public function __construct(
61
-        CapabilitiesChecker $capabilities_checker,
62
-        RequestInterface $request,
63
-        string $return_url = ''
64
-    ) {
65
-        $this->capabilities_checker = $capabilities_checker;
66
-        $this->request = $request;
67
-        $this->setReturnUrl($return_url);
68
-        // setup up notices at priority 9 because `EE_Admin::display_admin_notices()` runs at priority 10,
69
-        // and we want to retrieve and generate any nag notices at the last possible moment
70
-        add_action('admin_notices', array($this, 'displayNotices'), 9);
71
-        add_action('network_admin_notices', array($this, 'displayNotices'), 9);
72
-        add_action('wp_ajax_dismiss_ee_nag_notice', array($this, 'dismissNotice'));
73
-        add_action('shutdown', array($this, 'registerAndSaveNotices'), 998);
74
-    }
75
-
76
-
77
-    /**
78
-     * @param string $return_url
79
-     */
80
-    public function setReturnUrl(string $return_url)
81
-    {
82
-        $this->return_url = $return_url;
83
-    }
84
-
85
-
86
-    /**
87
-     * @return Collection
88
-     * @throws InvalidEntityException
89
-     * @throws InvalidInterfaceException
90
-     * @throws DomainException
91
-     * @throws DuplicateCollectionIdentifierException
92
-     */
93
-    protected function getPersistentAdminNoticeCollection(): Collection
94
-    {
95
-        if (! $this->notice_collection instanceof Collection) {
96
-            $this->notice_collection = new Collection(
97
-                'EventEspresso\core\domain\entities\notifications\PersistentAdminNotice'
98
-            );
99
-            $this->retrieveStoredNotices();
100
-            $this->registerNotices();
101
-        }
102
-        return $this->notice_collection;
103
-    }
104
-
105
-
106
-    /**
107
-     * generates PersistentAdminNotice objects for all non-dismissed notices saved to the db
108
-     *
109
-     * @return void
110
-     * @throws InvalidEntityException
111
-     * @throws DomainException
112
-     * @throws DuplicateCollectionIdentifierException
113
-     */
114
-    protected function retrieveStoredNotices()
115
-    {
116
-        $persistent_admin_notices = get_option(PersistentAdminNoticeManager::WP_OPTION_KEY, array());
117
-        if (! empty($persistent_admin_notices)) {
118
-            foreach ($persistent_admin_notices as $name => $details) {
119
-                if (is_array($details)) {
120
-                    if (
121
-                        ! isset(
122
-                            $details['message'],
123
-                            $details['capability'],
124
-                            $details['cap_context'],
125
-                            $details['dismissed']
126
-                        )
127
-                    ) {
128
-                        throw new DomainException(
129
-                            sprintf(
130
-                                esc_html__(
131
-                                    'The "%1$s" PersistentAdminNotice could not be retrieved from the database.',
132
-                                    'event_espresso'
133
-                                ),
134
-                                $name
135
-                            )
136
-                        );
137
-                    }
138
-                    // new format for nag notices
139
-                    $this->notice_collection->add(
140
-                        new PersistentAdminNotice(
141
-                            (string) $name,
142
-                            (string) $details['message'],
143
-                            false,
144
-                            (string) $details['capability'],
145
-                            (string) $details['cap_context'],
146
-                            (bool) $details['dismissed']
147
-                        ),
148
-                        sanitize_key($name)
149
-                    );
150
-                } else {
151
-                    try {
152
-                        // old nag notices, that we want to convert to the new format
153
-                        $this->notice_collection->add(
154
-                            new PersistentAdminNotice(
155
-                                (string) $name,
156
-                                (string) $details,
157
-                                false,
158
-                                '',
159
-                                '',
160
-                                empty($details)
161
-                            ),
162
-                            sanitize_key($name)
163
-                        );
164
-                    } catch (Exception $e) {
165
-                        EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__);
166
-                    }
167
-                }
168
-                // each notice will self register when the action hook in registerNotices is triggered
169
-            }
170
-        }
171
-    }
172
-
173
-
174
-    /**
175
-     * exposes the Persistent Admin Notice Collection via an action
176
-     * so that PersistentAdminNotice objects can be added and/or removed
177
-     * without compromising the actual collection like a filter would
178
-     */
179
-    protected function registerNotices()
180
-    {
181
-        do_action(
182
-            'AHEE__EventEspresso_core_services_notifications_PersistentAdminNoticeManager__registerNotices',
183
-            $this->notice_collection
184
-        );
185
-    }
186
-
187
-
188
-    /**
189
-     * @throws DomainException
190
-     * @throws InvalidClassException
191
-     * @throws InvalidInterfaceException
192
-     * @throws InvalidEntityException
193
-     * @throws DuplicateCollectionIdentifierException
194
-     */
195
-    public function displayNotices()
196
-    {
197
-        $this->notice_collection = $this->getPersistentAdminNoticeCollection();
198
-        if ($this->notice_collection->hasObjects()) {
199
-            $enqueue_assets = false;
200
-            // and display notices
201
-            foreach ($this->notice_collection as $persistent_admin_notice) {
202
-                /** @var PersistentAdminNotice $persistent_admin_notice */
203
-                // don't display notices that have already been dismissed
204
-                if ($persistent_admin_notice->getDismissed()) {
205
-                    continue;
206
-                }
207
-                try {
208
-                    $this->capabilities_checker->processCapCheck(
209
-                        $persistent_admin_notice->getCapCheck()
210
-                    );
211
-                } catch (InsufficientPermissionsException $e) {
212
-                    // user does not have required cap, so skip to next notice
213
-                    // and just eat the exception - nom nom nom nom
214
-                    continue;
215
-                }
216
-                if ($persistent_admin_notice->getMessage() === '') {
217
-                    continue;
218
-                }
219
-                $this->displayPersistentAdminNotice($persistent_admin_notice);
220
-                $enqueue_assets = true;
221
-            }
222
-            if ($enqueue_assets) {
223
-                $this->enqueueAssets();
224
-            }
225
-        }
226
-    }
227
-
228
-
229
-    /**
230
-     * does what it's named
231
-     *
232
-     * @return void
233
-     */
234
-    public function enqueueAssets()
235
-    {
236
-        wp_register_script(
237
-            'espresso_core',
238
-            EE_GLOBAL_ASSETS_URL . 'scripts/espresso_core.js',
239
-            array('jquery'),
240
-            EVENT_ESPRESSO_VERSION,
241
-            true
242
-        );
243
-        wp_register_script(
244
-            'ee_error_js',
245
-            EE_GLOBAL_ASSETS_URL . 'scripts/EE_Error.js',
246
-            array('espresso_core'),
247
-            EVENT_ESPRESSO_VERSION,
248
-            true
249
-        );
250
-        wp_localize_script(
251
-            'ee_error_js',
252
-            'ee_dismiss',
253
-            array(
254
-                'return_url'    => urlencode($this->return_url),
255
-                'ajax_url'      => WP_AJAX_URL,
256
-                'unknown_error' => wp_strip_all_tags(
257
-                    __(
258
-                        'An unknown error has occurred on the server while attempting to dismiss this notice.',
259
-                        'event_espresso'
260
-                    )
261
-                ),
262
-            )
263
-        );
264
-        wp_enqueue_script('ee_error_js');
265
-    }
266
-
267
-
268
-    /**
269
-     * displayPersistentAdminNoticeHtml
270
-     *
271
-     * @param  PersistentAdminNotice $persistent_admin_notice
272
-     */
273
-    protected function displayPersistentAdminNotice(PersistentAdminNotice $persistent_admin_notice)
274
-    {
275
-        // used in template
276
-        $persistent_admin_notice_name = $persistent_admin_notice->getName();
277
-        $persistent_admin_notice_message = $persistent_admin_notice->getMessage();
278
-        require EE_TEMPLATES . '/notifications/persistent_admin_notice.template.php';
279
-    }
280
-
281
-
282
-    /**
283
-     * dismissNotice
284
-     *
285
-     * @param string $pan_name the name, or key of the Persistent Admin Notice to be dismissed
286
-     * @param bool   $purge    if true, then delete it from the db
287
-     * @param bool   $return   forget all of this AJAX or redirect nonsense, and just return
288
-     * @return void
289
-     * @throws InvalidEntityException
290
-     * @throws InvalidInterfaceException
291
-     * @throws DomainException
292
-     * @throws InvalidArgumentException
293
-     * @throws InvalidArgumentException
294
-     * @throws InvalidArgumentException
295
-     * @throws InvalidArgumentException
296
-     * @throws DuplicateCollectionIdentifierException
297
-     */
298
-    public function dismissNotice(string $pan_name = '', bool $purge = false, bool $return = false)
299
-    {
300
-        $pan_name = $this->request->getRequestParam('ee_nag_notice', $pan_name);
301
-        $this->notice_collection = $this->getPersistentAdminNoticeCollection();
302
-        if (! empty($pan_name) && $this->notice_collection->has($pan_name)) {
303
-            /** @var PersistentAdminNotice $persistent_admin_notice */
304
-            $persistent_admin_notice = $this->notice_collection->get($pan_name);
305
-            $persistent_admin_notice->setDismissed(true);
306
-            $persistent_admin_notice->setPurge($purge);
307
-            $this->saveNotices();
308
-        }
309
-        if ($return) {
310
-            return;
311
-        }
312
-        if ($this->request->isAjax()) {
313
-            // grab any notices and concatenate into string
314
-            echo wp_json_encode(
315
-                array(
316
-                    'errors' => implode('<br />', EE_Error::get_notices(false)),
317
-                )
318
-            );
319
-            exit();
320
-        }
321
-        // save errors to a transient to be displayed on next request (after redirect)
322
-        EE_Error::get_notices(false, true);
323
-        wp_safe_redirect(
324
-            urldecode(
325
-                $this->request->getRequestParam('return_url', '')
326
-            )
327
-        );
328
-    }
329
-
330
-
331
-    /**
332
-     * saveNotices
333
-     *
334
-     * @throws DomainException
335
-     * @throws InvalidInterfaceException
336
-     * @throws InvalidEntityException
337
-     * @throws DuplicateCollectionIdentifierException
338
-     */
339
-    public function saveNotices()
340
-    {
341
-        $this->notice_collection = $this->getPersistentAdminNoticeCollection();
342
-        if ($this->notice_collection->hasObjects()) {
343
-            $persistent_admin_notices = get_option(PersistentAdminNoticeManager::WP_OPTION_KEY, array());
344
-            // maybe initialize persistent_admin_notices
345
-            if (empty($persistent_admin_notices)) {
346
-                add_option(PersistentAdminNoticeManager::WP_OPTION_KEY, array(), '', 'no');
347
-            }
348
-            $new_notices_array = [];
349
-            foreach ($this->notice_collection as $persistent_admin_notice) {
350
-                // remove this notice ?
351
-                if ($persistent_admin_notice->getPurge()) {
352
-                    continue;
353
-                }
354
-                /** @var PersistentAdminNotice $persistent_admin_notice */
355
-                $new_notices_array[ $persistent_admin_notice->getName() ] = array(
356
-                    'message'     => $persistent_admin_notice->getMessage(),
357
-                    'capability'  => $persistent_admin_notice->getCapability(),
358
-                    'cap_context' => $persistent_admin_notice->getCapContext(),
359
-                    'dismissed'   => $persistent_admin_notice->getDismissed(),
360
-                );
361
-            }
362
-            update_option(PersistentAdminNoticeManager::WP_OPTION_KEY, $new_notices_array);
363
-        }
364
-    }
365
-
366
-
367
-    /**
368
-     * @throws DomainException
369
-     * @throws InvalidEntityException
370
-     * @throws InvalidInterfaceException
371
-     * @throws DuplicateCollectionIdentifierException
372
-     */
373
-    public function registerAndSaveNotices()
374
-    {
375
-        $this->getPersistentAdminNoticeCollection();
376
-        $this->registerNotices();
377
-        $this->saveNotices();
378
-        add_filter(
379
-            'PersistentAdminNoticeManager__registerAndSaveNotices__complete',
380
-            '__return_true'
381
-        );
382
-    }
383
-
384
-
385
-    /**
386
-     * @throws DomainException
387
-     * @throws InvalidEntityException
388
-     * @throws InvalidInterfaceException
389
-     * @throws InvalidArgumentException
390
-     * @throws DuplicateCollectionIdentifierException
391
-     */
392
-    public static function loadRegisterAndSaveNotices()
393
-    {
394
-        /** @var PersistentAdminNoticeManager $persistent_admin_notice_manager */
395
-        $persistent_admin_notice_manager = LoaderFactory::getLoader()->getShared(
396
-            'EventEspresso\core\services\notifications\PersistentAdminNoticeManager'
397
-        );
398
-        // if shutdown has already run, then call registerAndSaveNotices() manually
399
-        if (did_action('shutdown')) {
400
-            $persistent_admin_notice_manager->registerAndSaveNotices();
401
-        }
402
-    }
32
+	const WP_OPTION_KEY = 'ee_pers_admin_notices';
33
+
34
+	private CapabilitiesChecker $capabilities_checker;
35
+
36
+	private RequestInterface $request;
37
+
38
+	/**
39
+	 * @var Collection|PersistentAdminNotice[]|null $notice_collection
40
+	 */
41
+	private ?Collection $notice_collection = null;
42
+
43
+	/**
44
+	 * if AJAX is not enabled, then the return URL will be used for redirecting back to the admin page where the
45
+	 * persistent admin notice was displayed, and ultimately dismissed from.
46
+	 *
47
+	 * @var string $return_url
48
+	 */
49
+	private string $return_url;
50
+
51
+
52
+
53
+	/**
54
+	 * PersistentAdminNoticeManager constructor
55
+	 *
56
+	 * @param CapabilitiesChecker $capabilities_checker
57
+	 * @param RequestInterface    $request
58
+	 * @param string              $return_url where to  redirect to after dismissing notices
59
+	 */
60
+	public function __construct(
61
+		CapabilitiesChecker $capabilities_checker,
62
+		RequestInterface $request,
63
+		string $return_url = ''
64
+	) {
65
+		$this->capabilities_checker = $capabilities_checker;
66
+		$this->request = $request;
67
+		$this->setReturnUrl($return_url);
68
+		// setup up notices at priority 9 because `EE_Admin::display_admin_notices()` runs at priority 10,
69
+		// and we want to retrieve and generate any nag notices at the last possible moment
70
+		add_action('admin_notices', array($this, 'displayNotices'), 9);
71
+		add_action('network_admin_notices', array($this, 'displayNotices'), 9);
72
+		add_action('wp_ajax_dismiss_ee_nag_notice', array($this, 'dismissNotice'));
73
+		add_action('shutdown', array($this, 'registerAndSaveNotices'), 998);
74
+	}
75
+
76
+
77
+	/**
78
+	 * @param string $return_url
79
+	 */
80
+	public function setReturnUrl(string $return_url)
81
+	{
82
+		$this->return_url = $return_url;
83
+	}
84
+
85
+
86
+	/**
87
+	 * @return Collection
88
+	 * @throws InvalidEntityException
89
+	 * @throws InvalidInterfaceException
90
+	 * @throws DomainException
91
+	 * @throws DuplicateCollectionIdentifierException
92
+	 */
93
+	protected function getPersistentAdminNoticeCollection(): Collection
94
+	{
95
+		if (! $this->notice_collection instanceof Collection) {
96
+			$this->notice_collection = new Collection(
97
+				'EventEspresso\core\domain\entities\notifications\PersistentAdminNotice'
98
+			);
99
+			$this->retrieveStoredNotices();
100
+			$this->registerNotices();
101
+		}
102
+		return $this->notice_collection;
103
+	}
104
+
105
+
106
+	/**
107
+	 * generates PersistentAdminNotice objects for all non-dismissed notices saved to the db
108
+	 *
109
+	 * @return void
110
+	 * @throws InvalidEntityException
111
+	 * @throws DomainException
112
+	 * @throws DuplicateCollectionIdentifierException
113
+	 */
114
+	protected function retrieveStoredNotices()
115
+	{
116
+		$persistent_admin_notices = get_option(PersistentAdminNoticeManager::WP_OPTION_KEY, array());
117
+		if (! empty($persistent_admin_notices)) {
118
+			foreach ($persistent_admin_notices as $name => $details) {
119
+				if (is_array($details)) {
120
+					if (
121
+						! isset(
122
+							$details['message'],
123
+							$details['capability'],
124
+							$details['cap_context'],
125
+							$details['dismissed']
126
+						)
127
+					) {
128
+						throw new DomainException(
129
+							sprintf(
130
+								esc_html__(
131
+									'The "%1$s" PersistentAdminNotice could not be retrieved from the database.',
132
+									'event_espresso'
133
+								),
134
+								$name
135
+							)
136
+						);
137
+					}
138
+					// new format for nag notices
139
+					$this->notice_collection->add(
140
+						new PersistentAdminNotice(
141
+							(string) $name,
142
+							(string) $details['message'],
143
+							false,
144
+							(string) $details['capability'],
145
+							(string) $details['cap_context'],
146
+							(bool) $details['dismissed']
147
+						),
148
+						sanitize_key($name)
149
+					);
150
+				} else {
151
+					try {
152
+						// old nag notices, that we want to convert to the new format
153
+						$this->notice_collection->add(
154
+							new PersistentAdminNotice(
155
+								(string) $name,
156
+								(string) $details,
157
+								false,
158
+								'',
159
+								'',
160
+								empty($details)
161
+							),
162
+							sanitize_key($name)
163
+						);
164
+					} catch (Exception $e) {
165
+						EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__);
166
+					}
167
+				}
168
+				// each notice will self register when the action hook in registerNotices is triggered
169
+			}
170
+		}
171
+	}
172
+
173
+
174
+	/**
175
+	 * exposes the Persistent Admin Notice Collection via an action
176
+	 * so that PersistentAdminNotice objects can be added and/or removed
177
+	 * without compromising the actual collection like a filter would
178
+	 */
179
+	protected function registerNotices()
180
+	{
181
+		do_action(
182
+			'AHEE__EventEspresso_core_services_notifications_PersistentAdminNoticeManager__registerNotices',
183
+			$this->notice_collection
184
+		);
185
+	}
186
+
187
+
188
+	/**
189
+	 * @throws DomainException
190
+	 * @throws InvalidClassException
191
+	 * @throws InvalidInterfaceException
192
+	 * @throws InvalidEntityException
193
+	 * @throws DuplicateCollectionIdentifierException
194
+	 */
195
+	public function displayNotices()
196
+	{
197
+		$this->notice_collection = $this->getPersistentAdminNoticeCollection();
198
+		if ($this->notice_collection->hasObjects()) {
199
+			$enqueue_assets = false;
200
+			// and display notices
201
+			foreach ($this->notice_collection as $persistent_admin_notice) {
202
+				/** @var PersistentAdminNotice $persistent_admin_notice */
203
+				// don't display notices that have already been dismissed
204
+				if ($persistent_admin_notice->getDismissed()) {
205
+					continue;
206
+				}
207
+				try {
208
+					$this->capabilities_checker->processCapCheck(
209
+						$persistent_admin_notice->getCapCheck()
210
+					);
211
+				} catch (InsufficientPermissionsException $e) {
212
+					// user does not have required cap, so skip to next notice
213
+					// and just eat the exception - nom nom nom nom
214
+					continue;
215
+				}
216
+				if ($persistent_admin_notice->getMessage() === '') {
217
+					continue;
218
+				}
219
+				$this->displayPersistentAdminNotice($persistent_admin_notice);
220
+				$enqueue_assets = true;
221
+			}
222
+			if ($enqueue_assets) {
223
+				$this->enqueueAssets();
224
+			}
225
+		}
226
+	}
227
+
228
+
229
+	/**
230
+	 * does what it's named
231
+	 *
232
+	 * @return void
233
+	 */
234
+	public function enqueueAssets()
235
+	{
236
+		wp_register_script(
237
+			'espresso_core',
238
+			EE_GLOBAL_ASSETS_URL . 'scripts/espresso_core.js',
239
+			array('jquery'),
240
+			EVENT_ESPRESSO_VERSION,
241
+			true
242
+		);
243
+		wp_register_script(
244
+			'ee_error_js',
245
+			EE_GLOBAL_ASSETS_URL . 'scripts/EE_Error.js',
246
+			array('espresso_core'),
247
+			EVENT_ESPRESSO_VERSION,
248
+			true
249
+		);
250
+		wp_localize_script(
251
+			'ee_error_js',
252
+			'ee_dismiss',
253
+			array(
254
+				'return_url'    => urlencode($this->return_url),
255
+				'ajax_url'      => WP_AJAX_URL,
256
+				'unknown_error' => wp_strip_all_tags(
257
+					__(
258
+						'An unknown error has occurred on the server while attempting to dismiss this notice.',
259
+						'event_espresso'
260
+					)
261
+				),
262
+			)
263
+		);
264
+		wp_enqueue_script('ee_error_js');
265
+	}
266
+
267
+
268
+	/**
269
+	 * displayPersistentAdminNoticeHtml
270
+	 *
271
+	 * @param  PersistentAdminNotice $persistent_admin_notice
272
+	 */
273
+	protected function displayPersistentAdminNotice(PersistentAdminNotice $persistent_admin_notice)
274
+	{
275
+		// used in template
276
+		$persistent_admin_notice_name = $persistent_admin_notice->getName();
277
+		$persistent_admin_notice_message = $persistent_admin_notice->getMessage();
278
+		require EE_TEMPLATES . '/notifications/persistent_admin_notice.template.php';
279
+	}
280
+
281
+
282
+	/**
283
+	 * dismissNotice
284
+	 *
285
+	 * @param string $pan_name the name, or key of the Persistent Admin Notice to be dismissed
286
+	 * @param bool   $purge    if true, then delete it from the db
287
+	 * @param bool   $return   forget all of this AJAX or redirect nonsense, and just return
288
+	 * @return void
289
+	 * @throws InvalidEntityException
290
+	 * @throws InvalidInterfaceException
291
+	 * @throws DomainException
292
+	 * @throws InvalidArgumentException
293
+	 * @throws InvalidArgumentException
294
+	 * @throws InvalidArgumentException
295
+	 * @throws InvalidArgumentException
296
+	 * @throws DuplicateCollectionIdentifierException
297
+	 */
298
+	public function dismissNotice(string $pan_name = '', bool $purge = false, bool $return = false)
299
+	{
300
+		$pan_name = $this->request->getRequestParam('ee_nag_notice', $pan_name);
301
+		$this->notice_collection = $this->getPersistentAdminNoticeCollection();
302
+		if (! empty($pan_name) && $this->notice_collection->has($pan_name)) {
303
+			/** @var PersistentAdminNotice $persistent_admin_notice */
304
+			$persistent_admin_notice = $this->notice_collection->get($pan_name);
305
+			$persistent_admin_notice->setDismissed(true);
306
+			$persistent_admin_notice->setPurge($purge);
307
+			$this->saveNotices();
308
+		}
309
+		if ($return) {
310
+			return;
311
+		}
312
+		if ($this->request->isAjax()) {
313
+			// grab any notices and concatenate into string
314
+			echo wp_json_encode(
315
+				array(
316
+					'errors' => implode('<br />', EE_Error::get_notices(false)),
317
+				)
318
+			);
319
+			exit();
320
+		}
321
+		// save errors to a transient to be displayed on next request (after redirect)
322
+		EE_Error::get_notices(false, true);
323
+		wp_safe_redirect(
324
+			urldecode(
325
+				$this->request->getRequestParam('return_url', '')
326
+			)
327
+		);
328
+	}
329
+
330
+
331
+	/**
332
+	 * saveNotices
333
+	 *
334
+	 * @throws DomainException
335
+	 * @throws InvalidInterfaceException
336
+	 * @throws InvalidEntityException
337
+	 * @throws DuplicateCollectionIdentifierException
338
+	 */
339
+	public function saveNotices()
340
+	{
341
+		$this->notice_collection = $this->getPersistentAdminNoticeCollection();
342
+		if ($this->notice_collection->hasObjects()) {
343
+			$persistent_admin_notices = get_option(PersistentAdminNoticeManager::WP_OPTION_KEY, array());
344
+			// maybe initialize persistent_admin_notices
345
+			if (empty($persistent_admin_notices)) {
346
+				add_option(PersistentAdminNoticeManager::WP_OPTION_KEY, array(), '', 'no');
347
+			}
348
+			$new_notices_array = [];
349
+			foreach ($this->notice_collection as $persistent_admin_notice) {
350
+				// remove this notice ?
351
+				if ($persistent_admin_notice->getPurge()) {
352
+					continue;
353
+				}
354
+				/** @var PersistentAdminNotice $persistent_admin_notice */
355
+				$new_notices_array[ $persistent_admin_notice->getName() ] = array(
356
+					'message'     => $persistent_admin_notice->getMessage(),
357
+					'capability'  => $persistent_admin_notice->getCapability(),
358
+					'cap_context' => $persistent_admin_notice->getCapContext(),
359
+					'dismissed'   => $persistent_admin_notice->getDismissed(),
360
+				);
361
+			}
362
+			update_option(PersistentAdminNoticeManager::WP_OPTION_KEY, $new_notices_array);
363
+		}
364
+	}
365
+
366
+
367
+	/**
368
+	 * @throws DomainException
369
+	 * @throws InvalidEntityException
370
+	 * @throws InvalidInterfaceException
371
+	 * @throws DuplicateCollectionIdentifierException
372
+	 */
373
+	public function registerAndSaveNotices()
374
+	{
375
+		$this->getPersistentAdminNoticeCollection();
376
+		$this->registerNotices();
377
+		$this->saveNotices();
378
+		add_filter(
379
+			'PersistentAdminNoticeManager__registerAndSaveNotices__complete',
380
+			'__return_true'
381
+		);
382
+	}
383
+
384
+
385
+	/**
386
+	 * @throws DomainException
387
+	 * @throws InvalidEntityException
388
+	 * @throws InvalidInterfaceException
389
+	 * @throws InvalidArgumentException
390
+	 * @throws DuplicateCollectionIdentifierException
391
+	 */
392
+	public static function loadRegisterAndSaveNotices()
393
+	{
394
+		/** @var PersistentAdminNoticeManager $persistent_admin_notice_manager */
395
+		$persistent_admin_notice_manager = LoaderFactory::getLoader()->getShared(
396
+			'EventEspresso\core\services\notifications\PersistentAdminNoticeManager'
397
+		);
398
+		// if shutdown has already run, then call registerAndSaveNotices() manually
399
+		if (did_action('shutdown')) {
400
+			$persistent_admin_notice_manager->registerAndSaveNotices();
401
+		}
402
+	}
403 403
 }
Please login to merge, or discard this patch.
Spacing   +7 added lines, -7 removed lines patch added patch discarded remove patch
@@ -92,7 +92,7 @@  discard block
 block discarded – undo
92 92
      */
93 93
     protected function getPersistentAdminNoticeCollection(): Collection
94 94
     {
95
-        if (! $this->notice_collection instanceof Collection) {
95
+        if ( ! $this->notice_collection instanceof Collection) {
96 96
             $this->notice_collection = new Collection(
97 97
                 'EventEspresso\core\domain\entities\notifications\PersistentAdminNotice'
98 98
             );
@@ -114,7 +114,7 @@  discard block
 block discarded – undo
114 114
     protected function retrieveStoredNotices()
115 115
     {
116 116
         $persistent_admin_notices = get_option(PersistentAdminNoticeManager::WP_OPTION_KEY, array());
117
-        if (! empty($persistent_admin_notices)) {
117
+        if ( ! empty($persistent_admin_notices)) {
118 118
             foreach ($persistent_admin_notices as $name => $details) {
119 119
                 if (is_array($details)) {
120 120
                     if (
@@ -235,14 +235,14 @@  discard block
 block discarded – undo
235 235
     {
236 236
         wp_register_script(
237 237
             'espresso_core',
238
-            EE_GLOBAL_ASSETS_URL . 'scripts/espresso_core.js',
238
+            EE_GLOBAL_ASSETS_URL.'scripts/espresso_core.js',
239 239
             array('jquery'),
240 240
             EVENT_ESPRESSO_VERSION,
241 241
             true
242 242
         );
243 243
         wp_register_script(
244 244
             'ee_error_js',
245
-            EE_GLOBAL_ASSETS_URL . 'scripts/EE_Error.js',
245
+            EE_GLOBAL_ASSETS_URL.'scripts/EE_Error.js',
246 246
             array('espresso_core'),
247 247
             EVENT_ESPRESSO_VERSION,
248 248
             true
@@ -275,7 +275,7 @@  discard block
 block discarded – undo
275 275
         // used in template
276 276
         $persistent_admin_notice_name = $persistent_admin_notice->getName();
277 277
         $persistent_admin_notice_message = $persistent_admin_notice->getMessage();
278
-        require EE_TEMPLATES . '/notifications/persistent_admin_notice.template.php';
278
+        require EE_TEMPLATES.'/notifications/persistent_admin_notice.template.php';
279 279
     }
280 280
 
281 281
 
@@ -299,7 +299,7 @@  discard block
 block discarded – undo
299 299
     {
300 300
         $pan_name = $this->request->getRequestParam('ee_nag_notice', $pan_name);
301 301
         $this->notice_collection = $this->getPersistentAdminNoticeCollection();
302
-        if (! empty($pan_name) && $this->notice_collection->has($pan_name)) {
302
+        if ( ! empty($pan_name) && $this->notice_collection->has($pan_name)) {
303 303
             /** @var PersistentAdminNotice $persistent_admin_notice */
304 304
             $persistent_admin_notice = $this->notice_collection->get($pan_name);
305 305
             $persistent_admin_notice->setDismissed(true);
@@ -352,7 +352,7 @@  discard block
 block discarded – undo
352 352
                     continue;
353 353
                 }
354 354
                 /** @var PersistentAdminNotice $persistent_admin_notice */
355
-                $new_notices_array[ $persistent_admin_notice->getName() ] = array(
355
+                $new_notices_array[$persistent_admin_notice->getName()] = array(
356 356
                     'message'     => $persistent_admin_notice->getMessage(),
357 357
                     'capability'  => $persistent_admin_notice->getCapability(),
358 358
                     'cap_context' => $persistent_admin_notice->getCapContext(),
Please login to merge, or discard this patch.
core/services/database/OptionEngine.php 1 patch
Indentation   +54 added lines, -54 removed lines patch added patch discarded remove patch
@@ -12,69 +12,69 @@
 block discarded – undo
12 12
  */
13 13
 class OptionEngine
14 14
 {
15
-    private bool $is_network_option;
15
+	private bool $is_network_option;
16 16
 
17
-    private int $network_ID;
17
+	private int $network_ID;
18 18
 
19 19
 
20
-    /**
21
-     * @param bool $is_network_option
22
-     */
23
-    public function __construct(bool $is_network_option = false)
24
-    {
25
-        $this->is_network_option = $is_network_option;
26
-        $this->network_ID        = get_current_network_id();
27
-    }
20
+	/**
21
+	 * @param bool $is_network_option
22
+	 */
23
+	public function __construct(bool $is_network_option = false)
24
+	{
25
+		$this->is_network_option = $is_network_option;
26
+		$this->network_ID        = get_current_network_id();
27
+	}
28 28
 
29 29
 
30
-    /**
31
-     * @param string $option_name
32
-     * @param mixed  $default_value
33
-     * @return false|mixed|void
34
-     */
35
-    public function getOption(string $option_name, $default_value)
36
-    {
37
-        return $this->is_network_option
38
-            ? get_network_option($this->network_ID, $option_name, $default_value)
39
-            : get_option($option_name, $default_value);
40
-    }
30
+	/**
31
+	 * @param string $option_name
32
+	 * @param mixed  $default_value
33
+	 * @return false|mixed|void
34
+	 */
35
+	public function getOption(string $option_name, $default_value)
36
+	{
37
+		return $this->is_network_option
38
+			? get_network_option($this->network_ID, $option_name, $default_value)
39
+			: get_option($option_name, $default_value);
40
+	}
41 41
 
42 42
 
43
-    /**
44
-     * @param string $option_name
45
-     * @param mixed  $value
46
-     * @param string $autoload
47
-     * @return bool
48
-     */
49
-    public function addOption(string $option_name, $value, string $autoload): bool
50
-    {
51
-        return $this->is_network_option
52
-            ? add_network_option($this->network_ID, $option_name, $value)
53
-            : add_option($option_name, $value, '', $autoload);
54
-    }
43
+	/**
44
+	 * @param string $option_name
45
+	 * @param mixed  $value
46
+	 * @param string $autoload
47
+	 * @return bool
48
+	 */
49
+	public function addOption(string $option_name, $value, string $autoload): bool
50
+	{
51
+		return $this->is_network_option
52
+			? add_network_option($this->network_ID, $option_name, $value)
53
+			: add_option($option_name, $value, '', $autoload);
54
+	}
55 55
 
56 56
 
57
-    /**
58
-     * @param string $option_name
59
-     * @param mixed  $value
60
-     * @return bool
61
-     */
62
-    public function updateOption(string $option_name, $value): bool
63
-    {
64
-        return $this->is_network_option
65
-            ? update_network_option($this->network_ID, $option_name, $value)
66
-            : update_option($option_name, $value);
67
-    }
57
+	/**
58
+	 * @param string $option_name
59
+	 * @param mixed  $value
60
+	 * @return bool
61
+	 */
62
+	public function updateOption(string $option_name, $value): bool
63
+	{
64
+		return $this->is_network_option
65
+			? update_network_option($this->network_ID, $option_name, $value)
66
+			: update_option($option_name, $value);
67
+	}
68 68
 
69 69
 
70
-    /**
71
-     * @param string $option_name
72
-     * @return bool
73
-     */
74
-    public function deleteOption(string $option_name): bool
75
-    {
76
-        return $this->is_network_option
77
-            ? delete_network_option($this->network_ID, $option_name)
78
-            : delete_option($option_name);
79
-    }
70
+	/**
71
+	 * @param string $option_name
72
+	 * @return bool
73
+	 */
74
+	public function deleteOption(string $option_name): bool
75
+	{
76
+		return $this->is_network_option
77
+			? delete_network_option($this->network_ID, $option_name)
78
+			: delete_option($option_name);
79
+	}
80 80
 }
Please login to merge, or discard this patch.
core/services/database/WordPressOption.php 1 patch
Indentation   +168 added lines, -168 removed lines patch added patch discarded remove patch
@@ -17,172 +17,172 @@
 block discarded – undo
17 17
  */
18 18
 abstract class WordPressOption
19 19
 {
20
-    public const NOT_SET_YET = 'wordpress-option-value-not-yet-set';
21
-
22
-    /**
23
-     * WordPress makes it difficult to determine if an option successfully saved or not,
24
-     * which is sometimes really important to know, especially if the information you are saving is critical.
25
-     * The following options allow us to have a better chance of knowing when an update actually failed
26
-     * or when everything is OK but it just didn't update because the value hasn't changed.
27
-     */
28
-    public const UPDATE_SUCCESS = 1;
29
-
30
-    public const UPDATE_NONE    = 0;
31
-
32
-    public const UPDATE_ERROR   = -1;
33
-
34
-    private bool $autoload = false;
35
-
36
-    /**
37
-     * @var mixed
38
-     */
39
-    private $default_value = null;
40
-
41
-    private string $option_name = '';
42
-
43
-    /**
44
-     * @var mixed
45
-     */
46
-    private $value = WordPressOption::NOT_SET_YET;
47
-
48
-    private OptionEngine $option_engine;
49
-
50
-
51
-    /**
52
-     * WordPressOption constructor.
53
-     *
54
-     * @param string $option_name
55
-     * @param mixed  $default_value
56
-     * @param bool   $autoload          if true, will load the option on EVERY request
57
-     * @param bool   $is_network_option if true, will save the option to the network as opposed to the current blog
58
-     */
59
-    public function __construct(
60
-        string $option_name,
61
-        $default_value,
62
-        bool $autoload = false,
63
-        bool $is_network_option = false
64
-    ) {
65
-        $this->setAutoload($autoload);
66
-        $this->setDefaultValue($default_value);
67
-        $this->setOptionName($option_name);
68
-        $this->option_engine = new OptionEngine($is_network_option);
69
-    }
70
-
71
-
72
-    /**
73
-     * @param bool|string $autoload
74
-     */
75
-    public function setAutoload($autoload): void
76
-    {
77
-        $this->autoload = filter_var($autoload, FILTER_VALIDATE_BOOLEAN);
78
-    }
79
-
80
-
81
-    /**
82
-     * @param mixed $default_value
83
-     */
84
-    public function setDefaultValue($default_value): void
85
-    {
86
-        $this->default_value = $default_value;
87
-    }
88
-
89
-
90
-    /**
91
-     * @param string $option_name
92
-     */
93
-    public function setOptionName(string $option_name): void
94
-    {
95
-        $this->option_name = sanitize_key($option_name);
96
-    }
97
-
98
-
99
-    /**
100
-     * @return string
101
-     */
102
-    public function optionExists(): string
103
-    {
104
-        return $this->option_engine->getOption(
105
-            $this->getOptionName(),
106
-            WordPressOption::NOT_SET_YET
107
-        ) !== WordPressOption::NOT_SET_YET;
108
-    }
109
-
110
-
111
-    /**
112
-     * @return string
113
-     */
114
-    public function getOptionName(): string
115
-    {
116
-        return $this->option_name;
117
-    }
118
-
119
-
120
-    /**
121
-     * @return false|mixed|void
122
-     */
123
-    public function loadOption()
124
-    {
125
-        if ($this->value === WordPressOption::NOT_SET_YET) {
126
-            $this->value = $this->option_engine->getOption($this->getOptionName(), $this->default_value);
127
-        }
128
-        return $this->value;
129
-    }
130
-
131
-
132
-    /**
133
-     * @param $value
134
-     * @return int
135
-     */
136
-    public function updateOption($value): int
137
-    {
138
-        // don't update if value has not changed since last update
139
-        if ($this->valueIsUnchanged($value)) {
140
-            return WordPressOption::UPDATE_NONE;
141
-        }
142
-        $this->value = $value;
143
-        // because the options for updating differ when adding an option for the first time
144
-        // we use the WordPressOption::NOT_SET_YET to determine if things already exist in the db
145
-        $updated = $this->optionExists()
146
-            ? $this->option_engine->updateOption($this->getOptionName(), $this->value)
147
-            : $this->option_engine->addOption($this->getOptionName(), $this->value, $this->autoload());
148
-
149
-        if ($updated) {
150
-            return WordPressOption::UPDATE_SUCCESS;
151
-        }
152
-        return WordPressOption::UPDATE_ERROR;
153
-    }
154
-
155
-
156
-    private function valueIsUnchanged($value): bool
157
-    {
158
-        if (is_array($value) && is_array($this->value)) {
159
-            $diff = EEH_Array::array_diff_recursive($value, $this->value);
160
-            // $diff = array_diff($value, $this->value);
161
-            return empty($diff);
162
-        }
163
-        // emulate WP's method for checking equality
164
-        return $value === $this->value && maybe_serialize($value) === maybe_serialize($this->value);
165
-    }
166
-
167
-
168
-    /**
169
-     * @return string
170
-     */
171
-    private function autoload(): string
172
-    {
173
-        return $this->autoload ? 'yes' : 'no';
174
-    }
175
-
176
-
177
-    /**
178
-     * Deletes the option from the database
179
-     * for the rest of the request
180
-     *
181
-     * @return bool
182
-     * @since  5.0.0.p
183
-     */
184
-    public function deleteOption(): bool
185
-    {
186
-        return $this->option_engine->deleteOption($this->getOptionName());
187
-    }
20
+	public const NOT_SET_YET = 'wordpress-option-value-not-yet-set';
21
+
22
+	/**
23
+	 * WordPress makes it difficult to determine if an option successfully saved or not,
24
+	 * which is sometimes really important to know, especially if the information you are saving is critical.
25
+	 * The following options allow us to have a better chance of knowing when an update actually failed
26
+	 * or when everything is OK but it just didn't update because the value hasn't changed.
27
+	 */
28
+	public const UPDATE_SUCCESS = 1;
29
+
30
+	public const UPDATE_NONE    = 0;
31
+
32
+	public const UPDATE_ERROR   = -1;
33
+
34
+	private bool $autoload = false;
35
+
36
+	/**
37
+	 * @var mixed
38
+	 */
39
+	private $default_value = null;
40
+
41
+	private string $option_name = '';
42
+
43
+	/**
44
+	 * @var mixed
45
+	 */
46
+	private $value = WordPressOption::NOT_SET_YET;
47
+
48
+	private OptionEngine $option_engine;
49
+
50
+
51
+	/**
52
+	 * WordPressOption constructor.
53
+	 *
54
+	 * @param string $option_name
55
+	 * @param mixed  $default_value
56
+	 * @param bool   $autoload          if true, will load the option on EVERY request
57
+	 * @param bool   $is_network_option if true, will save the option to the network as opposed to the current blog
58
+	 */
59
+	public function __construct(
60
+		string $option_name,
61
+		$default_value,
62
+		bool $autoload = false,
63
+		bool $is_network_option = false
64
+	) {
65
+		$this->setAutoload($autoload);
66
+		$this->setDefaultValue($default_value);
67
+		$this->setOptionName($option_name);
68
+		$this->option_engine = new OptionEngine($is_network_option);
69
+	}
70
+
71
+
72
+	/**
73
+	 * @param bool|string $autoload
74
+	 */
75
+	public function setAutoload($autoload): void
76
+	{
77
+		$this->autoload = filter_var($autoload, FILTER_VALIDATE_BOOLEAN);
78
+	}
79
+
80
+
81
+	/**
82
+	 * @param mixed $default_value
83
+	 */
84
+	public function setDefaultValue($default_value): void
85
+	{
86
+		$this->default_value = $default_value;
87
+	}
88
+
89
+
90
+	/**
91
+	 * @param string $option_name
92
+	 */
93
+	public function setOptionName(string $option_name): void
94
+	{
95
+		$this->option_name = sanitize_key($option_name);
96
+	}
97
+
98
+
99
+	/**
100
+	 * @return string
101
+	 */
102
+	public function optionExists(): string
103
+	{
104
+		return $this->option_engine->getOption(
105
+			$this->getOptionName(),
106
+			WordPressOption::NOT_SET_YET
107
+		) !== WordPressOption::NOT_SET_YET;
108
+	}
109
+
110
+
111
+	/**
112
+	 * @return string
113
+	 */
114
+	public function getOptionName(): string
115
+	{
116
+		return $this->option_name;
117
+	}
118
+
119
+
120
+	/**
121
+	 * @return false|mixed|void
122
+	 */
123
+	public function loadOption()
124
+	{
125
+		if ($this->value === WordPressOption::NOT_SET_YET) {
126
+			$this->value = $this->option_engine->getOption($this->getOptionName(), $this->default_value);
127
+		}
128
+		return $this->value;
129
+	}
130
+
131
+
132
+	/**
133
+	 * @param $value
134
+	 * @return int
135
+	 */
136
+	public function updateOption($value): int
137
+	{
138
+		// don't update if value has not changed since last update
139
+		if ($this->valueIsUnchanged($value)) {
140
+			return WordPressOption::UPDATE_NONE;
141
+		}
142
+		$this->value = $value;
143
+		// because the options for updating differ when adding an option for the first time
144
+		// we use the WordPressOption::NOT_SET_YET to determine if things already exist in the db
145
+		$updated = $this->optionExists()
146
+			? $this->option_engine->updateOption($this->getOptionName(), $this->value)
147
+			: $this->option_engine->addOption($this->getOptionName(), $this->value, $this->autoload());
148
+
149
+		if ($updated) {
150
+			return WordPressOption::UPDATE_SUCCESS;
151
+		}
152
+		return WordPressOption::UPDATE_ERROR;
153
+	}
154
+
155
+
156
+	private function valueIsUnchanged($value): bool
157
+	{
158
+		if (is_array($value) && is_array($this->value)) {
159
+			$diff = EEH_Array::array_diff_recursive($value, $this->value);
160
+			// $diff = array_diff($value, $this->value);
161
+			return empty($diff);
162
+		}
163
+		// emulate WP's method for checking equality
164
+		return $value === $this->value && maybe_serialize($value) === maybe_serialize($this->value);
165
+	}
166
+
167
+
168
+	/**
169
+	 * @return string
170
+	 */
171
+	private function autoload(): string
172
+	{
173
+		return $this->autoload ? 'yes' : 'no';
174
+	}
175
+
176
+
177
+	/**
178
+	 * Deletes the option from the database
179
+	 * for the rest of the request
180
+	 *
181
+	 * @return bool
182
+	 * @since  5.0.0.p
183
+	 */
184
+	public function deleteOption(): bool
185
+	{
186
+		return $this->option_engine->deleteOption($this->getOptionName());
187
+	}
188 188
 }
Please login to merge, or discard this patch.
core/db_classes/EE_Registration.class.php 1 patch
Indentation   +2558 added lines, -2558 removed lines patch added patch discarded remove patch
@@ -17,2562 +17,2562 @@
 block discarded – undo
17 17
  */
18 18
 class EE_Registration extends EE_Soft_Delete_Base_Class implements EEI_Registration, EEI_Admin_Links
19 19
 {
20
-    /**
21
-     * Used to reference when a registration has never been checked in.
22
-     *
23
-     * @deprecated use \EE_Checkin::status_checked_never instead
24
-     * @type int
25
-     */
26
-    const checkin_status_never = 2;
27
-
28
-    /**
29
-     * Used to reference when a registration has been checked in.
30
-     *
31
-     * @deprecated use \EE_Checkin::status_checked_in instead
32
-     * @type int
33
-     */
34
-    const checkin_status_in = 1;
35
-
36
-    /**
37
-     * Used to reference when a registration has been checked out.
38
-     *
39
-     * @deprecated use \EE_Checkin::status_checked_out instead
40
-     * @type int
41
-     */
42
-    const checkin_status_out = 0;
43
-
44
-    /**
45
-     * extra meta key for tracking reg status os trashed registrations
46
-     *
47
-     * @type string
48
-     */
49
-    const PRE_TRASH_REG_STATUS_KEY = 'pre_trash_registration_status';
50
-
51
-    /**
52
-     * extra meta key for tracking if registration has reserved ticket
53
-     *
54
-     * @type string
55
-     */
56
-    const HAS_RESERVED_TICKET_KEY = 'has_reserved_ticket';
57
-
58
-
59
-    /**
60
-     * @param array  $props_n_values          incoming values
61
-     * @param string $timezone                incoming timezone (if not set the timezone set for the website will be
62
-     *                                        used.)
63
-     * @param array  $date_formats            incoming date_formats in an array where the first value is the
64
-     *                                        date_format and the second value is the time format
65
-     * @return EE_Registration
66
-     * @throws EE_Error
67
-     * @throws InvalidArgumentException
68
-     * @throws InvalidDataTypeException
69
-     * @throws InvalidInterfaceException
70
-     * @throws ReflectionException
71
-     */
72
-    public static function new_instance($props_n_values = [], $timezone = '', $date_formats = [])
73
-    {
74
-        $has_object = parent::_check_for_object($props_n_values, __CLASS__, $timezone, $date_formats);
75
-        return $has_object
76
-            ?: new self($props_n_values, false, $timezone, $date_formats);
77
-    }
78
-
79
-
80
-    /**
81
-     * @param array  $props_n_values  incoming values from the database
82
-     * @param string $timezone        incoming timezone as set by the model.  If not set the timezone for
83
-     *                                the website will be used.
84
-     * @return EE_Registration
85
-     * @throws EE_Error
86
-     * @throws InvalidArgumentException
87
-     * @throws InvalidDataTypeException
88
-     * @throws InvalidInterfaceException
89
-     * @throws ReflectionException
90
-     */
91
-    public static function new_instance_from_db($props_n_values = [], $timezone = '')
92
-    {
93
-        return new self($props_n_values, true, $timezone);
94
-    }
95
-
96
-
97
-    /**
98
-     *        Set Event ID
99
-     *
100
-     * @param int $EVT_ID Event ID
101
-     * @throws DomainException
102
-     * @throws EE_Error
103
-     * @throws EntityNotFoundException
104
-     * @throws InvalidArgumentException
105
-     * @throws InvalidDataTypeException
106
-     * @throws InvalidInterfaceException
107
-     * @throws ReflectionException
108
-     * @throws RuntimeException
109
-     * @throws UnexpectedEntityException
110
-     */
111
-    public function set_event($EVT_ID = 0)
112
-    {
113
-        $this->set('EVT_ID', $EVT_ID);
114
-    }
115
-
116
-
117
-    /**
118
-     * Overrides parent set() method so that all calls to set( 'REG_code', $REG_code ) OR set( 'STS_ID', $STS_ID ) can
119
-     * be routed to internal methods
120
-     *
121
-     * @param string $field_name
122
-     * @param mixed  $field_value
123
-     * @param bool   $use_default
124
-     * @throws DomainException
125
-     * @throws EE_Error
126
-     * @throws EntityNotFoundException
127
-     * @throws InvalidArgumentException
128
-     * @throws InvalidDataTypeException
129
-     * @throws InvalidInterfaceException
130
-     * @throws ReflectionException
131
-     * @throws RuntimeException
132
-     * @throws UnexpectedEntityException
133
-     */
134
-    public function set($field_name, $field_value, $use_default = false)
135
-    {
136
-        switch ($field_name) {
137
-            case 'REG_code':
138
-                if (! empty($field_value) && ! $this->reg_code()) {
139
-                    $this->set_reg_code($field_value, $use_default);
140
-                }
141
-                break;
142
-            case 'STS_ID':
143
-                $this->set_status($field_value, $use_default);
144
-                break;
145
-            default:
146
-                parent::set($field_name, $field_value, $use_default);
147
-        }
148
-    }
149
-
150
-
151
-    /**
152
-     * Set Status ID
153
-     * updates the registration status and ALSO...
154
-     * calls reserve_registration_space() if the reg status changes TO approved from any other reg status
155
-     * calls release_registration_space() if the reg status changes FROM approved to any other reg status
156
-     *
157
-     * @param string                $new_STS_ID
158
-     * @param boolean               $use_default
159
-     * @param ContextInterface|null $context
160
-     * @return bool
161
-     * @throws DomainException
162
-     * @throws EE_Error
163
-     * @throws EntityNotFoundException
164
-     * @throws InvalidArgumentException
165
-     * @throws InvalidDataTypeException
166
-     * @throws InvalidInterfaceException
167
-     * @throws ReflectionException
168
-     * @throws RuntimeException
169
-     * @throws UnexpectedEntityException
170
-     */
171
-    public function set_status($new_STS_ID = null, $use_default = false, ContextInterface $context = null)
172
-    {
173
-        // get current REG_Status
174
-        $old_STS_ID = $this->status_ID();
175
-        // if status has changed
176
-        if (
177
-            $old_STS_ID !== $new_STS_ID // and that status has actually changed
178
-            && ! empty($old_STS_ID) // and that old status is actually set
179
-            && ! empty($new_STS_ID) // as well as the new status
180
-            && $this->ID() // ensure registration is in the db
181
-        ) {
182
-            // update internal status first
183
-            parent::set('STS_ID', $new_STS_ID, $use_default);
184
-            // THEN handle other changes that occur when reg status changes
185
-            // TO approved
186
-            if ($new_STS_ID === EEM_Registration::status_id_approved) {
187
-                // reserve a space by incrementing ticket and datetime sold values
188
-                $this->reserveRegistrationSpace();
189
-                do_action('AHEE__EE_Registration__set_status__to_approved', $this, $old_STS_ID, $new_STS_ID, $context);
190
-                // OR FROM  approved
191
-            } elseif ($old_STS_ID === EEM_Registration::status_id_approved) {
192
-                // release a space by decrementing ticket and datetime sold values
193
-                $this->releaseRegistrationSpace();
194
-                do_action(
195
-                    'AHEE__EE_Registration__set_status__from_approved',
196
-                    $this,
197
-                    $old_STS_ID,
198
-                    $new_STS_ID,
199
-                    $context
200
-                );
201
-            }
202
-            // update status
203
-            parent::set('STS_ID', $new_STS_ID, $use_default);
204
-            $this->updateIfCanceledOrReinstated($new_STS_ID, $old_STS_ID, $context);
205
-            if ($this->statusChangeUpdatesTransaction($context)) {
206
-                $this->updateTransactionAfterStatusChange();
207
-            }
208
-            do_action('AHEE__EE_Registration__set_status__after_update', $this, $old_STS_ID, $new_STS_ID, $context);
209
-            return true;
210
-        }
211
-        // even though the old value matches the new value, it's still good to
212
-        // allow the parent set method to have a say
213
-        parent::set('STS_ID', $new_STS_ID, $use_default);
214
-        return true;
215
-    }
216
-
217
-
218
-    /**
219
-     * update REGs and TXN when cancelled or declined registrations involved
220
-     *
221
-     * @param string                $new_STS_ID
222
-     * @param string                $old_STS_ID
223
-     * @param ContextInterface|null $context
224
-     * @throws EE_Error
225
-     * @throws InvalidArgumentException
226
-     * @throws InvalidDataTypeException
227
-     * @throws InvalidInterfaceException
228
-     * @throws ReflectionException
229
-     * @throws RuntimeException
230
-     */
231
-    private function updateIfCanceledOrReinstated($new_STS_ID, $old_STS_ID, ContextInterface $context = null)
232
-    {
233
-        // these reg statuses should not be considered in any calculations involving monies owing
234
-        $closed_reg_statuses = EEM_Registration::closed_reg_statuses();
235
-        // true if registration has been cancelled or declined
236
-        $this->updateIfCanceled(
237
-            $closed_reg_statuses,
238
-            $new_STS_ID,
239
-            $old_STS_ID,
240
-            $context
241
-        );
242
-        $this->updateIfReinstated(
243
-            $closed_reg_statuses,
244
-            $new_STS_ID,
245
-            $old_STS_ID,
246
-            $context
247
-        );
248
-    }
249
-
250
-
251
-    /**
252
-     * update REGs and TXN when cancelled or declined registrations involved
253
-     *
254
-     * @param array                 $closed_reg_statuses
255
-     * @param string                $new_STS_ID
256
-     * @param string                $old_STS_ID
257
-     * @param ContextInterface|null $context
258
-     * @throws EE_Error
259
-     * @throws InvalidArgumentException
260
-     * @throws InvalidDataTypeException
261
-     * @throws InvalidInterfaceException
262
-     * @throws ReflectionException
263
-     * @throws RuntimeException
264
-     */
265
-    private function updateIfCanceled(
266
-        array $closed_reg_statuses,
267
-        $new_STS_ID,
268
-        $old_STS_ID,
269
-        ContextInterface $context = null
270
-    ) {
271
-        // true if registration has been cancelled or declined
272
-        if (
273
-            in_array($new_STS_ID, $closed_reg_statuses, true)
274
-            && ! in_array($old_STS_ID, $closed_reg_statuses, true)
275
-        ) {
276
-            /** @type EE_Registration_Processor $registration_processor */
277
-            $registration_processor = EE_Registry::instance()->load_class('Registration_Processor');
278
-            /** @type EE_Transaction_Processor $transaction_processor */
279
-            $transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor');
280
-            // cancelled or declined registration
281
-            $registration_processor->update_registration_after_being_canceled_or_declined(
282
-                $this,
283
-                $closed_reg_statuses
284
-            );
285
-            $transaction_processor->update_transaction_after_canceled_or_declined_registration(
286
-                $this,
287
-                $closed_reg_statuses,
288
-                false
289
-            );
290
-            do_action(
291
-                'AHEE__EE_Registration__set_status__canceled_or_declined',
292
-                $this,
293
-                $old_STS_ID,
294
-                $new_STS_ID,
295
-                $context
296
-            );
297
-            return;
298
-        }
299
-    }
300
-
301
-
302
-    /**
303
-     * update REGs and TXN when cancelled or declined registrations involved
304
-     *
305
-     * @param array                 $closed_reg_statuses
306
-     * @param string                $new_STS_ID
307
-     * @param string                $old_STS_ID
308
-     * @param ContextInterface|null $context
309
-     * @throws EE_Error
310
-     * @throws InvalidArgumentException
311
-     * @throws InvalidDataTypeException
312
-     * @throws InvalidInterfaceException
313
-     * @throws ReflectionException
314
-     * @throws RuntimeException
315
-     */
316
-    private function updateIfReinstated(
317
-        array $closed_reg_statuses,
318
-        $new_STS_ID,
319
-        $old_STS_ID,
320
-        ContextInterface $context = null
321
-    ) {
322
-        // true if reinstating cancelled or declined registration
323
-        if (
324
-            in_array($old_STS_ID, $closed_reg_statuses, true)
325
-            && ! in_array($new_STS_ID, $closed_reg_statuses, true)
326
-        ) {
327
-            /** @type EE_Registration_Processor $registration_processor */
328
-            $registration_processor = EE_Registry::instance()->load_class('Registration_Processor');
329
-            /** @type EE_Transaction_Processor $transaction_processor */
330
-            $transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor');
331
-            // reinstating cancelled or declined registration
332
-            $registration_processor->update_canceled_or_declined_registration_after_being_reinstated(
333
-                $this,
334
-                $closed_reg_statuses
335
-            );
336
-            $transaction_processor->update_transaction_after_reinstating_canceled_registration(
337
-                $this,
338
-                $closed_reg_statuses,
339
-                false
340
-            );
341
-            do_action(
342
-                'AHEE__EE_Registration__set_status__after_reinstated',
343
-                $this,
344
-                $old_STS_ID,
345
-                $new_STS_ID,
346
-                $context
347
-            );
348
-        }
349
-    }
350
-
351
-
352
-    /**
353
-     * @param ContextInterface|null $context
354
-     * @return bool
355
-     */
356
-    private function statusChangeUpdatesTransaction(ContextInterface $context = null)
357
-    {
358
-        $contexts_that_do_not_update_transaction = (array) apply_filters(
359
-            'AHEE__EE_Registration__statusChangeUpdatesTransaction__contexts_that_do_not_update_transaction',
360
-            ['spco_reg_step_attendee_information_process_registrations'],
361
-            $context,
362
-            $this
363
-        );
364
-        return ! (
365
-            $context instanceof ContextInterface
366
-            && in_array($context->slug(), $contexts_that_do_not_update_transaction, true)
367
-        );
368
-    }
369
-
370
-
371
-    /**
372
-     * @throws EE_Error
373
-     * @throws EntityNotFoundException
374
-     * @throws InvalidArgumentException
375
-     * @throws InvalidDataTypeException
376
-     * @throws InvalidInterfaceException
377
-     * @throws ReflectionException
378
-     * @throws RuntimeException
379
-     */
380
-    private function updateTransactionAfterStatusChange()
381
-    {
382
-        /** @type EE_Transaction_Payments $transaction_payments */
383
-        $transaction_payments = EE_Registry::instance()->load_class('Transaction_Payments');
384
-        $transaction_payments->recalculate_transaction_total($this->transaction(), false);
385
-        $this->transaction()->update_status_based_on_total_paid();
386
-    }
387
-
388
-
389
-    /**
390
-     * get Status ID
391
-     *
392
-     * @throws EE_Error
393
-     * @throws InvalidArgumentException
394
-     * @throws InvalidDataTypeException
395
-     * @throws InvalidInterfaceException
396
-     * @throws ReflectionException
397
-     */
398
-    public function status_ID()
399
-    {
400
-        return $this->get('STS_ID');
401
-    }
402
-
403
-
404
-    /**
405
-     * Gets the ticket this registration is for
406
-     *
407
-     * @param boolean $include_archived whether to include archived tickets or not.
408
-     * @return EE_Ticket|EE_Base_Class
409
-     * @throws EE_Error
410
-     * @throws InvalidArgumentException
411
-     * @throws InvalidDataTypeException
412
-     * @throws InvalidInterfaceException
413
-     * @throws ReflectionException
414
-     */
415
-    public function ticket($include_archived = true)
416
-    {
417
-        $query_params = [];
418
-        if ($include_archived) {
419
-            $query_params['default_where_conditions'] = 'none';
420
-        }
421
-        return $this->get_first_related('Ticket', $query_params);
422
-    }
423
-
424
-
425
-    /**
426
-     * Gets the event this registration is for
427
-     *
428
-     * @return EE_Event
429
-     * @throws EE_Error
430
-     * @throws EntityNotFoundException
431
-     * @throws InvalidArgumentException
432
-     * @throws InvalidDataTypeException
433
-     * @throws InvalidInterfaceException
434
-     * @throws ReflectionException
435
-     */
436
-    public function event(): EE_Event
437
-    {
438
-        $event = $this->get_first_related('Event');
439
-        if (! $event instanceof EE_Event) {
440
-            throw new EntityNotFoundException('Event ID', $this->event_ID());
441
-        }
442
-        return $event;
443
-    }
444
-
445
-
446
-    /**
447
-     * Gets the "author" of the registration.  Note that for the purposes of registrations, the author will correspond
448
-     * with the author of the event this registration is for.
449
-     *
450
-     * @return int
451
-     * @throws EE_Error
452
-     * @throws EntityNotFoundException
453
-     * @throws InvalidArgumentException
454
-     * @throws InvalidDataTypeException
455
-     * @throws InvalidInterfaceException
456
-     * @throws ReflectionException
457
-     * @since 4.5.0
458
-     */
459
-    public function wp_user(): int
460
-    {
461
-        return $this->event()->wp_user();
462
-    }
463
-
464
-
465
-    /**
466
-     * increments this registration's related ticket sold and corresponding datetime sold values
467
-     *
468
-     * @return void
469
-     * @throws DomainException
470
-     * @throws EE_Error
471
-     * @throws EntityNotFoundException
472
-     * @throws InvalidArgumentException
473
-     * @throws InvalidDataTypeException
474
-     * @throws InvalidInterfaceException
475
-     * @throws ReflectionException
476
-     * @throws UnexpectedEntityException
477
-     */
478
-    private function reserveRegistrationSpace()
479
-    {
480
-        // reserved ticket and datetime counts will be decremented as sold counts are incremented
481
-        // so stop tracking that this reg has a ticket reserved
482
-        $this->release_reserved_ticket(false, "REG: {$this->ID()} (ln:" . __LINE__ . ')');
483
-        $ticket = $this->ticket();
484
-        $ticket->increaseSold();
485
-        // possibly set event status to sold out
486
-        $this->event()->perform_sold_out_status_check();
487
-    }
488
-
489
-
490
-    /**
491
-     * decrements (subtracts) this registration's related ticket sold and corresponding datetime sold values
492
-     *
493
-     * @return void
494
-     * @throws DomainException
495
-     * @throws EE_Error
496
-     * @throws EntityNotFoundException
497
-     * @throws InvalidArgumentException
498
-     * @throws InvalidDataTypeException
499
-     * @throws InvalidInterfaceException
500
-     * @throws ReflectionException
501
-     * @throws UnexpectedEntityException
502
-     */
503
-    private function releaseRegistrationSpace()
504
-    {
505
-        $ticket = $this->ticket();
506
-        $ticket->decreaseSold();
507
-        // possibly change event status from sold out back to previous status
508
-        $this->event()->perform_sold_out_status_check();
509
-    }
510
-
511
-
512
-    /**
513
-     * tracks this registration's ticket reservation in extra meta
514
-     * and can increment related ticket reserved and corresponding datetime reserved values
515
-     *
516
-     * @param bool   $update_ticket if true, will increment ticket and datetime reserved count
517
-     * @param string $source
518
-     * @return void
519
-     * @throws EE_Error
520
-     * @throws InvalidArgumentException
521
-     * @throws InvalidDataTypeException
522
-     * @throws InvalidInterfaceException
523
-     * @throws ReflectionException
524
-     */
525
-    public function reserve_ticket($update_ticket = false, $source = 'unknown')
526
-    {
527
-        // only reserve ticket if space is not currently reserved
528
-        if ((bool) $this->get_extra_meta(EE_Registration::HAS_RESERVED_TICKET_KEY, true) !== true) {
529
-            $reserved = $this->update_extra_meta(EE_Registration::HAS_RESERVED_TICKET_KEY, true);
530
-            if ($reserved && $update_ticket) {
531
-                $ticket = $this->ticket();
532
-                $ticket->increaseReserved(1, "REG: {$this->ID()} (ln:" . __LINE__ . ')');
533
-                $this->update_extra_meta('reserve_ticket', "{$this->ticket_ID()} from {$source}");
534
-                $ticket->save();
535
-            }
536
-        }
537
-    }
538
-
539
-
540
-    /**
541
-     * stops tracking this registration's ticket reservation in extra meta
542
-     * decrements (subtracts) related ticket reserved and corresponding datetime reserved values
543
-     *
544
-     * @param bool   $update_ticket if true, will decrement ticket and datetime reserved count
545
-     * @param string $source
546
-     * @return void
547
-     * @throws EE_Error
548
-     * @throws InvalidArgumentException
549
-     * @throws InvalidDataTypeException
550
-     * @throws InvalidInterfaceException
551
-     * @throws ReflectionException
552
-     */
553
-    public function release_reserved_ticket($update_ticket = false, $source = 'unknown')
554
-    {
555
-        // only release ticket if space is currently reserved
556
-        if ((bool) $this->get_extra_meta(EE_Registration::HAS_RESERVED_TICKET_KEY, true) === true) {
557
-            $reserved = $this->update_extra_meta(EE_Registration::HAS_RESERVED_TICKET_KEY, false);
558
-            if ($reserved && $update_ticket) {
559
-                $ticket = $this->ticket();
560
-                $ticket->decreaseReserved(1, true, "REG: {$this->ID()} (ln:" . __LINE__ . ')');
561
-                $this->update_extra_meta('release_reserved_ticket', "{$this->ticket_ID()} from {$source}");
562
-            }
563
-        }
564
-    }
565
-
566
-
567
-    /**
568
-     * Set Attendee ID
569
-     *
570
-     * @param int $ATT_ID Attendee ID
571
-     * @throws DomainException
572
-     * @throws EE_Error
573
-     * @throws EntityNotFoundException
574
-     * @throws InvalidArgumentException
575
-     * @throws InvalidDataTypeException
576
-     * @throws InvalidInterfaceException
577
-     * @throws ReflectionException
578
-     * @throws RuntimeException
579
-     * @throws UnexpectedEntityException
580
-     */
581
-    public function set_attendee_id($ATT_ID = 0)
582
-    {
583
-        $this->set('ATT_ID', $ATT_ID);
584
-    }
585
-
586
-
587
-    /**
588
-     *        Set Transaction ID
589
-     *
590
-     * @param int $TXN_ID Transaction ID
591
-     * @throws DomainException
592
-     * @throws EE_Error
593
-     * @throws EntityNotFoundException
594
-     * @throws InvalidArgumentException
595
-     * @throws InvalidDataTypeException
596
-     * @throws InvalidInterfaceException
597
-     * @throws ReflectionException
598
-     * @throws RuntimeException
599
-     * @throws UnexpectedEntityException
600
-     */
601
-    public function set_transaction_id($TXN_ID = 0)
602
-    {
603
-        $this->set('TXN_ID', $TXN_ID);
604
-    }
605
-
606
-
607
-    /**
608
-     *        Set Session
609
-     *
610
-     * @param string $REG_session PHP Session ID
611
-     * @throws DomainException
612
-     * @throws EE_Error
613
-     * @throws EntityNotFoundException
614
-     * @throws InvalidArgumentException
615
-     * @throws InvalidDataTypeException
616
-     * @throws InvalidInterfaceException
617
-     * @throws ReflectionException
618
-     * @throws RuntimeException
619
-     * @throws UnexpectedEntityException
620
-     */
621
-    public function set_session($REG_session = '')
622
-    {
623
-        $this->set('REG_session', $REG_session);
624
-    }
625
-
626
-
627
-    /**
628
-     *        Set Registration URL Link
629
-     *
630
-     * @param string $REG_url_link Registration URL Link
631
-     * @throws DomainException
632
-     * @throws EE_Error
633
-     * @throws EntityNotFoundException
634
-     * @throws InvalidArgumentException
635
-     * @throws InvalidDataTypeException
636
-     * @throws InvalidInterfaceException
637
-     * @throws ReflectionException
638
-     * @throws RuntimeException
639
-     * @throws UnexpectedEntityException
640
-     */
641
-    public function set_reg_url_link($REG_url_link = '')
642
-    {
643
-        $this->set('REG_url_link', $REG_url_link);
644
-    }
645
-
646
-
647
-    /**
648
-     *        Set Attendee Counter
649
-     *
650
-     * @param int $REG_count Primary Attendee
651
-     * @throws DomainException
652
-     * @throws EE_Error
653
-     * @throws EntityNotFoundException
654
-     * @throws InvalidArgumentException
655
-     * @throws InvalidDataTypeException
656
-     * @throws InvalidInterfaceException
657
-     * @throws ReflectionException
658
-     * @throws RuntimeException
659
-     * @throws UnexpectedEntityException
660
-     */
661
-    public function set_count($REG_count = 1)
662
-    {
663
-        $this->set('REG_count', $REG_count);
664
-    }
665
-
666
-
667
-    /**
668
-     *        Set Group Size
669
-     *
670
-     * @param boolean $REG_group_size Group Registration
671
-     * @throws DomainException
672
-     * @throws EE_Error
673
-     * @throws EntityNotFoundException
674
-     * @throws InvalidArgumentException
675
-     * @throws InvalidDataTypeException
676
-     * @throws InvalidInterfaceException
677
-     * @throws ReflectionException
678
-     * @throws RuntimeException
679
-     * @throws UnexpectedEntityException
680
-     */
681
-    public function set_group_size($REG_group_size = false)
682
-    {
683
-        $this->set('REG_group_size', $REG_group_size);
684
-    }
685
-
686
-
687
-    /**
688
-     *    is_not_approved -  convenience method that returns TRUE if REG status ID ==
689
-     *    EEM_Registration::status_id_not_approved
690
-     *
691
-     * @return        boolean
692
-     * @throws EE_Error
693
-     * @throws InvalidArgumentException
694
-     * @throws InvalidDataTypeException
695
-     * @throws InvalidInterfaceException
696
-     * @throws ReflectionException
697
-     */
698
-    public function is_not_approved()
699
-    {
700
-        return $this->status_ID() === EEM_Registration::status_id_not_approved;
701
-    }
702
-
703
-
704
-    /**
705
-     *    is_pending_payment -  convenience method that returns TRUE if REG status ID ==
706
-     *    EEM_Registration::status_id_pending_payment
707
-     *
708
-     * @return        boolean
709
-     * @throws EE_Error
710
-     * @throws InvalidArgumentException
711
-     * @throws InvalidDataTypeException
712
-     * @throws InvalidInterfaceException
713
-     * @throws ReflectionException
714
-     */
715
-    public function is_pending_payment()
716
-    {
717
-        return $this->status_ID() === EEM_Registration::status_id_pending_payment;
718
-    }
719
-
720
-
721
-    /**
722
-     *    is_approved -  convenience method that returns TRUE if REG status ID == EEM_Registration::status_id_approved
723
-     *
724
-     * @return        boolean
725
-     * @throws EE_Error
726
-     * @throws InvalidArgumentException
727
-     * @throws InvalidDataTypeException
728
-     * @throws InvalidInterfaceException
729
-     * @throws ReflectionException
730
-     */
731
-    public function is_approved()
732
-    {
733
-        return $this->status_ID() === EEM_Registration::status_id_approved;
734
-    }
735
-
736
-
737
-    /**
738
-     *    is_cancelled -  convenience method that returns TRUE if REG status ID == EEM_Registration::status_id_cancelled
739
-     *
740
-     * @return        boolean
741
-     * @throws EE_Error
742
-     * @throws InvalidArgumentException
743
-     * @throws InvalidDataTypeException
744
-     * @throws InvalidInterfaceException
745
-     * @throws ReflectionException
746
-     */
747
-    public function is_cancelled()
748
-    {
749
-        return $this->status_ID() === EEM_Registration::status_id_cancelled;
750
-    }
751
-
752
-
753
-    /**
754
-     *    is_declined -  convenience method that returns TRUE if REG status ID == EEM_Registration::status_id_declined
755
-     *
756
-     * @return        boolean
757
-     * @throws EE_Error
758
-     * @throws InvalidArgumentException
759
-     * @throws InvalidDataTypeException
760
-     * @throws InvalidInterfaceException
761
-     * @throws ReflectionException
762
-     */
763
-    public function is_declined()
764
-    {
765
-        return $this->status_ID() === EEM_Registration::status_id_declined;
766
-    }
767
-
768
-
769
-    /**
770
-     *    is_incomplete -  convenience method that returns TRUE if REG status ID ==
771
-     *    EEM_Registration::status_id_incomplete
772
-     *
773
-     * @return        boolean
774
-     * @throws EE_Error
775
-     * @throws InvalidArgumentException
776
-     * @throws InvalidDataTypeException
777
-     * @throws InvalidInterfaceException
778
-     * @throws ReflectionException
779
-     */
780
-    public function is_incomplete()
781
-    {
782
-        return $this->status_ID() === EEM_Registration::status_id_incomplete;
783
-    }
784
-
785
-
786
-    /**
787
-     *        Set Registration Date
788
-     *
789
-     * @param mixed ( int or string ) $REG_date Registration Date - Unix timestamp or string representation of
790
-     *                                                 Date
791
-     * @throws DomainException
792
-     * @throws EE_Error
793
-     * @throws EntityNotFoundException
794
-     * @throws InvalidArgumentException
795
-     * @throws InvalidDataTypeException
796
-     * @throws InvalidInterfaceException
797
-     * @throws ReflectionException
798
-     * @throws RuntimeException
799
-     * @throws UnexpectedEntityException
800
-     */
801
-    public function set_reg_date($REG_date = false)
802
-    {
803
-        $this->set('REG_date', $REG_date);
804
-    }
805
-
806
-
807
-    /**
808
-     *    Set final price owing for this registration after all ticket/price modifications
809
-     *
810
-     * @param float $REG_final_price
811
-     * @throws DomainException
812
-     * @throws EE_Error
813
-     * @throws EntityNotFoundException
814
-     * @throws InvalidArgumentException
815
-     * @throws InvalidDataTypeException
816
-     * @throws InvalidInterfaceException
817
-     * @throws ReflectionException
818
-     * @throws RuntimeException
819
-     * @throws UnexpectedEntityException
820
-     */
821
-    public function set_final_price($REG_final_price = 0.00)
822
-    {
823
-        $this->set('REG_final_price', $REG_final_price);
824
-    }
825
-
826
-
827
-    /**
828
-     *    Set amount paid towards this registration's final price
829
-     *
830
-     * @param float|int|string $REG_paid
831
-     * @throws DomainException
832
-     * @throws EE_Error
833
-     * @throws EntityNotFoundException
834
-     * @throws InvalidArgumentException
835
-     * @throws InvalidDataTypeException
836
-     * @throws InvalidInterfaceException
837
-     * @throws ReflectionException
838
-     * @throws RuntimeException
839
-     * @throws UnexpectedEntityException
840
-     */
841
-    public function set_paid($REG_paid = 0.00)
842
-    {
843
-        $this->set('REG_paid', (float) $REG_paid);
844
-    }
845
-
846
-
847
-    /**
848
-     *        Attendee Is Going
849
-     *
850
-     * @param boolean $REG_att_is_going Attendee Is Going
851
-     * @throws DomainException
852
-     * @throws EE_Error
853
-     * @throws EntityNotFoundException
854
-     * @throws InvalidArgumentException
855
-     * @throws InvalidDataTypeException
856
-     * @throws InvalidInterfaceException
857
-     * @throws ReflectionException
858
-     * @throws RuntimeException
859
-     * @throws UnexpectedEntityException
860
-     */
861
-    public function set_att_is_going($REG_att_is_going = false)
862
-    {
863
-        $this->set('REG_att_is_going', $REG_att_is_going);
864
-    }
865
-
866
-
867
-    /**
868
-     * Gets the related attendee
869
-     *
870
-     * @return EE_Attendee|EE_Base_Class
871
-     * @throws EE_Error
872
-     * @throws InvalidArgumentException
873
-     * @throws InvalidDataTypeException
874
-     * @throws InvalidInterfaceException
875
-     * @throws ReflectionException
876
-     */
877
-    public function attendee()
878
-    {
879
-        return $this->get_first_related('Attendee');
880
-    }
881
-
882
-
883
-    /**
884
-     * Gets the name of the attendee.
885
-     *
886
-     * @param bool $apply_html_entities set to true if you want to use HTML entities.
887
-     * @return string
888
-     * @throws EE_Error
889
-     * @throws InvalidArgumentException
890
-     * @throws InvalidDataTypeException
891
-     * @throws InvalidInterfaceException
892
-     * @throws ReflectionException
893
-     * @since 4.10.12.p
894
-     */
895
-    public function attendeeName($apply_html_entities = false)
896
-    {
897
-        $attendee = $this->get_first_related('Attendee');
898
-        if ($attendee instanceof EE_Attendee) {
899
-            $attendee_name = $attendee->full_name($apply_html_entities);
900
-        } else {
901
-            $attendee_name = esc_html__('Unknown', 'event_espresso');
902
-        }
903
-        return $attendee_name;
904
-    }
905
-
906
-
907
-    /**
908
-     *        get Event ID
909
-     */
910
-    public function event_ID()
911
-    {
912
-        return $this->get('EVT_ID');
913
-    }
914
-
915
-
916
-    /**
917
-     *        get Event ID
918
-     */
919
-    public function event_name()
920
-    {
921
-        $event = $this->event_obj();
922
-        if ($event) {
923
-            return $event->name();
924
-        } else {
925
-            return null;
926
-        }
927
-    }
928
-
929
-
930
-    /**
931
-     * Fetches the event this registration is for
932
-     *
933
-     * @return EE_Base_Class|EE_Event
934
-     * @throws EE_Error
935
-     * @throws InvalidArgumentException
936
-     * @throws InvalidDataTypeException
937
-     * @throws InvalidInterfaceException
938
-     * @throws ReflectionException
939
-     */
940
-    public function event_obj()
941
-    {
942
-        return $this->get_first_related('Event');
943
-    }
944
-
945
-
946
-    /**
947
-     *        get Attendee ID
948
-     */
949
-    public function attendee_ID()
950
-    {
951
-        return $this->get('ATT_ID');
952
-    }
953
-
954
-
955
-    /**
956
-     *        get PHP Session ID
957
-     */
958
-    public function session_ID()
959
-    {
960
-        return $this->get('REG_session');
961
-    }
962
-
963
-
964
-    /**
965
-     * Gets the string which represents the URL trigger for the receipt template in the message template system.
966
-     *
967
-     * @param string $messenger 'pdf' or 'html'.  Default 'html'.
968
-     * @return string
969
-     * @throws DomainException
970
-     * @throws InvalidArgumentException
971
-     * @throws InvalidDataTypeException
972
-     * @throws InvalidInterfaceException
973
-     */
974
-    public function receipt_url($messenger = 'html')
975
-    {
976
-        return apply_filters('FHEE__EE_Registration__receipt_url__receipt_url', '', $this, $messenger, 'receipt');
977
-    }
978
-
979
-
980
-    /**
981
-     * Gets the string which represents the URL trigger for the invoice template in the message template system.
982
-     *
983
-     * @param string $messenger 'pdf' or 'html'.  Default 'html'.
984
-     * @return string
985
-     * @throws DomainException
986
-     * @throws InvalidArgumentException
987
-     * @throws InvalidDataTypeException
988
-     * @throws InvalidInterfaceException
989
-     */
990
-    public function invoice_url($messenger = 'html')
991
-    {
992
-        return apply_filters('FHEE__EE_Registration__invoice_url__invoice_url', '', $this, $messenger, 'invoice');
993
-    }
994
-
995
-
996
-    /**
997
-     * get Registration URL Link
998
-     *
999
-     * @return string
1000
-     * @throws EE_Error
1001
-     * @throws InvalidArgumentException
1002
-     * @throws InvalidDataTypeException
1003
-     * @throws InvalidInterfaceException
1004
-     * @throws ReflectionException
1005
-     */
1006
-    public function reg_url_link()
1007
-    {
1008
-        return (string) $this->get('REG_url_link');
1009
-    }
1010
-
1011
-
1012
-    /**
1013
-     * Echoes out invoice_url()
1014
-     *
1015
-     * @param string $type 'download','launch', or 'html' (default is 'launch')
1016
-     * @return void
1017
-     * @throws DomainException
1018
-     * @throws EE_Error
1019
-     * @throws InvalidArgumentException
1020
-     * @throws InvalidDataTypeException
1021
-     * @throws InvalidInterfaceException
1022
-     * @throws ReflectionException
1023
-     */
1024
-    public function e_invoice_url($type = 'launch')
1025
-    {
1026
-        echo esc_url_raw($this->invoice_url($type));
1027
-    }
1028
-
1029
-
1030
-    /**
1031
-     * Echoes out payment_overview_url
1032
-     */
1033
-    public function e_payment_overview_url()
1034
-    {
1035
-        echo esc_url_raw($this->payment_overview_url());
1036
-    }
1037
-
1038
-
1039
-    /**
1040
-     * Gets the URL for the checkout payment options reg step
1041
-     * with this registration's REG_url_link added as a query parameter
1042
-     *
1043
-     * @param bool $clear_session Set to true when you want to clear the session on revisiting the
1044
-     *                            payment overview url.
1045
-     * @return string
1046
-     * @throws EE_Error
1047
-     * @throws InvalidArgumentException
1048
-     * @throws InvalidDataTypeException
1049
-     * @throws InvalidInterfaceException
1050
-     * @throws ReflectionException
1051
-     */
1052
-    public function payment_overview_url($clear_session = false)
1053
-    {
1054
-        return add_query_arg(
1055
-            (array) apply_filters(
1056
-                'FHEE__EE_Registration__payment_overview_url__query_args',
1057
-                [
1058
-                    'e_reg_url_link' => $this->reg_url_link(),
1059
-                    'step'           => 'payment_options',
1060
-                    'revisit'        => true,
1061
-                    'clear_session'  => (bool) $clear_session,
1062
-                ],
1063
-                $this
1064
-            ),
1065
-            EE_Registry::instance()->CFG->core->reg_page_url()
1066
-        );
1067
-    }
1068
-
1069
-
1070
-    /**
1071
-     * Gets the URL for the checkout attendee information reg step
1072
-     * with this registration's REG_url_link added as a query parameter
1073
-     *
1074
-     * @return string
1075
-     * @throws EE_Error
1076
-     * @throws InvalidArgumentException
1077
-     * @throws InvalidDataTypeException
1078
-     * @throws InvalidInterfaceException
1079
-     * @throws ReflectionException
1080
-     */
1081
-    public function edit_attendee_information_url()
1082
-    {
1083
-        return add_query_arg(
1084
-            (array) apply_filters(
1085
-                'FHEE__EE_Registration__edit_attendee_information_url__query_args',
1086
-                [
1087
-                    'e_reg_url_link' => $this->reg_url_link(),
1088
-                    'step'           => 'attendee_information',
1089
-                    'revisit'        => true,
1090
-                ],
1091
-                $this
1092
-            ),
1093
-            EE_Registry::instance()->CFG->core->reg_page_url()
1094
-        );
1095
-    }
1096
-
1097
-
1098
-    /**
1099
-     * Simply generates and returns the appropriate admin_url link to edit this registration
1100
-     *
1101
-     * @return string
1102
-     * @throws EE_Error
1103
-     * @throws InvalidArgumentException
1104
-     * @throws InvalidDataTypeException
1105
-     * @throws InvalidInterfaceException
1106
-     * @throws ReflectionException
1107
-     */
1108
-    public function get_admin_edit_url()
1109
-    {
1110
-        return EEH_URL::add_query_args_and_nonce(
1111
-            [
1112
-                'page'    => 'espresso_registrations',
1113
-                'action'  => 'view_registration',
1114
-                '_REG_ID' => $this->ID(),
1115
-            ],
1116
-            admin_url('admin.php')
1117
-        );
1118
-    }
1119
-
1120
-
1121
-    /**
1122
-     * is_primary_registrant?
1123
-     *
1124
-     * @throws EE_Error
1125
-     * @throws InvalidArgumentException
1126
-     * @throws InvalidDataTypeException
1127
-     * @throws InvalidInterfaceException
1128
-     * @throws ReflectionException
1129
-     */
1130
-    public function is_primary_registrant()
1131
-    {
1132
-        return (int) $this->get('REG_count') === 1;
1133
-    }
1134
-
1135
-
1136
-    /**
1137
-     * This returns the primary registration object for this registration group (which may be this object).
1138
-     *
1139
-     * @return EE_Registration
1140
-     * @throws EE_Error
1141
-     * @throws InvalidArgumentException
1142
-     * @throws InvalidDataTypeException
1143
-     * @throws InvalidInterfaceException
1144
-     * @throws ReflectionException
1145
-     */
1146
-    public function get_primary_registration()
1147
-    {
1148
-        if ($this->is_primary_registrant()) {
1149
-            return $this;
1150
-        }
1151
-
1152
-        // k reg_count !== 1 so let's get the EE_Registration object matching this txn_id and reg_count == 1
1153
-        /** @var EE_Registration $primary_registrant */
1154
-        $primary_registrant = EEM_Registration::instance()->get_one(
1155
-            [
1156
-                [
1157
-                    'TXN_ID'    => $this->transaction_ID(),
1158
-                    'REG_count' => 1,
1159
-                ],
1160
-            ]
1161
-        );
1162
-        return $primary_registrant;
1163
-    }
1164
-
1165
-
1166
-    /**
1167
-     * get  Attendee Number
1168
-     *
1169
-     * @throws EE_Error
1170
-     * @throws InvalidArgumentException
1171
-     * @throws InvalidDataTypeException
1172
-     * @throws InvalidInterfaceException
1173
-     * @throws ReflectionException
1174
-     */
1175
-    public function count()
1176
-    {
1177
-        return $this->get('REG_count');
1178
-    }
1179
-
1180
-
1181
-    /**
1182
-     * get Group Size
1183
-     *
1184
-     * @throws EE_Error
1185
-     * @throws InvalidArgumentException
1186
-     * @throws InvalidDataTypeException
1187
-     * @throws InvalidInterfaceException
1188
-     * @throws ReflectionException
1189
-     */
1190
-    public function group_size()
1191
-    {
1192
-        return $this->get('REG_group_size');
1193
-    }
1194
-
1195
-
1196
-    /**
1197
-     * get Registration Date
1198
-     *
1199
-     * @throws EE_Error
1200
-     * @throws InvalidArgumentException
1201
-     * @throws InvalidDataTypeException
1202
-     * @throws InvalidInterfaceException
1203
-     * @throws ReflectionException
1204
-     */
1205
-    public function date()
1206
-    {
1207
-        return $this->get('REG_date');
1208
-    }
1209
-
1210
-
1211
-    /**
1212
-     * gets a pretty date
1213
-     *
1214
-     * @param string $date_format
1215
-     * @param string $time_format
1216
-     * @return string
1217
-     * @throws EE_Error
1218
-     * @throws InvalidArgumentException
1219
-     * @throws InvalidDataTypeException
1220
-     * @throws InvalidInterfaceException
1221
-     * @throws ReflectionException
1222
-     */
1223
-    public function pretty_date($date_format = null, $time_format = null)
1224
-    {
1225
-        return $this->get_datetime('REG_date', $date_format, $time_format);
1226
-    }
1227
-
1228
-
1229
-    /**
1230
-     * final_price
1231
-     * the registration's share of the transaction total, so that the
1232
-     * sum of all the transaction's REG_final_prices equal the transaction's total
1233
-     *
1234
-     * @return float
1235
-     * @throws EE_Error
1236
-     * @throws InvalidArgumentException
1237
-     * @throws InvalidDataTypeException
1238
-     * @throws InvalidInterfaceException
1239
-     * @throws ReflectionException
1240
-     */
1241
-    public function final_price(): float
1242
-    {
1243
-        return (float) $this->get('REG_final_price');
1244
-    }
1245
-
1246
-
1247
-    /**
1248
-     * pretty_final_price
1249
-     *  final price as formatted string, with correct decimal places and currency symbol
1250
-     *
1251
-     * @return string
1252
-     * @throws EE_Error
1253
-     * @throws InvalidArgumentException
1254
-     * @throws InvalidDataTypeException
1255
-     * @throws InvalidInterfaceException
1256
-     * @throws ReflectionException
1257
-     */
1258
-    public function pretty_final_price()
1259
-    {
1260
-        return $this->get_pretty('REG_final_price');
1261
-    }
1262
-
1263
-
1264
-    /**
1265
-     * get paid (yeah)
1266
-     *
1267
-     * @return float
1268
-     * @throws EE_Error
1269
-     * @throws InvalidArgumentException
1270
-     * @throws InvalidDataTypeException
1271
-     * @throws InvalidInterfaceException
1272
-     * @throws ReflectionException
1273
-     */
1274
-    public function paid(): float
1275
-    {
1276
-        return (float) $this->get('REG_paid');
1277
-    }
1278
-
1279
-
1280
-    /**
1281
-     * pretty_paid
1282
-     *
1283
-     * @return float
1284
-     * @throws EE_Error
1285
-     * @throws InvalidArgumentException
1286
-     * @throws InvalidDataTypeException
1287
-     * @throws InvalidInterfaceException
1288
-     * @throws ReflectionException
1289
-     */
1290
-    public function pretty_paid()
1291
-    {
1292
-        return $this->get_pretty('REG_paid');
1293
-    }
1294
-
1295
-
1296
-    /**
1297
-     * owes_monies_and_can_pay
1298
-     * whether or not this registration has monies owing and it's' status allows payment
1299
-     *
1300
-     * @param array $requires_payment list of registration statuses that allow a registrant to make a payment
1301
-     * @return bool
1302
-     * @throws EE_Error
1303
-     * @throws InvalidArgumentException
1304
-     * @throws InvalidDataTypeException
1305
-     * @throws InvalidInterfaceException
1306
-     * @throws ReflectionException
1307
-     */
1308
-    public function owes_monies_and_can_pay($requires_payment = [])
1309
-    {
1310
-        // these reg statuses require payment (if event is not free)
1311
-        $requires_payment = ! empty($requires_payment)
1312
-            ? $requires_payment
1313
-            : EEM_Registration::reg_statuses_that_allow_payment();
1314
-        if (
1315
-            $this->final_price() !== 0 &&
1316
-            $this->final_price() !== $this->paid() &&
1317
-            in_array($this->status_ID(), $requires_payment)
1318
-        ) {
1319
-            return true;
1320
-        }
1321
-        return false;
1322
-    }
1323
-
1324
-
1325
-    /**
1326
-     * Prints out the return value of $this->pretty_status()
1327
-     *
1328
-     * @param bool $show_icons
1329
-     * @return void
1330
-     * @throws EE_Error
1331
-     * @throws InvalidArgumentException
1332
-     * @throws InvalidDataTypeException
1333
-     * @throws InvalidInterfaceException
1334
-     * @throws ReflectionException
1335
-     */
1336
-    public function e_pretty_status($show_icons = false)
1337
-    {
1338
-        echo wp_kses($this->pretty_status($show_icons), AllowedTags::getAllowedTags());
1339
-    }
1340
-
1341
-
1342
-    /**
1343
-     * Returns a nice version of the status for displaying to customers
1344
-     *
1345
-     * @param bool $show_icons
1346
-     * @return string
1347
-     * @throws EE_Error
1348
-     * @throws InvalidArgumentException
1349
-     * @throws InvalidDataTypeException
1350
-     * @throws InvalidInterfaceException
1351
-     * @throws ReflectionException
1352
-     */
1353
-    public function pretty_status($show_icons = false)
1354
-    {
1355
-        $status = EEM_Status::instance()->localized_status(
1356
-            [$this->status_ID() => esc_html__('unknown', 'event_espresso')],
1357
-            false,
1358
-            'sentence'
1359
-        );
1360
-        $icon   = '';
1361
-        switch ($this->status_ID()) {
1362
-            case EEM_Registration::status_id_approved:
1363
-                $icon = $show_icons
1364
-                    ? '<span class="dashicons dashicons-star-filled ee-icon-size-16 green-text"></span>'
1365
-                    : '';
1366
-                break;
1367
-            case EEM_Registration::status_id_pending_payment:
1368
-                $icon = $show_icons
1369
-                    ? '<span class="dashicons dashicons-star-half ee-icon-size-16 orange-text"></span>'
1370
-                    : '';
1371
-                break;
1372
-            case EEM_Registration::status_id_not_approved:
1373
-                $icon = $show_icons
1374
-                    ? '<span class="dashicons dashicons-marker ee-icon-size-16 orange-text"></span>'
1375
-                    : '';
1376
-                break;
1377
-            case EEM_Registration::status_id_cancelled:
1378
-                $icon = $show_icons
1379
-                    ? '<span class="dashicons dashicons-no ee-icon-size-16 lt-grey-text"></span>'
1380
-                    : '';
1381
-                break;
1382
-            case EEM_Registration::status_id_incomplete:
1383
-                $icon = $show_icons
1384
-                    ? '<span class="dashicons dashicons-no ee-icon-size-16 lt-orange-text"></span>'
1385
-                    : '';
1386
-                break;
1387
-            case EEM_Registration::status_id_declined:
1388
-                $icon = $show_icons
1389
-                    ? '<span class="dashicons dashicons-no ee-icon-size-16 red-text"></span>'
1390
-                    : '';
1391
-                break;
1392
-            case EEM_Registration::status_id_wait_list:
1393
-                $icon = $show_icons
1394
-                    ? '<span class="dashicons dashicons-clipboard ee-icon-size-16 purple-text"></span>'
1395
-                    : '';
1396
-                break;
1397
-        }
1398
-        return $icon . $status[ $this->status_ID() ];
1399
-    }
1400
-
1401
-
1402
-    /**
1403
-     *        get Attendee Is Going
1404
-     */
1405
-    public function att_is_going()
1406
-    {
1407
-        return $this->get('REG_att_is_going');
1408
-    }
1409
-
1410
-
1411
-    /**
1412
-     * Gets related answers
1413
-     *
1414
-     * @param array $query_params @see
1415
-     *                            https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
1416
-     * @return EE_Answer[]|EE_Base_Class[]
1417
-     * @throws EE_Error
1418
-     * @throws InvalidArgumentException
1419
-     * @throws InvalidDataTypeException
1420
-     * @throws InvalidInterfaceException
1421
-     * @throws ReflectionException
1422
-     */
1423
-    public function answers($query_params = [])
1424
-    {
1425
-        return $this->get_many_related('Answer', $query_params);
1426
-    }
1427
-
1428
-
1429
-    /**
1430
-     * Gets the registration's answer value to the specified question
1431
-     * (either the question's ID or a question object)
1432
-     *
1433
-     * @param EE_Question|int $question
1434
-     * @param bool            $pretty_value
1435
-     * @return array|string if pretty_value= true, the result will always be a string
1436
-     * (because the answer might be an array of answer values, so passing pretty_value=true
1437
-     * will convert it into some kind of string)
1438
-     * @throws EE_Error
1439
-     * @throws InvalidArgumentException
1440
-     * @throws InvalidDataTypeException
1441
-     * @throws InvalidInterfaceException
1442
-     */
1443
-    public function answer_value_to_question($question, $pretty_value = true)
1444
-    {
1445
-        $question_id = EEM_Question::instance()->ensure_is_ID($question);
1446
-        return EEM_Answer::instance()->get_answer_value_to_question($this, $question_id, $pretty_value);
1447
-    }
1448
-
1449
-
1450
-    /**
1451
-     * question_groups
1452
-     * returns an array of EE_Question_Group objects for this registration
1453
-     *
1454
-     * @return EE_Question_Group[]
1455
-     * @throws EE_Error
1456
-     * @throws InvalidArgumentException
1457
-     * @throws InvalidDataTypeException
1458
-     * @throws InvalidInterfaceException
1459
-     * @throws ReflectionException
1460
-     */
1461
-    public function question_groups()
1462
-    {
1463
-        return EEM_Event::instance()->get_question_groups_for_event($this->event_ID(), $this);
1464
-    }
1465
-
1466
-
1467
-    /**
1468
-     * count_question_groups
1469
-     * returns a count of the number of EE_Question_Group objects for this registration
1470
-     *
1471
-     * @return int
1472
-     * @throws EE_Error
1473
-     * @throws EntityNotFoundException
1474
-     * @throws InvalidArgumentException
1475
-     * @throws InvalidDataTypeException
1476
-     * @throws InvalidInterfaceException
1477
-     * @throws ReflectionException
1478
-     */
1479
-    public function count_question_groups()
1480
-    {
1481
-        return EEM_Event::instance()->count_related(
1482
-            $this->event_ID(),
1483
-            'Question_Group',
1484
-            [
1485
-                [
1486
-                    'Event_Question_Group.'
1487
-                    . EEM_Event_Question_Group::instance()->fieldNameForContext($this->is_primary_registrant()) => true,
1488
-                ],
1489
-            ]
1490
-        );
1491
-    }
1492
-
1493
-
1494
-    /**
1495
-     * Returns the registration date in the 'standard' string format
1496
-     * (function may be improved in the future to allow for different formats and timezones)
1497
-     *
1498
-     * @return string
1499
-     * @throws EE_Error
1500
-     * @throws InvalidArgumentException
1501
-     * @throws InvalidDataTypeException
1502
-     * @throws InvalidInterfaceException
1503
-     * @throws ReflectionException
1504
-     */
1505
-    public function reg_date()
1506
-    {
1507
-        return $this->get_datetime('REG_date');
1508
-    }
1509
-
1510
-
1511
-    /**
1512
-     * Gets the datetime-ticket for this registration (ie, it can be used to isolate
1513
-     * the ticket this registration purchased, or the datetime they have registered
1514
-     * to attend)
1515
-     *
1516
-     * @return EE_Base_Class|EE_Datetime_Ticket
1517
-     * @throws EE_Error
1518
-     * @throws InvalidArgumentException
1519
-     * @throws InvalidDataTypeException
1520
-     * @throws InvalidInterfaceException
1521
-     * @throws ReflectionException
1522
-     */
1523
-    public function datetime_ticket()
1524
-    {
1525
-        return $this->get_first_related('Datetime_Ticket');
1526
-    }
1527
-
1528
-
1529
-    /**
1530
-     * Sets the registration's datetime_ticket.
1531
-     *
1532
-     * @param EE_Datetime_Ticket $datetime_ticket
1533
-     * @return EE_Base_Class|EE_Datetime_Ticket
1534
-     * @throws EE_Error
1535
-     * @throws InvalidArgumentException
1536
-     * @throws InvalidDataTypeException
1537
-     * @throws InvalidInterfaceException
1538
-     * @throws ReflectionException
1539
-     */
1540
-    public function set_datetime_ticket($datetime_ticket)
1541
-    {
1542
-        return $this->_add_relation_to($datetime_ticket, 'Datetime_Ticket');
1543
-    }
1544
-
1545
-
1546
-    /**
1547
-     * Gets deleted
1548
-     *
1549
-     * @return bool
1550
-     * @throws EE_Error
1551
-     * @throws InvalidArgumentException
1552
-     * @throws InvalidDataTypeException
1553
-     * @throws InvalidInterfaceException
1554
-     * @throws ReflectionException
1555
-     */
1556
-    public function deleted()
1557
-    {
1558
-        return $this->get('REG_deleted');
1559
-    }
1560
-
1561
-
1562
-    /**
1563
-     * Sets deleted
1564
-     *
1565
-     * @param boolean $deleted
1566
-     * @return void
1567
-     * @throws DomainException
1568
-     * @throws EE_Error
1569
-     * @throws EntityNotFoundException
1570
-     * @throws InvalidArgumentException
1571
-     * @throws InvalidDataTypeException
1572
-     * @throws InvalidInterfaceException
1573
-     * @throws ReflectionException
1574
-     * @throws RuntimeException
1575
-     * @throws UnexpectedEntityException
1576
-     */
1577
-    public function set_deleted($deleted)
1578
-    {
1579
-        if ($deleted) {
1580
-            $this->delete();
1581
-        } else {
1582
-            $this->restore();
1583
-        }
1584
-    }
1585
-
1586
-
1587
-    /**
1588
-     * Get the status object of this object
1589
-     *
1590
-     * @return EE_Base_Class|EE_Status
1591
-     * @throws EE_Error
1592
-     * @throws InvalidArgumentException
1593
-     * @throws InvalidDataTypeException
1594
-     * @throws InvalidInterfaceException
1595
-     * @throws ReflectionException
1596
-     */
1597
-    public function status_obj()
1598
-    {
1599
-        return $this->get_first_related('Status');
1600
-    }
1601
-
1602
-
1603
-    /**
1604
-     * Returns the number of times this registration has checked into any of the datetimes
1605
-     * its available for
1606
-     *
1607
-     * @return int
1608
-     * @throws EE_Error
1609
-     * @throws InvalidArgumentException
1610
-     * @throws InvalidDataTypeException
1611
-     * @throws InvalidInterfaceException
1612
-     * @throws ReflectionException
1613
-     */
1614
-    public function count_checkins()
1615
-    {
1616
-        return $this->get_model()->count_related($this, 'Checkin');
1617
-    }
1618
-
1619
-
1620
-    /**
1621
-     * Returns the number of current Check-ins this registration is checked into for any of the datetimes the
1622
-     * registration is for.  Note, this is ONLY checked in (does not include checkedout)
1623
-     *
1624
-     * @return int
1625
-     * @throws EE_Error
1626
-     * @throws InvalidArgumentException
1627
-     * @throws InvalidDataTypeException
1628
-     * @throws InvalidInterfaceException
1629
-     * @throws ReflectionException
1630
-     */
1631
-    public function count_checkins_not_checkedout()
1632
-    {
1633
-        return $this->get_model()->count_related($this, 'Checkin', [['CHK_in' => 1]]);
1634
-    }
1635
-
1636
-
1637
-    /**
1638
-     * The purpose of this method is simply to check whether this registration can checkin to the given datetime.
1639
-     *
1640
-     * @param int | EE_Datetime $DTT_OR_ID      The datetime the registration is being checked against
1641
-     * @param bool              $check_approved This is used to indicate whether the caller wants can_checkin to also
1642
-     *                                          consider registration status as well as datetime access.
1643
-     * @return bool
1644
-     * @throws EE_Error
1645
-     * @throws InvalidArgumentException
1646
-     * @throws InvalidDataTypeException
1647
-     * @throws InvalidInterfaceException
1648
-     * @throws ReflectionException
1649
-     */
1650
-    public function can_checkin($DTT_OR_ID, $check_approved = true)
1651
-    {
1652
-        $DTT_ID = EEM_Datetime::instance()->ensure_is_ID($DTT_OR_ID);
1653
-        // first check registration status
1654
-        if (! $DTT_ID || ($check_approved && ! $this->is_approved())) {
1655
-            return false;
1656
-        }
1657
-        // is there a datetime ticket that matches this dtt_ID?
1658
-        if (
1659
-            ! (EEM_Datetime_Ticket::instance()->exists(
1660
-                [
1661
-                    [
1662
-                        'TKT_ID' => $this->get('TKT_ID'),
1663
-                        'DTT_ID' => $DTT_ID,
1664
-                    ],
1665
-                ]
1666
-            ))
1667
-        ) {
1668
-            return false;
1669
-        }
1670
-
1671
-        // final check is against TKT_uses
1672
-        return $this->verify_can_checkin_against_TKT_uses($DTT_ID);
1673
-    }
1674
-
1675
-
1676
-    /**
1677
-     * This method verifies whether the user can checkin for the given datetime considering the max uses value set on
1678
-     * the ticket. To do this,  a query is done to get the count of the datetime records already checked into.  If the
1679
-     * datetime given does not have a check-in record and checking in for that datetime will exceed the allowed uses,
1680
-     * then return false.  Otherwise return true.
1681
-     *
1682
-     * @param int | EE_Datetime $DTT_OR_ID The datetime the registration is being checked against
1683
-     * @return bool true means can checkin.  false means cannot checkin.
1684
-     * @throws EE_Error
1685
-     * @throws InvalidArgumentException
1686
-     * @throws InvalidDataTypeException
1687
-     * @throws InvalidInterfaceException
1688
-     * @throws ReflectionException
1689
-     */
1690
-    public function verify_can_checkin_against_TKT_uses($DTT_OR_ID)
1691
-    {
1692
-        $DTT_ID = EEM_Datetime::instance()->ensure_is_ID($DTT_OR_ID);
1693
-
1694
-        if (! $DTT_ID) {
1695
-            return false;
1696
-        }
1697
-
1698
-        $max_uses = $this->ticket() instanceof EE_Ticket
1699
-            ? $this->ticket()->uses()
1700
-            : EE_INF;
1701
-
1702
-        // if max uses is not set or equals infinity then return true cause its not a factor for whether user can
1703
-        // check-in or not.
1704
-        if (! $max_uses || $max_uses === EE_INF) {
1705
-            return true;
1706
-        }
1707
-
1708
-        // does this datetime have a checkin record?  If so, then the dtt count has already been verified so we can just
1709
-        // go ahead and toggle.
1710
-        if (EEM_Checkin::instance()->exists([['REG_ID' => $this->ID(), 'DTT_ID' => $DTT_ID]])) {
1711
-            return true;
1712
-        }
1713
-
1714
-        // made it here so the last check is whether the number of checkins per unique datetime on this registration
1715
-        // disallows further check-ins.
1716
-        $count_unique_dtt_checkins = EEM_Checkin::instance()->count(
1717
-            [
1718
-                [
1719
-                    'REG_ID' => $this->ID(),
1720
-                    'CHK_in' => true,
1721
-                ],
1722
-            ],
1723
-            'DTT_ID',
1724
-            true
1725
-        );
1726
-        // checkins have already reached their max number of uses
1727
-        // so registrant can NOT checkin
1728
-        if ($count_unique_dtt_checkins >= $max_uses) {
1729
-            EE_Error::add_error(
1730
-                esc_html__(
1731
-                    'Check-in denied because number of datetime uses for the ticket has been reached or exceeded.',
1732
-                    'event_espresso'
1733
-                ),
1734
-                __FILE__,
1735
-                __FUNCTION__,
1736
-                __LINE__
1737
-            );
1738
-            return false;
1739
-        }
1740
-        return true;
1741
-    }
1742
-
1743
-
1744
-    /**
1745
-     * toggle Check-in status for this registration
1746
-     * Check-ins are toggled in the following order:
1747
-     * never checked in -> checked in
1748
-     * checked in -> checked out
1749
-     * checked out -> checked in
1750
-     *
1751
-     * @param int  $DTT_ID  include specific datetime to toggle Check-in for.
1752
-     *                      If not included or null, then it is assumed latest datetime is being toggled.
1753
-     * @param bool $verify  If true then can_checkin() is used to verify whether the person
1754
-     *                      can be checked in or not.  Otherwise this forces change in checkin status.
1755
-     * @return bool|int     the chk_in status toggled to OR false if nothing got changed.
1756
-     * @throws EE_Error
1757
-     * @throws InvalidArgumentException
1758
-     * @throws InvalidDataTypeException
1759
-     * @throws InvalidInterfaceException
1760
-     * @throws ReflectionException
1761
-     */
1762
-    public function toggle_checkin_status($DTT_ID = null, $verify = false)
1763
-    {
1764
-        if (empty($DTT_ID)) {
1765
-            $datetime = $this->get_latest_related_datetime();
1766
-            $DTT_ID   = $datetime instanceof EE_Datetime ? $datetime->ID() : 0;
1767
-            // verify the registration can checkin for the given DTT_ID
1768
-        } elseif (! $this->can_checkin($DTT_ID, $verify)) {
1769
-            EE_Error::add_error(
1770
-                sprintf(
1771
-                    esc_html__(
1772
-                        'The given registration (ID:%1$d) can not be checked in to the given DTT_ID (%2$d), because the registration does not have access',
1773
-                        'event_espresso'
1774
-                    ),
1775
-                    $this->ID(),
1776
-                    $DTT_ID
1777
-                ),
1778
-                __FILE__,
1779
-                __FUNCTION__,
1780
-                __LINE__
1781
-            );
1782
-            return false;
1783
-        }
1784
-        $status_paths = [
1785
-            EE_Checkin::status_checked_never => EE_Checkin::status_checked_in,
1786
-            EE_Checkin::status_checked_in    => EE_Checkin::status_checked_out,
1787
-            EE_Checkin::status_checked_out   => EE_Checkin::status_checked_in,
1788
-        ];
1789
-        // start by getting the current status so we know what status we'll be changing to.
1790
-        $cur_status = $this->check_in_status_for_datetime($DTT_ID);
1791
-        $status_to  = $status_paths[ $cur_status ];
1792
-        // database only records true for checked IN or false for checked OUT
1793
-        // no record ( null ) means checked in NEVER, but we obviously don't save that
1794
-        $new_status = $status_to === EE_Checkin::status_checked_in;
1795
-        // add relation - note Check-ins are always creating new rows
1796
-        // because we are keeping track of Check-ins over time.
1797
-        // Eventually we'll probably want to show a list table
1798
-        // for the individual Check-ins so that they can be managed.
1799
-        $checkin = EE_Checkin::new_instance(
1800
-            [
1801
-                'REG_ID' => $this->ID(),
1802
-                'DTT_ID' => $DTT_ID,
1803
-                'CHK_in' => $new_status,
1804
-            ]
1805
-        );
1806
-        // if the record could not be saved then return false
1807
-        if ($checkin->save() === 0) {
1808
-            if (WP_DEBUG) {
1809
-                global $wpdb;
1810
-                $error = sprintf(
1811
-                    esc_html__(
1812
-                        'Registration check in update failed because of the following database error: %1$s%2$s',
1813
-                        'event_espresso'
1814
-                    ),
1815
-                    '<br />',
1816
-                    $wpdb->last_error
1817
-                );
1818
-            } else {
1819
-                $error = esc_html__(
1820
-                    'Registration check in update failed because of an unknown database error',
1821
-                    'event_espresso'
1822
-                );
1823
-            }
1824
-            EE_Error::add_error($error, __FILE__, __FUNCTION__, __LINE__);
1825
-            return false;
1826
-        }
1827
-        // Fire a checked_in and checkout_out action.
1828
-        $checked_status = $status_to === EE_Checkin::status_checked_in
1829
-            ? 'checked_in'
1830
-            : 'checked_out';
1831
-        do_action("AHEE__EE_Registration__toggle_checkin_status__{$checked_status}", $this, $DTT_ID);
1832
-        return $status_to;
1833
-    }
1834
-
1835
-
1836
-    /**
1837
-     * Returns the latest datetime related to this registration (via the ticket attached to the registration).
1838
-     * "Latest" is defined by the `DTT_EVT_start` column.
1839
-     *
1840
-     * @return EE_Datetime|null
1841
-     * @throws EE_Error
1842
-     * @throws InvalidArgumentException
1843
-     * @throws InvalidDataTypeException
1844
-     * @throws InvalidInterfaceException
1845
-     * @throws ReflectionException
1846
-     */
1847
-    public function get_latest_related_datetime(): ?EE_Datetime
1848
-    {
1849
-        return EEM_Datetime::instance()->get_one(
1850
-            [
1851
-                [
1852
-                    'Ticket.Registration.REG_ID' => $this->ID(),
1853
-                ],
1854
-                'order_by' => ['DTT_EVT_start' => 'DESC'],
1855
-            ]
1856
-        );
1857
-    }
1858
-
1859
-
1860
-    /**
1861
-     * Returns the earliest datetime related to this registration (via the ticket attached to the registration).
1862
-     * "Earliest" is defined by the `DTT_EVT_start` column.
1863
-     *
1864
-     * @return EE_Base_Class|EE_Soft_Delete_Base_Class|NULL
1865
-     * @throws EE_Error
1866
-     * @throws InvalidArgumentException
1867
-     * @throws InvalidDataTypeException
1868
-     * @throws InvalidInterfaceException
1869
-     * @throws ReflectionException
1870
-     */
1871
-    public function get_earliest_related_datetime()
1872
-    {
1873
-        return EEM_Datetime::instance()->get_one(
1874
-            [
1875
-                [
1876
-                    'Ticket.Registration.REG_ID' => $this->ID(),
1877
-                ],
1878
-                'order_by' => ['DTT_EVT_start' => 'ASC'],
1879
-            ]
1880
-        );
1881
-    }
1882
-
1883
-
1884
-    /**
1885
-     * This method simply returns the check-in status for this registration and the given datetime.
1886
-     * If neither the datetime nor the checkin values are provided as arguments,
1887
-     * then this will return the LATEST check-in status for the registration across all datetimes it belongs to.
1888
-     *
1889
-     * @param int|null        $DTT_ID  The ID of the datetime we're checking against
1890
-     *                                 (if empty we'll get the primary datetime for
1891
-     *                                 this registration (via event) and use it's ID);
1892
-     * @param EE_Checkin|null $checkin If present, we use the given checkin object rather than the dtt_id.
1893
-     * @return int                     Integer representing Check-in status.
1894
-     * @throws EE_Error
1895
-     * @throws ReflectionException
1896
-     */
1897
-    public function check_in_status_for_datetime(?int $DTT_ID = 0, ?EE_Checkin $checkin = null): int
1898
-    {
1899
-        if ($checkin instanceof EE_Checkin) {
1900
-            return $checkin->status();
1901
-        }
1902
-
1903
-        if (! $DTT_ID) {
1904
-            return EE_Checkin::status_invalid;
1905
-        }
1906
-
1907
-        $checkin_query_params = [
1908
-            0          => ['DTT_ID' => $DTT_ID],
1909
-            'order_by' => ['CHK_timestamp' => 'DESC'],
1910
-        ];
1911
-
1912
-        $checkin = $this->get_first_related(
1913
-            'Checkin',
1914
-            $checkin_query_params
1915
-        );
1916
-        return $checkin instanceof EE_Checkin ? $checkin->status() : EE_Checkin::status_checked_never;
1917
-    }
1918
-
1919
-
1920
-    /**
1921
-     * This method returns a localized message for the toggled Check-in message.
1922
-     *
1923
-     * @param int|null $DTT_ID include specific datetime to get the correct Check-in message.  If not included or null,
1924
-     *                         then it is assumed Check-in for primary datetime was toggled.
1925
-     * @param bool     $error  This just flags that you want an error message returned. This is put in so that the error
1926
-     *                         message can be customized with the attendee name.
1927
-     * @return string internationalized message
1928
-     * @throws EE_Error
1929
-     * @throws ReflectionException
1930
-     */
1931
-    public function get_checkin_msg(?int $DTT_ID, bool $error = false): string
1932
-    {
1933
-        // let's get the attendee first so we can include the name of the attendee
1934
-        $attendee = $this->get_first_related('Attendee');
1935
-        if ($attendee instanceof EE_Attendee) {
1936
-            if ($error) {
1937
-                return sprintf(
1938
-                    esc_html__("%s's check-in status was not changed.", "event_espresso"),
1939
-                    $attendee->full_name()
1940
-                );
1941
-            }
1942
-            $cur_status = $this->check_in_status_for_datetime($DTT_ID);
1943
-            // what is the status message going to be?
1944
-            switch ($cur_status) {
1945
-                case EE_Checkin::status_checked_never:
1946
-                    return sprintf(
1947
-                        esc_html__('%s has been removed from Check-in records', 'event_espresso'),
1948
-                        $attendee->full_name()
1949
-                    );
1950
-                case EE_Checkin::status_checked_in:
1951
-                    return sprintf(esc_html__('%s has been checked in', 'event_espresso'), $attendee->full_name());
1952
-                case EE_Checkin::status_checked_out:
1953
-                    return sprintf(esc_html__('%s has been checked out', 'event_espresso'), $attendee->full_name());
1954
-            }
1955
-        }
1956
-        return esc_html__('The check-in status could not be determined.', 'event_espresso');
1957
-    }
1958
-
1959
-
1960
-    /**
1961
-     * Returns the related EE_Transaction to this registration
1962
-     *
1963
-     * @return EE_Transaction
1964
-     * @throws EE_Error
1965
-     * @throws EntityNotFoundException
1966
-     * @throws ReflectionException
1967
-     */
1968
-    public function transaction(): EE_Transaction
1969
-    {
1970
-        $transaction = $this->get_first_related('Transaction');
1971
-        if (! $transaction instanceof \EE_Transaction) {
1972
-            throw new EntityNotFoundException('Transaction ID', $this->transaction_ID());
1973
-        }
1974
-        return $transaction;
1975
-    }
1976
-
1977
-
1978
-    /**
1979
-     * get Registration Code
1980
-     *
1981
-     * @return string
1982
-     * @throws EE_Error
1983
-     * @throws InvalidArgumentException
1984
-     * @throws InvalidDataTypeException
1985
-     * @throws InvalidInterfaceException
1986
-     * @throws ReflectionException
1987
-     */
1988
-    public function reg_code(): string
1989
-    {
1990
-        return $this->get('REG_code')
1991
-            ?: '';
1992
-    }
1993
-
1994
-
1995
-    /**
1996
-     * @return mixed
1997
-     * @throws EE_Error
1998
-     * @throws InvalidArgumentException
1999
-     * @throws InvalidDataTypeException
2000
-     * @throws InvalidInterfaceException
2001
-     * @throws ReflectionException
2002
-     */
2003
-    public function transaction_ID()
2004
-    {
2005
-        return $this->get('TXN_ID');
2006
-    }
2007
-
2008
-
2009
-    /**
2010
-     * @return int
2011
-     * @throws EE_Error
2012
-     * @throws InvalidArgumentException
2013
-     * @throws InvalidDataTypeException
2014
-     * @throws InvalidInterfaceException
2015
-     * @throws ReflectionException
2016
-     */
2017
-    public function ticket_ID()
2018
-    {
2019
-        return $this->get('TKT_ID');
2020
-    }
2021
-
2022
-
2023
-    /**
2024
-     * Set Registration Code
2025
-     *
2026
-     * @param RegCode|string $REG_code Registration Code
2027
-     * @param boolean        $use_default
2028
-     * @throws EE_Error
2029
-     * @throws InvalidArgumentException
2030
-     * @throws InvalidDataTypeException
2031
-     * @throws InvalidInterfaceException
2032
-     * @throws ReflectionException
2033
-     */
2034
-    public function set_reg_code($REG_code, bool $use_default = false)
2035
-    {
2036
-        if (empty($REG_code)) {
2037
-            EE_Error::add_error(
2038
-                esc_html__('REG_code can not be empty.', 'event_espresso'),
2039
-                __FILE__,
2040
-                __FUNCTION__,
2041
-                __LINE__
2042
-            );
2043
-            return;
2044
-        }
2045
-        if (! $this->reg_code()) {
2046
-            parent::set('REG_code', $REG_code, $use_default);
2047
-        } else {
2048
-            EE_Error::doing_it_wrong(
2049
-                __CLASS__ . '::' . __FUNCTION__,
2050
-                esc_html__('Can not change a registration REG_code once it has been set.', 'event_espresso'),
2051
-                '4.6.0'
2052
-            );
2053
-        }
2054
-    }
2055
-
2056
-
2057
-    /**
2058
-     * Returns all other registrations in the same group as this registrant who have the same ticket option.
2059
-     * Note, if you want to just get all registrations in the same transaction (group), use:
2060
-     *    $registration->transaction()->registrations();
2061
-     *
2062
-     * @return EE_Registration[] or empty array if this isn't a group registration.
2063
-     * @throws EE_Error
2064
-     * @throws InvalidArgumentException
2065
-     * @throws InvalidDataTypeException
2066
-     * @throws InvalidInterfaceException
2067
-     * @throws ReflectionException
2068
-     * @since 4.5.0
2069
-     */
2070
-    public function get_all_other_registrations_in_group()
2071
-    {
2072
-        if ($this->group_size() < 2) {
2073
-            return [];
2074
-        }
2075
-
2076
-        $query[0] = [
2077
-            'TXN_ID' => $this->transaction_ID(),
2078
-            'REG_ID' => ['!=', $this->ID()],
2079
-            'TKT_ID' => $this->ticket_ID(),
2080
-        ];
2081
-        /** @var EE_Registration[] $registrations */
2082
-        $registrations = $this->get_model()->get_all($query);
2083
-        return $registrations;
2084
-    }
2085
-
2086
-
2087
-    /**
2088
-     * Return the link to the admin details for the object.
2089
-     *
2090
-     * @return string
2091
-     * @throws EE_Error
2092
-     * @throws InvalidArgumentException
2093
-     * @throws InvalidDataTypeException
2094
-     * @throws InvalidInterfaceException
2095
-     * @throws ReflectionException
2096
-     */
2097
-    public function get_admin_details_link()
2098
-    {
2099
-        EE_Registry::instance()->load_helper('URL');
2100
-        return EEH_URL::add_query_args_and_nonce(
2101
-            [
2102
-                'page'    => 'espresso_registrations',
2103
-                'action'  => 'view_registration',
2104
-                '_REG_ID' => $this->ID(),
2105
-            ],
2106
-            admin_url('admin.php')
2107
-        );
2108
-    }
2109
-
2110
-
2111
-    /**
2112
-     * Returns the link to the editor for the object.  Sometimes this is the same as the details.
2113
-     *
2114
-     * @return string
2115
-     * @throws EE_Error
2116
-     * @throws InvalidArgumentException
2117
-     * @throws InvalidDataTypeException
2118
-     * @throws InvalidInterfaceException
2119
-     * @throws ReflectionException
2120
-     */
2121
-    public function get_admin_edit_link()
2122
-    {
2123
-        return $this->get_admin_details_link();
2124
-    }
2125
-
2126
-
2127
-    /**
2128
-     * Returns the link to a settings page for the object.
2129
-     *
2130
-     * @return string
2131
-     * @throws EE_Error
2132
-     * @throws InvalidArgumentException
2133
-     * @throws InvalidDataTypeException
2134
-     * @throws InvalidInterfaceException
2135
-     * @throws ReflectionException
2136
-     */
2137
-    public function get_admin_settings_link()
2138
-    {
2139
-        return $this->get_admin_details_link();
2140
-    }
2141
-
2142
-
2143
-    /**
2144
-     * Returns the link to the "overview" for the object (typically the "list table" view).
2145
-     *
2146
-     * @return string
2147
-     * @throws EE_Error
2148
-     * @throws InvalidArgumentException
2149
-     * @throws InvalidDataTypeException
2150
-     * @throws InvalidInterfaceException
2151
-     * @throws ReflectionException
2152
-     */
2153
-    public function get_admin_overview_link()
2154
-    {
2155
-        EE_Registry::instance()->load_helper('URL');
2156
-        return EEH_URL::add_query_args_and_nonce(
2157
-            [
2158
-                'page' => 'espresso_registrations',
2159
-            ],
2160
-            admin_url('admin.php')
2161
-        );
2162
-    }
2163
-
2164
-
2165
-    /**
2166
-     * @param array $query_params
2167
-     * @return EE_Base_Class[]|EE_Registration[]
2168
-     * @throws EE_Error
2169
-     * @throws InvalidArgumentException
2170
-     * @throws InvalidDataTypeException
2171
-     * @throws InvalidInterfaceException
2172
-     * @throws ReflectionException
2173
-     */
2174
-    public function payments($query_params = [])
2175
-    {
2176
-        return $this->get_many_related('Payment', $query_params);
2177
-    }
2178
-
2179
-
2180
-    /**
2181
-     * @param array $query_params
2182
-     * @return EE_Base_Class[]|EE_Registration_Payment[]
2183
-     * @throws EE_Error
2184
-     * @throws InvalidArgumentException
2185
-     * @throws InvalidDataTypeException
2186
-     * @throws InvalidInterfaceException
2187
-     * @throws ReflectionException
2188
-     */
2189
-    public function registration_payments($query_params = [])
2190
-    {
2191
-        return $this->get_many_related('Registration_Payment', $query_params);
2192
-    }
2193
-
2194
-
2195
-    /**
2196
-     * This grabs the payment method corresponding to the last payment made for the amount owing on the registration.
2197
-     * Note: if there are no payments on the registration there will be no payment method returned.
2198
-     *
2199
-     * @return EE_Payment|EE_Payment_Method|null
2200
-     * @throws EE_Error
2201
-     * @throws InvalidArgumentException
2202
-     * @throws InvalidDataTypeException
2203
-     * @throws InvalidInterfaceException
2204
-     */
2205
-    public function payment_method()
2206
-    {
2207
-        return EEM_Payment_Method::instance()->get_last_used_for_registration($this);
2208
-    }
2209
-
2210
-
2211
-    /**
2212
-     * @return \EE_Line_Item
2213
-     * @throws EE_Error
2214
-     * @throws EntityNotFoundException
2215
-     * @throws InvalidArgumentException
2216
-     * @throws InvalidDataTypeException
2217
-     * @throws InvalidInterfaceException
2218
-     * @throws ReflectionException
2219
-     */
2220
-    public function ticket_line_item()
2221
-    {
2222
-        $ticket            = $this->ticket();
2223
-        $transaction       = $this->transaction();
2224
-        $line_item         = null;
2225
-        $ticket_line_items = \EEH_Line_Item::get_line_items_by_object_type_and_IDs(
2226
-            $transaction->total_line_item(),
2227
-            'Ticket',
2228
-            [$ticket->ID()]
2229
-        );
2230
-        foreach ($ticket_line_items as $ticket_line_item) {
2231
-            if (
2232
-                $ticket_line_item instanceof \EE_Line_Item
2233
-                && $ticket_line_item->OBJ_type() === 'Ticket'
2234
-                && $ticket_line_item->OBJ_ID() === $ticket->ID()
2235
-            ) {
2236
-                $line_item = $ticket_line_item;
2237
-                break;
2238
-            }
2239
-        }
2240
-        if (! ($line_item instanceof \EE_Line_Item && $line_item->OBJ_type() === 'Ticket')) {
2241
-            throw new EntityNotFoundException('Line Item Ticket ID', $ticket->ID());
2242
-        }
2243
-        return $line_item;
2244
-    }
2245
-
2246
-
2247
-    /**
2248
-     * Soft Deletes this model object.
2249
-     *
2250
-     * @param string $source function name that called this method
2251
-     * @return boolean | int
2252
-     * @throws DomainException
2253
-     * @throws EE_Error
2254
-     * @throws EntityNotFoundException
2255
-     * @throws InvalidArgumentException
2256
-     * @throws InvalidDataTypeException
2257
-     * @throws InvalidInterfaceException
2258
-     * @throws ReflectionException
2259
-     * @throws RuntimeException
2260
-     * @throws UnexpectedEntityException
2261
-     */
2262
-    public function delete()
2263
-    {
2264
-        if ($this->update_extra_meta(EE_Registration::PRE_TRASH_REG_STATUS_KEY, $this->status_ID()) === true) {
2265
-            $this->set_status(EEM_Registration::status_id_cancelled);
2266
-        }
2267
-        return parent::delete();
2268
-    }
2269
-
2270
-
2271
-    /**
2272
-     * Restores whatever the previous status was on a registration before it was trashed (if possible)
2273
-     *
2274
-     * @param string $source function name that called this method
2275
-     * @return bool|int
2276
-     * @throws DomainException
2277
-     * @throws EE_Error
2278
-     * @throws EntityNotFoundException
2279
-     * @throws InvalidArgumentException
2280
-     * @throws InvalidDataTypeException
2281
-     * @throws InvalidInterfaceException
2282
-     * @throws ReflectionException
2283
-     * @throws RuntimeException
2284
-     * @throws UnexpectedEntityException
2285
-     */
2286
-    public function restore()
2287
-    {
2288
-        $previous_status = $this->get_extra_meta(
2289
-            EE_Registration::PRE_TRASH_REG_STATUS_KEY,
2290
-            true,
2291
-            EEM_Registration::status_id_cancelled
2292
-        );
2293
-        if ($previous_status) {
2294
-            $this->delete_extra_meta(EE_Registration::PRE_TRASH_REG_STATUS_KEY);
2295
-            $this->set_status($previous_status);
2296
-        }
2297
-        return parent::restore();
2298
-    }
2299
-
2300
-
2301
-    /**
2302
-     * possibly toggle Registration status based on comparison of REG_paid vs REG_final_price
2303
-     *
2304
-     * @param boolean $trigger_set_status_logic  EE_Registration::set_status() can trigger additional logic
2305
-     *                                           depending on whether the reg status changes to or from "Approved"
2306
-     * @return boolean whether the Registration status was updated
2307
-     * @throws DomainException
2308
-     * @throws EE_Error
2309
-     * @throws EntityNotFoundException
2310
-     * @throws InvalidArgumentException
2311
-     * @throws InvalidDataTypeException
2312
-     * @throws InvalidInterfaceException
2313
-     * @throws ReflectionException
2314
-     * @throws RuntimeException
2315
-     * @throws UnexpectedEntityException
2316
-     */
2317
-    public function updateStatusBasedOnTotalPaid($trigger_set_status_logic = true)
2318
-    {
2319
-        $paid  = $this->paid();
2320
-        $price = $this->final_price();
2321
-        switch (true) {
2322
-            // overpaid or paid
2323
-            case EEH_Money::compare_floats($paid, $price, '>'):
2324
-            case EEH_Money::compare_floats($paid, $price):
2325
-                $new_status = EEM_Registration::status_id_approved;
2326
-                break;
2327
-            //  underpaid
2328
-            case EEH_Money::compare_floats($paid, $price, '<'):
2329
-                $new_status = EEM_Registration::status_id_pending_payment;
2330
-                break;
2331
-            // uhhh Houston...
2332
-            default:
2333
-                throw new RuntimeException(
2334
-                    esc_html__('The total paid calculation for this registration is inaccurate.', 'event_espresso')
2335
-                );
2336
-        }
2337
-        if ($new_status !== $this->status_ID()) {
2338
-            if ($trigger_set_status_logic) {
2339
-                return $this->set_status($new_status);
2340
-            }
2341
-            parent::set('STS_ID', $new_status);
2342
-            return true;
2343
-        }
2344
-        return false;
2345
-    }
2346
-
2347
-
2348
-    /*************************** DEPRECATED ***************************/
2349
-
2350
-
2351
-    /**
2352
-     * @deprecated
2353
-     * @since     4.7.0
2354
-     */
2355
-    public function price_paid()
2356
-    {
2357
-        EE_Error::doing_it_wrong(
2358
-            'EE_Registration::price_paid()',
2359
-            esc_html__(
2360
-                'This method is deprecated, please use EE_Registration::final_price() instead.',
2361
-                'event_espresso'
2362
-            ),
2363
-            '4.7.0'
2364
-        );
2365
-        return $this->final_price();
2366
-    }
2367
-
2368
-
2369
-    /**
2370
-     * @param float $REG_final_price
2371
-     * @throws EE_Error
2372
-     * @throws EntityNotFoundException
2373
-     * @throws InvalidArgumentException
2374
-     * @throws InvalidDataTypeException
2375
-     * @throws InvalidInterfaceException
2376
-     * @throws ReflectionException
2377
-     * @throws RuntimeException
2378
-     * @throws DomainException
2379
-     * @deprecated
2380
-     * @since     4.7.0
2381
-     */
2382
-    public function set_price_paid($REG_final_price = 0.00)
2383
-    {
2384
-        EE_Error::doing_it_wrong(
2385
-            'EE_Registration::set_price_paid()',
2386
-            esc_html__(
2387
-                'This method is deprecated, please use EE_Registration::set_final_price() instead.',
2388
-                'event_espresso'
2389
-            ),
2390
-            '4.7.0'
2391
-        );
2392
-        $this->set_final_price($REG_final_price);
2393
-    }
2394
-
2395
-
2396
-    /**
2397
-     * @return string
2398
-     * @throws EE_Error
2399
-     * @throws InvalidArgumentException
2400
-     * @throws InvalidDataTypeException
2401
-     * @throws InvalidInterfaceException
2402
-     * @throws ReflectionException
2403
-     * @deprecated
2404
-     * @since 4.7.0
2405
-     */
2406
-    public function pretty_price_paid()
2407
-    {
2408
-        EE_Error::doing_it_wrong(
2409
-            'EE_Registration::pretty_price_paid()',
2410
-            esc_html__(
2411
-                'This method is deprecated, please use EE_Registration::pretty_final_price() instead.',
2412
-                'event_espresso'
2413
-            ),
2414
-            '4.7.0'
2415
-        );
2416
-        return $this->pretty_final_price();
2417
-    }
2418
-
2419
-
2420
-    /**
2421
-     * Gets the primary datetime related to this registration via the related Event to this registration
2422
-     *
2423
-     * @return EE_Datetime
2424
-     * @throws EE_Error
2425
-     * @throws EntityNotFoundException
2426
-     * @throws InvalidArgumentException
2427
-     * @throws InvalidDataTypeException
2428
-     * @throws InvalidInterfaceException
2429
-     * @throws ReflectionException
2430
-     * @deprecated 4.9.17
2431
-     */
2432
-    public function get_related_primary_datetime()
2433
-    {
2434
-        EE_Error::doing_it_wrong(
2435
-            __METHOD__,
2436
-            esc_html__(
2437
-                'Use EE_Registration::get_latest_related_datetime() or EE_Registration::get_earliest_related_datetime()',
2438
-                'event_espresso'
2439
-            ),
2440
-            '4.9.17',
2441
-            '5.0.0'
2442
-        );
2443
-        return $this->event()->primary_datetime();
2444
-    }
2445
-
2446
-
2447
-    /**
2448
-     * Returns the contact's name (or "Unknown" if there is no contact.)
2449
-     *
2450
-     * @return string
2451
-     * @throws EE_Error
2452
-     * @throws InvalidArgumentException
2453
-     * @throws InvalidDataTypeException
2454
-     * @throws InvalidInterfaceException
2455
-     * @throws ReflectionException
2456
-     * @since 4.10.12.p
2457
-     */
2458
-    public function name()
2459
-    {
2460
-        return $this->attendeeName();
2461
-    }
2462
-
2463
-
2464
-    /**
2465
-     * @return bool
2466
-     * @throws EE_Error
2467
-     * @throws ReflectionException
2468
-     */
2469
-    public function wasMoved(): bool
2470
-    {
2471
-        // only need to check 'registration-moved-to' because
2472
-        // the existence of a new REG ID means the registration was moved
2473
-        $reg_moved = $this->get_extra_meta('registration-moved-to', true, []);
2474
-        return isset($reg_moved['NEW_REG_ID']) && $reg_moved['NEW_REG_ID'];
2475
-    }
2476
-
2477
-
2478
-    /**
2479
-     * @param EE_Payment $payment
2480
-     * @param float|null $amount
2481
-     * @return float
2482
-     * @throws EE_Error
2483
-     * @throws ReflectionException
2484
-     * @since 5.0.8.p
2485
-     */
2486
-    public function applyPayment(EE_Payment $payment, ?float $amount = null): float
2487
-    {
2488
-        // echo "\n\n";
2489
-        // \EEH_Debug_Tools::printr(__FUNCTION__, __CLASS__, __FILE__, __LINE__, 3);
2490
-        // \EEH_Debug_Tools::printr($this->ID(), 'REG ID', __FILE__, __LINE__);
2491
-        $payment_amount = $amount ?? $payment->amount();
2492
-        // ensure $payment_amount is NOT negative
2493
-        $payment_amount = (float) abs($payment_amount);
2494
-        // \EEH_Debug_Tools::printr($payment_amount, 'incoming $payment_amount', __FILE__, __LINE__);
2495
-        // \EEH_Debug_Tools::printr($this->final_price(), 'reg final price', __FILE__, __LINE__);
2496
-        // \EEH_Debug_Tools::printr($this->paid(), 'reg paid to date', __FILE__, __LINE__);
2497
-        $payment_amount = $payment->is_a_refund()
2498
-            ? $this->processRefund($payment_amount)
2499
-            : $this->processPayment($payment_amount);
2500
-        // \EEH_Debug_Tools::printr($payment_amount, 'applied payment_amount', __FILE__, __LINE__);
2501
-        if ($payment_amount) {
2502
-            $reg_payment = EEM_Registration_Payment::instance()->get_one(
2503
-                [['REG_ID' => $this->ID(), 'PAY_ID' => $payment->ID()]]
2504
-            );
2505
-            // if existing registration payment exists
2506
-            if ($reg_payment instanceof EE_Registration_Payment) {
2507
-                // echo "\nUPDATE EXISTING REG PAYMENT";
2508
-                // then update that record
2509
-                $reg_payment->set_amount($payment_amount);
2510
-            } else {
2511
-                // echo "\nCREATE NEW REG PAYMENT";
2512
-                // or add new relation between registration and payment and set amount
2513
-                $reg_payment = EE_Registration_Payment::new_instance(
2514
-                    [
2515
-                        'REG_ID'     => $this->ID(),
2516
-                        'PAY_ID'     => $payment->ID(),
2517
-                        'RPY_amount' => $payment_amount,
2518
-                    ]
2519
-                );
2520
-                // $this->_add_relation_to($payment, 'Payment', ['RPY_amount' => $payment_amount]);
2521
-            }
2522
-            $reg_payment->save();
2523
-            // \EEH_Debug_Tools::printr($reg_payment->ID(), '$reg payment ID', __FILE__, __LINE__);
2524
-        }
2525
-        return $payment_amount;
2526
-    }
2527
-
2528
-
2529
-    /**
2530
-     * @throws EE_Error
2531
-     * @throws ReflectionException
2532
-     */
2533
-    private function processPayment(float $payment_amount): float
2534
-    {
2535
-        // echo "\n";
2536
-        // \EEH_Debug_Tools::printr(__FUNCTION__, __CLASS__, __FILE__, __LINE__, 3);
2537
-        $paid  = $this->paid();
2538
-        $owing = $this->final_price() - $paid;
2539
-        // \EEH_Debug_Tools::printr($owing, '$owing', __FILE__, __LINE__);
2540
-        if ($owing <= 0) {
2541
-            return 0.0;
2542
-        }
2543
-        // don't allow payment amount to exceed the incoming amount, OR the amount owing
2544
-        $payment_amount = min($payment_amount, $owing);
2545
-        $paid           = $paid + $payment_amount;
2546
-        // \EEH_Debug_Tools::printr($paid, 'NEW REG PAID AMOUNT', __FILE__, __LINE__);
2547
-        // calculate and set new REG_paid
2548
-        $this->set_paid($paid);
2549
-        // make it stick
2550
-        $this->save();
2551
-        return (float) $payment_amount;
2552
-    }
2553
-
2554
-
2555
-    /**
2556
-     * @throws ReflectionException
2557
-     * @throws EE_Error
2558
-     */
2559
-    private function processRefund(float $payment_amount): float
2560
-    {
2561
-        // echo "\n";
2562
-        // \EEH_Debug_Tools::printr(__FUNCTION__, __CLASS__, __FILE__, __LINE__, 3);
2563
-        $paid = $this->paid();
2564
-        if ($paid <= 0) {
2565
-            return 0.0;
2566
-        }
2567
-        // don't allow refund amount to exceed the incoming amount, OR the amount paid
2568
-        $payment_amount = min($payment_amount, $paid);
2569
-        // calculate and set new REG_paid
2570
-        $paid = $paid - $payment_amount;
2571
-        // \EEH_Debug_Tools::printr($paid, 'NEW REG PAID AMOUNT', __FILE__, __LINE__);
2572
-        $this->set_paid($paid);
2573
-        // make it stick
2574
-        $this->save();
2575
-        // convert payment amount back to a negative value for storage in the db
2576
-        return (float) $payment_amount;
2577
-    }
20
+	/**
21
+	 * Used to reference when a registration has never been checked in.
22
+	 *
23
+	 * @deprecated use \EE_Checkin::status_checked_never instead
24
+	 * @type int
25
+	 */
26
+	const checkin_status_never = 2;
27
+
28
+	/**
29
+	 * Used to reference when a registration has been checked in.
30
+	 *
31
+	 * @deprecated use \EE_Checkin::status_checked_in instead
32
+	 * @type int
33
+	 */
34
+	const checkin_status_in = 1;
35
+
36
+	/**
37
+	 * Used to reference when a registration has been checked out.
38
+	 *
39
+	 * @deprecated use \EE_Checkin::status_checked_out instead
40
+	 * @type int
41
+	 */
42
+	const checkin_status_out = 0;
43
+
44
+	/**
45
+	 * extra meta key for tracking reg status os trashed registrations
46
+	 *
47
+	 * @type string
48
+	 */
49
+	const PRE_TRASH_REG_STATUS_KEY = 'pre_trash_registration_status';
50
+
51
+	/**
52
+	 * extra meta key for tracking if registration has reserved ticket
53
+	 *
54
+	 * @type string
55
+	 */
56
+	const HAS_RESERVED_TICKET_KEY = 'has_reserved_ticket';
57
+
58
+
59
+	/**
60
+	 * @param array  $props_n_values          incoming values
61
+	 * @param string $timezone                incoming timezone (if not set the timezone set for the website will be
62
+	 *                                        used.)
63
+	 * @param array  $date_formats            incoming date_formats in an array where the first value is the
64
+	 *                                        date_format and the second value is the time format
65
+	 * @return EE_Registration
66
+	 * @throws EE_Error
67
+	 * @throws InvalidArgumentException
68
+	 * @throws InvalidDataTypeException
69
+	 * @throws InvalidInterfaceException
70
+	 * @throws ReflectionException
71
+	 */
72
+	public static function new_instance($props_n_values = [], $timezone = '', $date_formats = [])
73
+	{
74
+		$has_object = parent::_check_for_object($props_n_values, __CLASS__, $timezone, $date_formats);
75
+		return $has_object
76
+			?: new self($props_n_values, false, $timezone, $date_formats);
77
+	}
78
+
79
+
80
+	/**
81
+	 * @param array  $props_n_values  incoming values from the database
82
+	 * @param string $timezone        incoming timezone as set by the model.  If not set the timezone for
83
+	 *                                the website will be used.
84
+	 * @return EE_Registration
85
+	 * @throws EE_Error
86
+	 * @throws InvalidArgumentException
87
+	 * @throws InvalidDataTypeException
88
+	 * @throws InvalidInterfaceException
89
+	 * @throws ReflectionException
90
+	 */
91
+	public static function new_instance_from_db($props_n_values = [], $timezone = '')
92
+	{
93
+		return new self($props_n_values, true, $timezone);
94
+	}
95
+
96
+
97
+	/**
98
+	 *        Set Event ID
99
+	 *
100
+	 * @param int $EVT_ID Event ID
101
+	 * @throws DomainException
102
+	 * @throws EE_Error
103
+	 * @throws EntityNotFoundException
104
+	 * @throws InvalidArgumentException
105
+	 * @throws InvalidDataTypeException
106
+	 * @throws InvalidInterfaceException
107
+	 * @throws ReflectionException
108
+	 * @throws RuntimeException
109
+	 * @throws UnexpectedEntityException
110
+	 */
111
+	public function set_event($EVT_ID = 0)
112
+	{
113
+		$this->set('EVT_ID', $EVT_ID);
114
+	}
115
+
116
+
117
+	/**
118
+	 * Overrides parent set() method so that all calls to set( 'REG_code', $REG_code ) OR set( 'STS_ID', $STS_ID ) can
119
+	 * be routed to internal methods
120
+	 *
121
+	 * @param string $field_name
122
+	 * @param mixed  $field_value
123
+	 * @param bool   $use_default
124
+	 * @throws DomainException
125
+	 * @throws EE_Error
126
+	 * @throws EntityNotFoundException
127
+	 * @throws InvalidArgumentException
128
+	 * @throws InvalidDataTypeException
129
+	 * @throws InvalidInterfaceException
130
+	 * @throws ReflectionException
131
+	 * @throws RuntimeException
132
+	 * @throws UnexpectedEntityException
133
+	 */
134
+	public function set($field_name, $field_value, $use_default = false)
135
+	{
136
+		switch ($field_name) {
137
+			case 'REG_code':
138
+				if (! empty($field_value) && ! $this->reg_code()) {
139
+					$this->set_reg_code($field_value, $use_default);
140
+				}
141
+				break;
142
+			case 'STS_ID':
143
+				$this->set_status($field_value, $use_default);
144
+				break;
145
+			default:
146
+				parent::set($field_name, $field_value, $use_default);
147
+		}
148
+	}
149
+
150
+
151
+	/**
152
+	 * Set Status ID
153
+	 * updates the registration status and ALSO...
154
+	 * calls reserve_registration_space() if the reg status changes TO approved from any other reg status
155
+	 * calls release_registration_space() if the reg status changes FROM approved to any other reg status
156
+	 *
157
+	 * @param string                $new_STS_ID
158
+	 * @param boolean               $use_default
159
+	 * @param ContextInterface|null $context
160
+	 * @return bool
161
+	 * @throws DomainException
162
+	 * @throws EE_Error
163
+	 * @throws EntityNotFoundException
164
+	 * @throws InvalidArgumentException
165
+	 * @throws InvalidDataTypeException
166
+	 * @throws InvalidInterfaceException
167
+	 * @throws ReflectionException
168
+	 * @throws RuntimeException
169
+	 * @throws UnexpectedEntityException
170
+	 */
171
+	public function set_status($new_STS_ID = null, $use_default = false, ContextInterface $context = null)
172
+	{
173
+		// get current REG_Status
174
+		$old_STS_ID = $this->status_ID();
175
+		// if status has changed
176
+		if (
177
+			$old_STS_ID !== $new_STS_ID // and that status has actually changed
178
+			&& ! empty($old_STS_ID) // and that old status is actually set
179
+			&& ! empty($new_STS_ID) // as well as the new status
180
+			&& $this->ID() // ensure registration is in the db
181
+		) {
182
+			// update internal status first
183
+			parent::set('STS_ID', $new_STS_ID, $use_default);
184
+			// THEN handle other changes that occur when reg status changes
185
+			// TO approved
186
+			if ($new_STS_ID === EEM_Registration::status_id_approved) {
187
+				// reserve a space by incrementing ticket and datetime sold values
188
+				$this->reserveRegistrationSpace();
189
+				do_action('AHEE__EE_Registration__set_status__to_approved', $this, $old_STS_ID, $new_STS_ID, $context);
190
+				// OR FROM  approved
191
+			} elseif ($old_STS_ID === EEM_Registration::status_id_approved) {
192
+				// release a space by decrementing ticket and datetime sold values
193
+				$this->releaseRegistrationSpace();
194
+				do_action(
195
+					'AHEE__EE_Registration__set_status__from_approved',
196
+					$this,
197
+					$old_STS_ID,
198
+					$new_STS_ID,
199
+					$context
200
+				);
201
+			}
202
+			// update status
203
+			parent::set('STS_ID', $new_STS_ID, $use_default);
204
+			$this->updateIfCanceledOrReinstated($new_STS_ID, $old_STS_ID, $context);
205
+			if ($this->statusChangeUpdatesTransaction($context)) {
206
+				$this->updateTransactionAfterStatusChange();
207
+			}
208
+			do_action('AHEE__EE_Registration__set_status__after_update', $this, $old_STS_ID, $new_STS_ID, $context);
209
+			return true;
210
+		}
211
+		// even though the old value matches the new value, it's still good to
212
+		// allow the parent set method to have a say
213
+		parent::set('STS_ID', $new_STS_ID, $use_default);
214
+		return true;
215
+	}
216
+
217
+
218
+	/**
219
+	 * update REGs and TXN when cancelled or declined registrations involved
220
+	 *
221
+	 * @param string                $new_STS_ID
222
+	 * @param string                $old_STS_ID
223
+	 * @param ContextInterface|null $context
224
+	 * @throws EE_Error
225
+	 * @throws InvalidArgumentException
226
+	 * @throws InvalidDataTypeException
227
+	 * @throws InvalidInterfaceException
228
+	 * @throws ReflectionException
229
+	 * @throws RuntimeException
230
+	 */
231
+	private function updateIfCanceledOrReinstated($new_STS_ID, $old_STS_ID, ContextInterface $context = null)
232
+	{
233
+		// these reg statuses should not be considered in any calculations involving monies owing
234
+		$closed_reg_statuses = EEM_Registration::closed_reg_statuses();
235
+		// true if registration has been cancelled or declined
236
+		$this->updateIfCanceled(
237
+			$closed_reg_statuses,
238
+			$new_STS_ID,
239
+			$old_STS_ID,
240
+			$context
241
+		);
242
+		$this->updateIfReinstated(
243
+			$closed_reg_statuses,
244
+			$new_STS_ID,
245
+			$old_STS_ID,
246
+			$context
247
+		);
248
+	}
249
+
250
+
251
+	/**
252
+	 * update REGs and TXN when cancelled or declined registrations involved
253
+	 *
254
+	 * @param array                 $closed_reg_statuses
255
+	 * @param string                $new_STS_ID
256
+	 * @param string                $old_STS_ID
257
+	 * @param ContextInterface|null $context
258
+	 * @throws EE_Error
259
+	 * @throws InvalidArgumentException
260
+	 * @throws InvalidDataTypeException
261
+	 * @throws InvalidInterfaceException
262
+	 * @throws ReflectionException
263
+	 * @throws RuntimeException
264
+	 */
265
+	private function updateIfCanceled(
266
+		array $closed_reg_statuses,
267
+		$new_STS_ID,
268
+		$old_STS_ID,
269
+		ContextInterface $context = null
270
+	) {
271
+		// true if registration has been cancelled or declined
272
+		if (
273
+			in_array($new_STS_ID, $closed_reg_statuses, true)
274
+			&& ! in_array($old_STS_ID, $closed_reg_statuses, true)
275
+		) {
276
+			/** @type EE_Registration_Processor $registration_processor */
277
+			$registration_processor = EE_Registry::instance()->load_class('Registration_Processor');
278
+			/** @type EE_Transaction_Processor $transaction_processor */
279
+			$transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor');
280
+			// cancelled or declined registration
281
+			$registration_processor->update_registration_after_being_canceled_or_declined(
282
+				$this,
283
+				$closed_reg_statuses
284
+			);
285
+			$transaction_processor->update_transaction_after_canceled_or_declined_registration(
286
+				$this,
287
+				$closed_reg_statuses,
288
+				false
289
+			);
290
+			do_action(
291
+				'AHEE__EE_Registration__set_status__canceled_or_declined',
292
+				$this,
293
+				$old_STS_ID,
294
+				$new_STS_ID,
295
+				$context
296
+			);
297
+			return;
298
+		}
299
+	}
300
+
301
+
302
+	/**
303
+	 * update REGs and TXN when cancelled or declined registrations involved
304
+	 *
305
+	 * @param array                 $closed_reg_statuses
306
+	 * @param string                $new_STS_ID
307
+	 * @param string                $old_STS_ID
308
+	 * @param ContextInterface|null $context
309
+	 * @throws EE_Error
310
+	 * @throws InvalidArgumentException
311
+	 * @throws InvalidDataTypeException
312
+	 * @throws InvalidInterfaceException
313
+	 * @throws ReflectionException
314
+	 * @throws RuntimeException
315
+	 */
316
+	private function updateIfReinstated(
317
+		array $closed_reg_statuses,
318
+		$new_STS_ID,
319
+		$old_STS_ID,
320
+		ContextInterface $context = null
321
+	) {
322
+		// true if reinstating cancelled or declined registration
323
+		if (
324
+			in_array($old_STS_ID, $closed_reg_statuses, true)
325
+			&& ! in_array($new_STS_ID, $closed_reg_statuses, true)
326
+		) {
327
+			/** @type EE_Registration_Processor $registration_processor */
328
+			$registration_processor = EE_Registry::instance()->load_class('Registration_Processor');
329
+			/** @type EE_Transaction_Processor $transaction_processor */
330
+			$transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor');
331
+			// reinstating cancelled or declined registration
332
+			$registration_processor->update_canceled_or_declined_registration_after_being_reinstated(
333
+				$this,
334
+				$closed_reg_statuses
335
+			);
336
+			$transaction_processor->update_transaction_after_reinstating_canceled_registration(
337
+				$this,
338
+				$closed_reg_statuses,
339
+				false
340
+			);
341
+			do_action(
342
+				'AHEE__EE_Registration__set_status__after_reinstated',
343
+				$this,
344
+				$old_STS_ID,
345
+				$new_STS_ID,
346
+				$context
347
+			);
348
+		}
349
+	}
350
+
351
+
352
+	/**
353
+	 * @param ContextInterface|null $context
354
+	 * @return bool
355
+	 */
356
+	private function statusChangeUpdatesTransaction(ContextInterface $context = null)
357
+	{
358
+		$contexts_that_do_not_update_transaction = (array) apply_filters(
359
+			'AHEE__EE_Registration__statusChangeUpdatesTransaction__contexts_that_do_not_update_transaction',
360
+			['spco_reg_step_attendee_information_process_registrations'],
361
+			$context,
362
+			$this
363
+		);
364
+		return ! (
365
+			$context instanceof ContextInterface
366
+			&& in_array($context->slug(), $contexts_that_do_not_update_transaction, true)
367
+		);
368
+	}
369
+
370
+
371
+	/**
372
+	 * @throws EE_Error
373
+	 * @throws EntityNotFoundException
374
+	 * @throws InvalidArgumentException
375
+	 * @throws InvalidDataTypeException
376
+	 * @throws InvalidInterfaceException
377
+	 * @throws ReflectionException
378
+	 * @throws RuntimeException
379
+	 */
380
+	private function updateTransactionAfterStatusChange()
381
+	{
382
+		/** @type EE_Transaction_Payments $transaction_payments */
383
+		$transaction_payments = EE_Registry::instance()->load_class('Transaction_Payments');
384
+		$transaction_payments->recalculate_transaction_total($this->transaction(), false);
385
+		$this->transaction()->update_status_based_on_total_paid();
386
+	}
387
+
388
+
389
+	/**
390
+	 * get Status ID
391
+	 *
392
+	 * @throws EE_Error
393
+	 * @throws InvalidArgumentException
394
+	 * @throws InvalidDataTypeException
395
+	 * @throws InvalidInterfaceException
396
+	 * @throws ReflectionException
397
+	 */
398
+	public function status_ID()
399
+	{
400
+		return $this->get('STS_ID');
401
+	}
402
+
403
+
404
+	/**
405
+	 * Gets the ticket this registration is for
406
+	 *
407
+	 * @param boolean $include_archived whether to include archived tickets or not.
408
+	 * @return EE_Ticket|EE_Base_Class
409
+	 * @throws EE_Error
410
+	 * @throws InvalidArgumentException
411
+	 * @throws InvalidDataTypeException
412
+	 * @throws InvalidInterfaceException
413
+	 * @throws ReflectionException
414
+	 */
415
+	public function ticket($include_archived = true)
416
+	{
417
+		$query_params = [];
418
+		if ($include_archived) {
419
+			$query_params['default_where_conditions'] = 'none';
420
+		}
421
+		return $this->get_first_related('Ticket', $query_params);
422
+	}
423
+
424
+
425
+	/**
426
+	 * Gets the event this registration is for
427
+	 *
428
+	 * @return EE_Event
429
+	 * @throws EE_Error
430
+	 * @throws EntityNotFoundException
431
+	 * @throws InvalidArgumentException
432
+	 * @throws InvalidDataTypeException
433
+	 * @throws InvalidInterfaceException
434
+	 * @throws ReflectionException
435
+	 */
436
+	public function event(): EE_Event
437
+	{
438
+		$event = $this->get_first_related('Event');
439
+		if (! $event instanceof EE_Event) {
440
+			throw new EntityNotFoundException('Event ID', $this->event_ID());
441
+		}
442
+		return $event;
443
+	}
444
+
445
+
446
+	/**
447
+	 * Gets the "author" of the registration.  Note that for the purposes of registrations, the author will correspond
448
+	 * with the author of the event this registration is for.
449
+	 *
450
+	 * @return int
451
+	 * @throws EE_Error
452
+	 * @throws EntityNotFoundException
453
+	 * @throws InvalidArgumentException
454
+	 * @throws InvalidDataTypeException
455
+	 * @throws InvalidInterfaceException
456
+	 * @throws ReflectionException
457
+	 * @since 4.5.0
458
+	 */
459
+	public function wp_user(): int
460
+	{
461
+		return $this->event()->wp_user();
462
+	}
463
+
464
+
465
+	/**
466
+	 * increments this registration's related ticket sold and corresponding datetime sold values
467
+	 *
468
+	 * @return void
469
+	 * @throws DomainException
470
+	 * @throws EE_Error
471
+	 * @throws EntityNotFoundException
472
+	 * @throws InvalidArgumentException
473
+	 * @throws InvalidDataTypeException
474
+	 * @throws InvalidInterfaceException
475
+	 * @throws ReflectionException
476
+	 * @throws UnexpectedEntityException
477
+	 */
478
+	private function reserveRegistrationSpace()
479
+	{
480
+		// reserved ticket and datetime counts will be decremented as sold counts are incremented
481
+		// so stop tracking that this reg has a ticket reserved
482
+		$this->release_reserved_ticket(false, "REG: {$this->ID()} (ln:" . __LINE__ . ')');
483
+		$ticket = $this->ticket();
484
+		$ticket->increaseSold();
485
+		// possibly set event status to sold out
486
+		$this->event()->perform_sold_out_status_check();
487
+	}
488
+
489
+
490
+	/**
491
+	 * decrements (subtracts) this registration's related ticket sold and corresponding datetime sold values
492
+	 *
493
+	 * @return void
494
+	 * @throws DomainException
495
+	 * @throws EE_Error
496
+	 * @throws EntityNotFoundException
497
+	 * @throws InvalidArgumentException
498
+	 * @throws InvalidDataTypeException
499
+	 * @throws InvalidInterfaceException
500
+	 * @throws ReflectionException
501
+	 * @throws UnexpectedEntityException
502
+	 */
503
+	private function releaseRegistrationSpace()
504
+	{
505
+		$ticket = $this->ticket();
506
+		$ticket->decreaseSold();
507
+		// possibly change event status from sold out back to previous status
508
+		$this->event()->perform_sold_out_status_check();
509
+	}
510
+
511
+
512
+	/**
513
+	 * tracks this registration's ticket reservation in extra meta
514
+	 * and can increment related ticket reserved and corresponding datetime reserved values
515
+	 *
516
+	 * @param bool   $update_ticket if true, will increment ticket and datetime reserved count
517
+	 * @param string $source
518
+	 * @return void
519
+	 * @throws EE_Error
520
+	 * @throws InvalidArgumentException
521
+	 * @throws InvalidDataTypeException
522
+	 * @throws InvalidInterfaceException
523
+	 * @throws ReflectionException
524
+	 */
525
+	public function reserve_ticket($update_ticket = false, $source = 'unknown')
526
+	{
527
+		// only reserve ticket if space is not currently reserved
528
+		if ((bool) $this->get_extra_meta(EE_Registration::HAS_RESERVED_TICKET_KEY, true) !== true) {
529
+			$reserved = $this->update_extra_meta(EE_Registration::HAS_RESERVED_TICKET_KEY, true);
530
+			if ($reserved && $update_ticket) {
531
+				$ticket = $this->ticket();
532
+				$ticket->increaseReserved(1, "REG: {$this->ID()} (ln:" . __LINE__ . ')');
533
+				$this->update_extra_meta('reserve_ticket', "{$this->ticket_ID()} from {$source}");
534
+				$ticket->save();
535
+			}
536
+		}
537
+	}
538
+
539
+
540
+	/**
541
+	 * stops tracking this registration's ticket reservation in extra meta
542
+	 * decrements (subtracts) related ticket reserved and corresponding datetime reserved values
543
+	 *
544
+	 * @param bool   $update_ticket if true, will decrement ticket and datetime reserved count
545
+	 * @param string $source
546
+	 * @return void
547
+	 * @throws EE_Error
548
+	 * @throws InvalidArgumentException
549
+	 * @throws InvalidDataTypeException
550
+	 * @throws InvalidInterfaceException
551
+	 * @throws ReflectionException
552
+	 */
553
+	public function release_reserved_ticket($update_ticket = false, $source = 'unknown')
554
+	{
555
+		// only release ticket if space is currently reserved
556
+		if ((bool) $this->get_extra_meta(EE_Registration::HAS_RESERVED_TICKET_KEY, true) === true) {
557
+			$reserved = $this->update_extra_meta(EE_Registration::HAS_RESERVED_TICKET_KEY, false);
558
+			if ($reserved && $update_ticket) {
559
+				$ticket = $this->ticket();
560
+				$ticket->decreaseReserved(1, true, "REG: {$this->ID()} (ln:" . __LINE__ . ')');
561
+				$this->update_extra_meta('release_reserved_ticket', "{$this->ticket_ID()} from {$source}");
562
+			}
563
+		}
564
+	}
565
+
566
+
567
+	/**
568
+	 * Set Attendee ID
569
+	 *
570
+	 * @param int $ATT_ID Attendee ID
571
+	 * @throws DomainException
572
+	 * @throws EE_Error
573
+	 * @throws EntityNotFoundException
574
+	 * @throws InvalidArgumentException
575
+	 * @throws InvalidDataTypeException
576
+	 * @throws InvalidInterfaceException
577
+	 * @throws ReflectionException
578
+	 * @throws RuntimeException
579
+	 * @throws UnexpectedEntityException
580
+	 */
581
+	public function set_attendee_id($ATT_ID = 0)
582
+	{
583
+		$this->set('ATT_ID', $ATT_ID);
584
+	}
585
+
586
+
587
+	/**
588
+	 *        Set Transaction ID
589
+	 *
590
+	 * @param int $TXN_ID Transaction ID
591
+	 * @throws DomainException
592
+	 * @throws EE_Error
593
+	 * @throws EntityNotFoundException
594
+	 * @throws InvalidArgumentException
595
+	 * @throws InvalidDataTypeException
596
+	 * @throws InvalidInterfaceException
597
+	 * @throws ReflectionException
598
+	 * @throws RuntimeException
599
+	 * @throws UnexpectedEntityException
600
+	 */
601
+	public function set_transaction_id($TXN_ID = 0)
602
+	{
603
+		$this->set('TXN_ID', $TXN_ID);
604
+	}
605
+
606
+
607
+	/**
608
+	 *        Set Session
609
+	 *
610
+	 * @param string $REG_session PHP Session ID
611
+	 * @throws DomainException
612
+	 * @throws EE_Error
613
+	 * @throws EntityNotFoundException
614
+	 * @throws InvalidArgumentException
615
+	 * @throws InvalidDataTypeException
616
+	 * @throws InvalidInterfaceException
617
+	 * @throws ReflectionException
618
+	 * @throws RuntimeException
619
+	 * @throws UnexpectedEntityException
620
+	 */
621
+	public function set_session($REG_session = '')
622
+	{
623
+		$this->set('REG_session', $REG_session);
624
+	}
625
+
626
+
627
+	/**
628
+	 *        Set Registration URL Link
629
+	 *
630
+	 * @param string $REG_url_link Registration URL Link
631
+	 * @throws DomainException
632
+	 * @throws EE_Error
633
+	 * @throws EntityNotFoundException
634
+	 * @throws InvalidArgumentException
635
+	 * @throws InvalidDataTypeException
636
+	 * @throws InvalidInterfaceException
637
+	 * @throws ReflectionException
638
+	 * @throws RuntimeException
639
+	 * @throws UnexpectedEntityException
640
+	 */
641
+	public function set_reg_url_link($REG_url_link = '')
642
+	{
643
+		$this->set('REG_url_link', $REG_url_link);
644
+	}
645
+
646
+
647
+	/**
648
+	 *        Set Attendee Counter
649
+	 *
650
+	 * @param int $REG_count Primary Attendee
651
+	 * @throws DomainException
652
+	 * @throws EE_Error
653
+	 * @throws EntityNotFoundException
654
+	 * @throws InvalidArgumentException
655
+	 * @throws InvalidDataTypeException
656
+	 * @throws InvalidInterfaceException
657
+	 * @throws ReflectionException
658
+	 * @throws RuntimeException
659
+	 * @throws UnexpectedEntityException
660
+	 */
661
+	public function set_count($REG_count = 1)
662
+	{
663
+		$this->set('REG_count', $REG_count);
664
+	}
665
+
666
+
667
+	/**
668
+	 *        Set Group Size
669
+	 *
670
+	 * @param boolean $REG_group_size Group Registration
671
+	 * @throws DomainException
672
+	 * @throws EE_Error
673
+	 * @throws EntityNotFoundException
674
+	 * @throws InvalidArgumentException
675
+	 * @throws InvalidDataTypeException
676
+	 * @throws InvalidInterfaceException
677
+	 * @throws ReflectionException
678
+	 * @throws RuntimeException
679
+	 * @throws UnexpectedEntityException
680
+	 */
681
+	public function set_group_size($REG_group_size = false)
682
+	{
683
+		$this->set('REG_group_size', $REG_group_size);
684
+	}
685
+
686
+
687
+	/**
688
+	 *    is_not_approved -  convenience method that returns TRUE if REG status ID ==
689
+	 *    EEM_Registration::status_id_not_approved
690
+	 *
691
+	 * @return        boolean
692
+	 * @throws EE_Error
693
+	 * @throws InvalidArgumentException
694
+	 * @throws InvalidDataTypeException
695
+	 * @throws InvalidInterfaceException
696
+	 * @throws ReflectionException
697
+	 */
698
+	public function is_not_approved()
699
+	{
700
+		return $this->status_ID() === EEM_Registration::status_id_not_approved;
701
+	}
702
+
703
+
704
+	/**
705
+	 *    is_pending_payment -  convenience method that returns TRUE if REG status ID ==
706
+	 *    EEM_Registration::status_id_pending_payment
707
+	 *
708
+	 * @return        boolean
709
+	 * @throws EE_Error
710
+	 * @throws InvalidArgumentException
711
+	 * @throws InvalidDataTypeException
712
+	 * @throws InvalidInterfaceException
713
+	 * @throws ReflectionException
714
+	 */
715
+	public function is_pending_payment()
716
+	{
717
+		return $this->status_ID() === EEM_Registration::status_id_pending_payment;
718
+	}
719
+
720
+
721
+	/**
722
+	 *    is_approved -  convenience method that returns TRUE if REG status ID == EEM_Registration::status_id_approved
723
+	 *
724
+	 * @return        boolean
725
+	 * @throws EE_Error
726
+	 * @throws InvalidArgumentException
727
+	 * @throws InvalidDataTypeException
728
+	 * @throws InvalidInterfaceException
729
+	 * @throws ReflectionException
730
+	 */
731
+	public function is_approved()
732
+	{
733
+		return $this->status_ID() === EEM_Registration::status_id_approved;
734
+	}
735
+
736
+
737
+	/**
738
+	 *    is_cancelled -  convenience method that returns TRUE if REG status ID == EEM_Registration::status_id_cancelled
739
+	 *
740
+	 * @return        boolean
741
+	 * @throws EE_Error
742
+	 * @throws InvalidArgumentException
743
+	 * @throws InvalidDataTypeException
744
+	 * @throws InvalidInterfaceException
745
+	 * @throws ReflectionException
746
+	 */
747
+	public function is_cancelled()
748
+	{
749
+		return $this->status_ID() === EEM_Registration::status_id_cancelled;
750
+	}
751
+
752
+
753
+	/**
754
+	 *    is_declined -  convenience method that returns TRUE if REG status ID == EEM_Registration::status_id_declined
755
+	 *
756
+	 * @return        boolean
757
+	 * @throws EE_Error
758
+	 * @throws InvalidArgumentException
759
+	 * @throws InvalidDataTypeException
760
+	 * @throws InvalidInterfaceException
761
+	 * @throws ReflectionException
762
+	 */
763
+	public function is_declined()
764
+	{
765
+		return $this->status_ID() === EEM_Registration::status_id_declined;
766
+	}
767
+
768
+
769
+	/**
770
+	 *    is_incomplete -  convenience method that returns TRUE if REG status ID ==
771
+	 *    EEM_Registration::status_id_incomplete
772
+	 *
773
+	 * @return        boolean
774
+	 * @throws EE_Error
775
+	 * @throws InvalidArgumentException
776
+	 * @throws InvalidDataTypeException
777
+	 * @throws InvalidInterfaceException
778
+	 * @throws ReflectionException
779
+	 */
780
+	public function is_incomplete()
781
+	{
782
+		return $this->status_ID() === EEM_Registration::status_id_incomplete;
783
+	}
784
+
785
+
786
+	/**
787
+	 *        Set Registration Date
788
+	 *
789
+	 * @param mixed ( int or string ) $REG_date Registration Date - Unix timestamp or string representation of
790
+	 *                                                 Date
791
+	 * @throws DomainException
792
+	 * @throws EE_Error
793
+	 * @throws EntityNotFoundException
794
+	 * @throws InvalidArgumentException
795
+	 * @throws InvalidDataTypeException
796
+	 * @throws InvalidInterfaceException
797
+	 * @throws ReflectionException
798
+	 * @throws RuntimeException
799
+	 * @throws UnexpectedEntityException
800
+	 */
801
+	public function set_reg_date($REG_date = false)
802
+	{
803
+		$this->set('REG_date', $REG_date);
804
+	}
805
+
806
+
807
+	/**
808
+	 *    Set final price owing for this registration after all ticket/price modifications
809
+	 *
810
+	 * @param float $REG_final_price
811
+	 * @throws DomainException
812
+	 * @throws EE_Error
813
+	 * @throws EntityNotFoundException
814
+	 * @throws InvalidArgumentException
815
+	 * @throws InvalidDataTypeException
816
+	 * @throws InvalidInterfaceException
817
+	 * @throws ReflectionException
818
+	 * @throws RuntimeException
819
+	 * @throws UnexpectedEntityException
820
+	 */
821
+	public function set_final_price($REG_final_price = 0.00)
822
+	{
823
+		$this->set('REG_final_price', $REG_final_price);
824
+	}
825
+
826
+
827
+	/**
828
+	 *    Set amount paid towards this registration's final price
829
+	 *
830
+	 * @param float|int|string $REG_paid
831
+	 * @throws DomainException
832
+	 * @throws EE_Error
833
+	 * @throws EntityNotFoundException
834
+	 * @throws InvalidArgumentException
835
+	 * @throws InvalidDataTypeException
836
+	 * @throws InvalidInterfaceException
837
+	 * @throws ReflectionException
838
+	 * @throws RuntimeException
839
+	 * @throws UnexpectedEntityException
840
+	 */
841
+	public function set_paid($REG_paid = 0.00)
842
+	{
843
+		$this->set('REG_paid', (float) $REG_paid);
844
+	}
845
+
846
+
847
+	/**
848
+	 *        Attendee Is Going
849
+	 *
850
+	 * @param boolean $REG_att_is_going Attendee Is Going
851
+	 * @throws DomainException
852
+	 * @throws EE_Error
853
+	 * @throws EntityNotFoundException
854
+	 * @throws InvalidArgumentException
855
+	 * @throws InvalidDataTypeException
856
+	 * @throws InvalidInterfaceException
857
+	 * @throws ReflectionException
858
+	 * @throws RuntimeException
859
+	 * @throws UnexpectedEntityException
860
+	 */
861
+	public function set_att_is_going($REG_att_is_going = false)
862
+	{
863
+		$this->set('REG_att_is_going', $REG_att_is_going);
864
+	}
865
+
866
+
867
+	/**
868
+	 * Gets the related attendee
869
+	 *
870
+	 * @return EE_Attendee|EE_Base_Class
871
+	 * @throws EE_Error
872
+	 * @throws InvalidArgumentException
873
+	 * @throws InvalidDataTypeException
874
+	 * @throws InvalidInterfaceException
875
+	 * @throws ReflectionException
876
+	 */
877
+	public function attendee()
878
+	{
879
+		return $this->get_first_related('Attendee');
880
+	}
881
+
882
+
883
+	/**
884
+	 * Gets the name of the attendee.
885
+	 *
886
+	 * @param bool $apply_html_entities set to true if you want to use HTML entities.
887
+	 * @return string
888
+	 * @throws EE_Error
889
+	 * @throws InvalidArgumentException
890
+	 * @throws InvalidDataTypeException
891
+	 * @throws InvalidInterfaceException
892
+	 * @throws ReflectionException
893
+	 * @since 4.10.12.p
894
+	 */
895
+	public function attendeeName($apply_html_entities = false)
896
+	{
897
+		$attendee = $this->get_first_related('Attendee');
898
+		if ($attendee instanceof EE_Attendee) {
899
+			$attendee_name = $attendee->full_name($apply_html_entities);
900
+		} else {
901
+			$attendee_name = esc_html__('Unknown', 'event_espresso');
902
+		}
903
+		return $attendee_name;
904
+	}
905
+
906
+
907
+	/**
908
+	 *        get Event ID
909
+	 */
910
+	public function event_ID()
911
+	{
912
+		return $this->get('EVT_ID');
913
+	}
914
+
915
+
916
+	/**
917
+	 *        get Event ID
918
+	 */
919
+	public function event_name()
920
+	{
921
+		$event = $this->event_obj();
922
+		if ($event) {
923
+			return $event->name();
924
+		} else {
925
+			return null;
926
+		}
927
+	}
928
+
929
+
930
+	/**
931
+	 * Fetches the event this registration is for
932
+	 *
933
+	 * @return EE_Base_Class|EE_Event
934
+	 * @throws EE_Error
935
+	 * @throws InvalidArgumentException
936
+	 * @throws InvalidDataTypeException
937
+	 * @throws InvalidInterfaceException
938
+	 * @throws ReflectionException
939
+	 */
940
+	public function event_obj()
941
+	{
942
+		return $this->get_first_related('Event');
943
+	}
944
+
945
+
946
+	/**
947
+	 *        get Attendee ID
948
+	 */
949
+	public function attendee_ID()
950
+	{
951
+		return $this->get('ATT_ID');
952
+	}
953
+
954
+
955
+	/**
956
+	 *        get PHP Session ID
957
+	 */
958
+	public function session_ID()
959
+	{
960
+		return $this->get('REG_session');
961
+	}
962
+
963
+
964
+	/**
965
+	 * Gets the string which represents the URL trigger for the receipt template in the message template system.
966
+	 *
967
+	 * @param string $messenger 'pdf' or 'html'.  Default 'html'.
968
+	 * @return string
969
+	 * @throws DomainException
970
+	 * @throws InvalidArgumentException
971
+	 * @throws InvalidDataTypeException
972
+	 * @throws InvalidInterfaceException
973
+	 */
974
+	public function receipt_url($messenger = 'html')
975
+	{
976
+		return apply_filters('FHEE__EE_Registration__receipt_url__receipt_url', '', $this, $messenger, 'receipt');
977
+	}
978
+
979
+
980
+	/**
981
+	 * Gets the string which represents the URL trigger for the invoice template in the message template system.
982
+	 *
983
+	 * @param string $messenger 'pdf' or 'html'.  Default 'html'.
984
+	 * @return string
985
+	 * @throws DomainException
986
+	 * @throws InvalidArgumentException
987
+	 * @throws InvalidDataTypeException
988
+	 * @throws InvalidInterfaceException
989
+	 */
990
+	public function invoice_url($messenger = 'html')
991
+	{
992
+		return apply_filters('FHEE__EE_Registration__invoice_url__invoice_url', '', $this, $messenger, 'invoice');
993
+	}
994
+
995
+
996
+	/**
997
+	 * get Registration URL Link
998
+	 *
999
+	 * @return string
1000
+	 * @throws EE_Error
1001
+	 * @throws InvalidArgumentException
1002
+	 * @throws InvalidDataTypeException
1003
+	 * @throws InvalidInterfaceException
1004
+	 * @throws ReflectionException
1005
+	 */
1006
+	public function reg_url_link()
1007
+	{
1008
+		return (string) $this->get('REG_url_link');
1009
+	}
1010
+
1011
+
1012
+	/**
1013
+	 * Echoes out invoice_url()
1014
+	 *
1015
+	 * @param string $type 'download','launch', or 'html' (default is 'launch')
1016
+	 * @return void
1017
+	 * @throws DomainException
1018
+	 * @throws EE_Error
1019
+	 * @throws InvalidArgumentException
1020
+	 * @throws InvalidDataTypeException
1021
+	 * @throws InvalidInterfaceException
1022
+	 * @throws ReflectionException
1023
+	 */
1024
+	public function e_invoice_url($type = 'launch')
1025
+	{
1026
+		echo esc_url_raw($this->invoice_url($type));
1027
+	}
1028
+
1029
+
1030
+	/**
1031
+	 * Echoes out payment_overview_url
1032
+	 */
1033
+	public function e_payment_overview_url()
1034
+	{
1035
+		echo esc_url_raw($this->payment_overview_url());
1036
+	}
1037
+
1038
+
1039
+	/**
1040
+	 * Gets the URL for the checkout payment options reg step
1041
+	 * with this registration's REG_url_link added as a query parameter
1042
+	 *
1043
+	 * @param bool $clear_session Set to true when you want to clear the session on revisiting the
1044
+	 *                            payment overview url.
1045
+	 * @return string
1046
+	 * @throws EE_Error
1047
+	 * @throws InvalidArgumentException
1048
+	 * @throws InvalidDataTypeException
1049
+	 * @throws InvalidInterfaceException
1050
+	 * @throws ReflectionException
1051
+	 */
1052
+	public function payment_overview_url($clear_session = false)
1053
+	{
1054
+		return add_query_arg(
1055
+			(array) apply_filters(
1056
+				'FHEE__EE_Registration__payment_overview_url__query_args',
1057
+				[
1058
+					'e_reg_url_link' => $this->reg_url_link(),
1059
+					'step'           => 'payment_options',
1060
+					'revisit'        => true,
1061
+					'clear_session'  => (bool) $clear_session,
1062
+				],
1063
+				$this
1064
+			),
1065
+			EE_Registry::instance()->CFG->core->reg_page_url()
1066
+		);
1067
+	}
1068
+
1069
+
1070
+	/**
1071
+	 * Gets the URL for the checkout attendee information reg step
1072
+	 * with this registration's REG_url_link added as a query parameter
1073
+	 *
1074
+	 * @return string
1075
+	 * @throws EE_Error
1076
+	 * @throws InvalidArgumentException
1077
+	 * @throws InvalidDataTypeException
1078
+	 * @throws InvalidInterfaceException
1079
+	 * @throws ReflectionException
1080
+	 */
1081
+	public function edit_attendee_information_url()
1082
+	{
1083
+		return add_query_arg(
1084
+			(array) apply_filters(
1085
+				'FHEE__EE_Registration__edit_attendee_information_url__query_args',
1086
+				[
1087
+					'e_reg_url_link' => $this->reg_url_link(),
1088
+					'step'           => 'attendee_information',
1089
+					'revisit'        => true,
1090
+				],
1091
+				$this
1092
+			),
1093
+			EE_Registry::instance()->CFG->core->reg_page_url()
1094
+		);
1095
+	}
1096
+
1097
+
1098
+	/**
1099
+	 * Simply generates and returns the appropriate admin_url link to edit this registration
1100
+	 *
1101
+	 * @return string
1102
+	 * @throws EE_Error
1103
+	 * @throws InvalidArgumentException
1104
+	 * @throws InvalidDataTypeException
1105
+	 * @throws InvalidInterfaceException
1106
+	 * @throws ReflectionException
1107
+	 */
1108
+	public function get_admin_edit_url()
1109
+	{
1110
+		return EEH_URL::add_query_args_and_nonce(
1111
+			[
1112
+				'page'    => 'espresso_registrations',
1113
+				'action'  => 'view_registration',
1114
+				'_REG_ID' => $this->ID(),
1115
+			],
1116
+			admin_url('admin.php')
1117
+		);
1118
+	}
1119
+
1120
+
1121
+	/**
1122
+	 * is_primary_registrant?
1123
+	 *
1124
+	 * @throws EE_Error
1125
+	 * @throws InvalidArgumentException
1126
+	 * @throws InvalidDataTypeException
1127
+	 * @throws InvalidInterfaceException
1128
+	 * @throws ReflectionException
1129
+	 */
1130
+	public function is_primary_registrant()
1131
+	{
1132
+		return (int) $this->get('REG_count') === 1;
1133
+	}
1134
+
1135
+
1136
+	/**
1137
+	 * This returns the primary registration object for this registration group (which may be this object).
1138
+	 *
1139
+	 * @return EE_Registration
1140
+	 * @throws EE_Error
1141
+	 * @throws InvalidArgumentException
1142
+	 * @throws InvalidDataTypeException
1143
+	 * @throws InvalidInterfaceException
1144
+	 * @throws ReflectionException
1145
+	 */
1146
+	public function get_primary_registration()
1147
+	{
1148
+		if ($this->is_primary_registrant()) {
1149
+			return $this;
1150
+		}
1151
+
1152
+		// k reg_count !== 1 so let's get the EE_Registration object matching this txn_id and reg_count == 1
1153
+		/** @var EE_Registration $primary_registrant */
1154
+		$primary_registrant = EEM_Registration::instance()->get_one(
1155
+			[
1156
+				[
1157
+					'TXN_ID'    => $this->transaction_ID(),
1158
+					'REG_count' => 1,
1159
+				],
1160
+			]
1161
+		);
1162
+		return $primary_registrant;
1163
+	}
1164
+
1165
+
1166
+	/**
1167
+	 * get  Attendee Number
1168
+	 *
1169
+	 * @throws EE_Error
1170
+	 * @throws InvalidArgumentException
1171
+	 * @throws InvalidDataTypeException
1172
+	 * @throws InvalidInterfaceException
1173
+	 * @throws ReflectionException
1174
+	 */
1175
+	public function count()
1176
+	{
1177
+		return $this->get('REG_count');
1178
+	}
1179
+
1180
+
1181
+	/**
1182
+	 * get Group Size
1183
+	 *
1184
+	 * @throws EE_Error
1185
+	 * @throws InvalidArgumentException
1186
+	 * @throws InvalidDataTypeException
1187
+	 * @throws InvalidInterfaceException
1188
+	 * @throws ReflectionException
1189
+	 */
1190
+	public function group_size()
1191
+	{
1192
+		return $this->get('REG_group_size');
1193
+	}
1194
+
1195
+
1196
+	/**
1197
+	 * get Registration Date
1198
+	 *
1199
+	 * @throws EE_Error
1200
+	 * @throws InvalidArgumentException
1201
+	 * @throws InvalidDataTypeException
1202
+	 * @throws InvalidInterfaceException
1203
+	 * @throws ReflectionException
1204
+	 */
1205
+	public function date()
1206
+	{
1207
+		return $this->get('REG_date');
1208
+	}
1209
+
1210
+
1211
+	/**
1212
+	 * gets a pretty date
1213
+	 *
1214
+	 * @param string $date_format
1215
+	 * @param string $time_format
1216
+	 * @return string
1217
+	 * @throws EE_Error
1218
+	 * @throws InvalidArgumentException
1219
+	 * @throws InvalidDataTypeException
1220
+	 * @throws InvalidInterfaceException
1221
+	 * @throws ReflectionException
1222
+	 */
1223
+	public function pretty_date($date_format = null, $time_format = null)
1224
+	{
1225
+		return $this->get_datetime('REG_date', $date_format, $time_format);
1226
+	}
1227
+
1228
+
1229
+	/**
1230
+	 * final_price
1231
+	 * the registration's share of the transaction total, so that the
1232
+	 * sum of all the transaction's REG_final_prices equal the transaction's total
1233
+	 *
1234
+	 * @return float
1235
+	 * @throws EE_Error
1236
+	 * @throws InvalidArgumentException
1237
+	 * @throws InvalidDataTypeException
1238
+	 * @throws InvalidInterfaceException
1239
+	 * @throws ReflectionException
1240
+	 */
1241
+	public function final_price(): float
1242
+	{
1243
+		return (float) $this->get('REG_final_price');
1244
+	}
1245
+
1246
+
1247
+	/**
1248
+	 * pretty_final_price
1249
+	 *  final price as formatted string, with correct decimal places and currency symbol
1250
+	 *
1251
+	 * @return string
1252
+	 * @throws EE_Error
1253
+	 * @throws InvalidArgumentException
1254
+	 * @throws InvalidDataTypeException
1255
+	 * @throws InvalidInterfaceException
1256
+	 * @throws ReflectionException
1257
+	 */
1258
+	public function pretty_final_price()
1259
+	{
1260
+		return $this->get_pretty('REG_final_price');
1261
+	}
1262
+
1263
+
1264
+	/**
1265
+	 * get paid (yeah)
1266
+	 *
1267
+	 * @return float
1268
+	 * @throws EE_Error
1269
+	 * @throws InvalidArgumentException
1270
+	 * @throws InvalidDataTypeException
1271
+	 * @throws InvalidInterfaceException
1272
+	 * @throws ReflectionException
1273
+	 */
1274
+	public function paid(): float
1275
+	{
1276
+		return (float) $this->get('REG_paid');
1277
+	}
1278
+
1279
+
1280
+	/**
1281
+	 * pretty_paid
1282
+	 *
1283
+	 * @return float
1284
+	 * @throws EE_Error
1285
+	 * @throws InvalidArgumentException
1286
+	 * @throws InvalidDataTypeException
1287
+	 * @throws InvalidInterfaceException
1288
+	 * @throws ReflectionException
1289
+	 */
1290
+	public function pretty_paid()
1291
+	{
1292
+		return $this->get_pretty('REG_paid');
1293
+	}
1294
+
1295
+
1296
+	/**
1297
+	 * owes_monies_and_can_pay
1298
+	 * whether or not this registration has monies owing and it's' status allows payment
1299
+	 *
1300
+	 * @param array $requires_payment list of registration statuses that allow a registrant to make a payment
1301
+	 * @return bool
1302
+	 * @throws EE_Error
1303
+	 * @throws InvalidArgumentException
1304
+	 * @throws InvalidDataTypeException
1305
+	 * @throws InvalidInterfaceException
1306
+	 * @throws ReflectionException
1307
+	 */
1308
+	public function owes_monies_and_can_pay($requires_payment = [])
1309
+	{
1310
+		// these reg statuses require payment (if event is not free)
1311
+		$requires_payment = ! empty($requires_payment)
1312
+			? $requires_payment
1313
+			: EEM_Registration::reg_statuses_that_allow_payment();
1314
+		if (
1315
+			$this->final_price() !== 0 &&
1316
+			$this->final_price() !== $this->paid() &&
1317
+			in_array($this->status_ID(), $requires_payment)
1318
+		) {
1319
+			return true;
1320
+		}
1321
+		return false;
1322
+	}
1323
+
1324
+
1325
+	/**
1326
+	 * Prints out the return value of $this->pretty_status()
1327
+	 *
1328
+	 * @param bool $show_icons
1329
+	 * @return void
1330
+	 * @throws EE_Error
1331
+	 * @throws InvalidArgumentException
1332
+	 * @throws InvalidDataTypeException
1333
+	 * @throws InvalidInterfaceException
1334
+	 * @throws ReflectionException
1335
+	 */
1336
+	public function e_pretty_status($show_icons = false)
1337
+	{
1338
+		echo wp_kses($this->pretty_status($show_icons), AllowedTags::getAllowedTags());
1339
+	}
1340
+
1341
+
1342
+	/**
1343
+	 * Returns a nice version of the status for displaying to customers
1344
+	 *
1345
+	 * @param bool $show_icons
1346
+	 * @return string
1347
+	 * @throws EE_Error
1348
+	 * @throws InvalidArgumentException
1349
+	 * @throws InvalidDataTypeException
1350
+	 * @throws InvalidInterfaceException
1351
+	 * @throws ReflectionException
1352
+	 */
1353
+	public function pretty_status($show_icons = false)
1354
+	{
1355
+		$status = EEM_Status::instance()->localized_status(
1356
+			[$this->status_ID() => esc_html__('unknown', 'event_espresso')],
1357
+			false,
1358
+			'sentence'
1359
+		);
1360
+		$icon   = '';
1361
+		switch ($this->status_ID()) {
1362
+			case EEM_Registration::status_id_approved:
1363
+				$icon = $show_icons
1364
+					? '<span class="dashicons dashicons-star-filled ee-icon-size-16 green-text"></span>'
1365
+					: '';
1366
+				break;
1367
+			case EEM_Registration::status_id_pending_payment:
1368
+				$icon = $show_icons
1369
+					? '<span class="dashicons dashicons-star-half ee-icon-size-16 orange-text"></span>'
1370
+					: '';
1371
+				break;
1372
+			case EEM_Registration::status_id_not_approved:
1373
+				$icon = $show_icons
1374
+					? '<span class="dashicons dashicons-marker ee-icon-size-16 orange-text"></span>'
1375
+					: '';
1376
+				break;
1377
+			case EEM_Registration::status_id_cancelled:
1378
+				$icon = $show_icons
1379
+					? '<span class="dashicons dashicons-no ee-icon-size-16 lt-grey-text"></span>'
1380
+					: '';
1381
+				break;
1382
+			case EEM_Registration::status_id_incomplete:
1383
+				$icon = $show_icons
1384
+					? '<span class="dashicons dashicons-no ee-icon-size-16 lt-orange-text"></span>'
1385
+					: '';
1386
+				break;
1387
+			case EEM_Registration::status_id_declined:
1388
+				$icon = $show_icons
1389
+					? '<span class="dashicons dashicons-no ee-icon-size-16 red-text"></span>'
1390
+					: '';
1391
+				break;
1392
+			case EEM_Registration::status_id_wait_list:
1393
+				$icon = $show_icons
1394
+					? '<span class="dashicons dashicons-clipboard ee-icon-size-16 purple-text"></span>'
1395
+					: '';
1396
+				break;
1397
+		}
1398
+		return $icon . $status[ $this->status_ID() ];
1399
+	}
1400
+
1401
+
1402
+	/**
1403
+	 *        get Attendee Is Going
1404
+	 */
1405
+	public function att_is_going()
1406
+	{
1407
+		return $this->get('REG_att_is_going');
1408
+	}
1409
+
1410
+
1411
+	/**
1412
+	 * Gets related answers
1413
+	 *
1414
+	 * @param array $query_params @see
1415
+	 *                            https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
1416
+	 * @return EE_Answer[]|EE_Base_Class[]
1417
+	 * @throws EE_Error
1418
+	 * @throws InvalidArgumentException
1419
+	 * @throws InvalidDataTypeException
1420
+	 * @throws InvalidInterfaceException
1421
+	 * @throws ReflectionException
1422
+	 */
1423
+	public function answers($query_params = [])
1424
+	{
1425
+		return $this->get_many_related('Answer', $query_params);
1426
+	}
1427
+
1428
+
1429
+	/**
1430
+	 * Gets the registration's answer value to the specified question
1431
+	 * (either the question's ID or a question object)
1432
+	 *
1433
+	 * @param EE_Question|int $question
1434
+	 * @param bool            $pretty_value
1435
+	 * @return array|string if pretty_value= true, the result will always be a string
1436
+	 * (because the answer might be an array of answer values, so passing pretty_value=true
1437
+	 * will convert it into some kind of string)
1438
+	 * @throws EE_Error
1439
+	 * @throws InvalidArgumentException
1440
+	 * @throws InvalidDataTypeException
1441
+	 * @throws InvalidInterfaceException
1442
+	 */
1443
+	public function answer_value_to_question($question, $pretty_value = true)
1444
+	{
1445
+		$question_id = EEM_Question::instance()->ensure_is_ID($question);
1446
+		return EEM_Answer::instance()->get_answer_value_to_question($this, $question_id, $pretty_value);
1447
+	}
1448
+
1449
+
1450
+	/**
1451
+	 * question_groups
1452
+	 * returns an array of EE_Question_Group objects for this registration
1453
+	 *
1454
+	 * @return EE_Question_Group[]
1455
+	 * @throws EE_Error
1456
+	 * @throws InvalidArgumentException
1457
+	 * @throws InvalidDataTypeException
1458
+	 * @throws InvalidInterfaceException
1459
+	 * @throws ReflectionException
1460
+	 */
1461
+	public function question_groups()
1462
+	{
1463
+		return EEM_Event::instance()->get_question_groups_for_event($this->event_ID(), $this);
1464
+	}
1465
+
1466
+
1467
+	/**
1468
+	 * count_question_groups
1469
+	 * returns a count of the number of EE_Question_Group objects for this registration
1470
+	 *
1471
+	 * @return int
1472
+	 * @throws EE_Error
1473
+	 * @throws EntityNotFoundException
1474
+	 * @throws InvalidArgumentException
1475
+	 * @throws InvalidDataTypeException
1476
+	 * @throws InvalidInterfaceException
1477
+	 * @throws ReflectionException
1478
+	 */
1479
+	public function count_question_groups()
1480
+	{
1481
+		return EEM_Event::instance()->count_related(
1482
+			$this->event_ID(),
1483
+			'Question_Group',
1484
+			[
1485
+				[
1486
+					'Event_Question_Group.'
1487
+					. EEM_Event_Question_Group::instance()->fieldNameForContext($this->is_primary_registrant()) => true,
1488
+				],
1489
+			]
1490
+		);
1491
+	}
1492
+
1493
+
1494
+	/**
1495
+	 * Returns the registration date in the 'standard' string format
1496
+	 * (function may be improved in the future to allow for different formats and timezones)
1497
+	 *
1498
+	 * @return string
1499
+	 * @throws EE_Error
1500
+	 * @throws InvalidArgumentException
1501
+	 * @throws InvalidDataTypeException
1502
+	 * @throws InvalidInterfaceException
1503
+	 * @throws ReflectionException
1504
+	 */
1505
+	public function reg_date()
1506
+	{
1507
+		return $this->get_datetime('REG_date');
1508
+	}
1509
+
1510
+
1511
+	/**
1512
+	 * Gets the datetime-ticket for this registration (ie, it can be used to isolate
1513
+	 * the ticket this registration purchased, or the datetime they have registered
1514
+	 * to attend)
1515
+	 *
1516
+	 * @return EE_Base_Class|EE_Datetime_Ticket
1517
+	 * @throws EE_Error
1518
+	 * @throws InvalidArgumentException
1519
+	 * @throws InvalidDataTypeException
1520
+	 * @throws InvalidInterfaceException
1521
+	 * @throws ReflectionException
1522
+	 */
1523
+	public function datetime_ticket()
1524
+	{
1525
+		return $this->get_first_related('Datetime_Ticket');
1526
+	}
1527
+
1528
+
1529
+	/**
1530
+	 * Sets the registration's datetime_ticket.
1531
+	 *
1532
+	 * @param EE_Datetime_Ticket $datetime_ticket
1533
+	 * @return EE_Base_Class|EE_Datetime_Ticket
1534
+	 * @throws EE_Error
1535
+	 * @throws InvalidArgumentException
1536
+	 * @throws InvalidDataTypeException
1537
+	 * @throws InvalidInterfaceException
1538
+	 * @throws ReflectionException
1539
+	 */
1540
+	public function set_datetime_ticket($datetime_ticket)
1541
+	{
1542
+		return $this->_add_relation_to($datetime_ticket, 'Datetime_Ticket');
1543
+	}
1544
+
1545
+
1546
+	/**
1547
+	 * Gets deleted
1548
+	 *
1549
+	 * @return bool
1550
+	 * @throws EE_Error
1551
+	 * @throws InvalidArgumentException
1552
+	 * @throws InvalidDataTypeException
1553
+	 * @throws InvalidInterfaceException
1554
+	 * @throws ReflectionException
1555
+	 */
1556
+	public function deleted()
1557
+	{
1558
+		return $this->get('REG_deleted');
1559
+	}
1560
+
1561
+
1562
+	/**
1563
+	 * Sets deleted
1564
+	 *
1565
+	 * @param boolean $deleted
1566
+	 * @return void
1567
+	 * @throws DomainException
1568
+	 * @throws EE_Error
1569
+	 * @throws EntityNotFoundException
1570
+	 * @throws InvalidArgumentException
1571
+	 * @throws InvalidDataTypeException
1572
+	 * @throws InvalidInterfaceException
1573
+	 * @throws ReflectionException
1574
+	 * @throws RuntimeException
1575
+	 * @throws UnexpectedEntityException
1576
+	 */
1577
+	public function set_deleted($deleted)
1578
+	{
1579
+		if ($deleted) {
1580
+			$this->delete();
1581
+		} else {
1582
+			$this->restore();
1583
+		}
1584
+	}
1585
+
1586
+
1587
+	/**
1588
+	 * Get the status object of this object
1589
+	 *
1590
+	 * @return EE_Base_Class|EE_Status
1591
+	 * @throws EE_Error
1592
+	 * @throws InvalidArgumentException
1593
+	 * @throws InvalidDataTypeException
1594
+	 * @throws InvalidInterfaceException
1595
+	 * @throws ReflectionException
1596
+	 */
1597
+	public function status_obj()
1598
+	{
1599
+		return $this->get_first_related('Status');
1600
+	}
1601
+
1602
+
1603
+	/**
1604
+	 * Returns the number of times this registration has checked into any of the datetimes
1605
+	 * its available for
1606
+	 *
1607
+	 * @return int
1608
+	 * @throws EE_Error
1609
+	 * @throws InvalidArgumentException
1610
+	 * @throws InvalidDataTypeException
1611
+	 * @throws InvalidInterfaceException
1612
+	 * @throws ReflectionException
1613
+	 */
1614
+	public function count_checkins()
1615
+	{
1616
+		return $this->get_model()->count_related($this, 'Checkin');
1617
+	}
1618
+
1619
+
1620
+	/**
1621
+	 * Returns the number of current Check-ins this registration is checked into for any of the datetimes the
1622
+	 * registration is for.  Note, this is ONLY checked in (does not include checkedout)
1623
+	 *
1624
+	 * @return int
1625
+	 * @throws EE_Error
1626
+	 * @throws InvalidArgumentException
1627
+	 * @throws InvalidDataTypeException
1628
+	 * @throws InvalidInterfaceException
1629
+	 * @throws ReflectionException
1630
+	 */
1631
+	public function count_checkins_not_checkedout()
1632
+	{
1633
+		return $this->get_model()->count_related($this, 'Checkin', [['CHK_in' => 1]]);
1634
+	}
1635
+
1636
+
1637
+	/**
1638
+	 * The purpose of this method is simply to check whether this registration can checkin to the given datetime.
1639
+	 *
1640
+	 * @param int | EE_Datetime $DTT_OR_ID      The datetime the registration is being checked against
1641
+	 * @param bool              $check_approved This is used to indicate whether the caller wants can_checkin to also
1642
+	 *                                          consider registration status as well as datetime access.
1643
+	 * @return bool
1644
+	 * @throws EE_Error
1645
+	 * @throws InvalidArgumentException
1646
+	 * @throws InvalidDataTypeException
1647
+	 * @throws InvalidInterfaceException
1648
+	 * @throws ReflectionException
1649
+	 */
1650
+	public function can_checkin($DTT_OR_ID, $check_approved = true)
1651
+	{
1652
+		$DTT_ID = EEM_Datetime::instance()->ensure_is_ID($DTT_OR_ID);
1653
+		// first check registration status
1654
+		if (! $DTT_ID || ($check_approved && ! $this->is_approved())) {
1655
+			return false;
1656
+		}
1657
+		// is there a datetime ticket that matches this dtt_ID?
1658
+		if (
1659
+			! (EEM_Datetime_Ticket::instance()->exists(
1660
+				[
1661
+					[
1662
+						'TKT_ID' => $this->get('TKT_ID'),
1663
+						'DTT_ID' => $DTT_ID,
1664
+					],
1665
+				]
1666
+			))
1667
+		) {
1668
+			return false;
1669
+		}
1670
+
1671
+		// final check is against TKT_uses
1672
+		return $this->verify_can_checkin_against_TKT_uses($DTT_ID);
1673
+	}
1674
+
1675
+
1676
+	/**
1677
+	 * This method verifies whether the user can checkin for the given datetime considering the max uses value set on
1678
+	 * the ticket. To do this,  a query is done to get the count of the datetime records already checked into.  If the
1679
+	 * datetime given does not have a check-in record and checking in for that datetime will exceed the allowed uses,
1680
+	 * then return false.  Otherwise return true.
1681
+	 *
1682
+	 * @param int | EE_Datetime $DTT_OR_ID The datetime the registration is being checked against
1683
+	 * @return bool true means can checkin.  false means cannot checkin.
1684
+	 * @throws EE_Error
1685
+	 * @throws InvalidArgumentException
1686
+	 * @throws InvalidDataTypeException
1687
+	 * @throws InvalidInterfaceException
1688
+	 * @throws ReflectionException
1689
+	 */
1690
+	public function verify_can_checkin_against_TKT_uses($DTT_OR_ID)
1691
+	{
1692
+		$DTT_ID = EEM_Datetime::instance()->ensure_is_ID($DTT_OR_ID);
1693
+
1694
+		if (! $DTT_ID) {
1695
+			return false;
1696
+		}
1697
+
1698
+		$max_uses = $this->ticket() instanceof EE_Ticket
1699
+			? $this->ticket()->uses()
1700
+			: EE_INF;
1701
+
1702
+		// if max uses is not set or equals infinity then return true cause its not a factor for whether user can
1703
+		// check-in or not.
1704
+		if (! $max_uses || $max_uses === EE_INF) {
1705
+			return true;
1706
+		}
1707
+
1708
+		// does this datetime have a checkin record?  If so, then the dtt count has already been verified so we can just
1709
+		// go ahead and toggle.
1710
+		if (EEM_Checkin::instance()->exists([['REG_ID' => $this->ID(), 'DTT_ID' => $DTT_ID]])) {
1711
+			return true;
1712
+		}
1713
+
1714
+		// made it here so the last check is whether the number of checkins per unique datetime on this registration
1715
+		// disallows further check-ins.
1716
+		$count_unique_dtt_checkins = EEM_Checkin::instance()->count(
1717
+			[
1718
+				[
1719
+					'REG_ID' => $this->ID(),
1720
+					'CHK_in' => true,
1721
+				],
1722
+			],
1723
+			'DTT_ID',
1724
+			true
1725
+		);
1726
+		// checkins have already reached their max number of uses
1727
+		// so registrant can NOT checkin
1728
+		if ($count_unique_dtt_checkins >= $max_uses) {
1729
+			EE_Error::add_error(
1730
+				esc_html__(
1731
+					'Check-in denied because number of datetime uses for the ticket has been reached or exceeded.',
1732
+					'event_espresso'
1733
+				),
1734
+				__FILE__,
1735
+				__FUNCTION__,
1736
+				__LINE__
1737
+			);
1738
+			return false;
1739
+		}
1740
+		return true;
1741
+	}
1742
+
1743
+
1744
+	/**
1745
+	 * toggle Check-in status for this registration
1746
+	 * Check-ins are toggled in the following order:
1747
+	 * never checked in -> checked in
1748
+	 * checked in -> checked out
1749
+	 * checked out -> checked in
1750
+	 *
1751
+	 * @param int  $DTT_ID  include specific datetime to toggle Check-in for.
1752
+	 *                      If not included or null, then it is assumed latest datetime is being toggled.
1753
+	 * @param bool $verify  If true then can_checkin() is used to verify whether the person
1754
+	 *                      can be checked in or not.  Otherwise this forces change in checkin status.
1755
+	 * @return bool|int     the chk_in status toggled to OR false if nothing got changed.
1756
+	 * @throws EE_Error
1757
+	 * @throws InvalidArgumentException
1758
+	 * @throws InvalidDataTypeException
1759
+	 * @throws InvalidInterfaceException
1760
+	 * @throws ReflectionException
1761
+	 */
1762
+	public function toggle_checkin_status($DTT_ID = null, $verify = false)
1763
+	{
1764
+		if (empty($DTT_ID)) {
1765
+			$datetime = $this->get_latest_related_datetime();
1766
+			$DTT_ID   = $datetime instanceof EE_Datetime ? $datetime->ID() : 0;
1767
+			// verify the registration can checkin for the given DTT_ID
1768
+		} elseif (! $this->can_checkin($DTT_ID, $verify)) {
1769
+			EE_Error::add_error(
1770
+				sprintf(
1771
+					esc_html__(
1772
+						'The given registration (ID:%1$d) can not be checked in to the given DTT_ID (%2$d), because the registration does not have access',
1773
+						'event_espresso'
1774
+					),
1775
+					$this->ID(),
1776
+					$DTT_ID
1777
+				),
1778
+				__FILE__,
1779
+				__FUNCTION__,
1780
+				__LINE__
1781
+			);
1782
+			return false;
1783
+		}
1784
+		$status_paths = [
1785
+			EE_Checkin::status_checked_never => EE_Checkin::status_checked_in,
1786
+			EE_Checkin::status_checked_in    => EE_Checkin::status_checked_out,
1787
+			EE_Checkin::status_checked_out   => EE_Checkin::status_checked_in,
1788
+		];
1789
+		// start by getting the current status so we know what status we'll be changing to.
1790
+		$cur_status = $this->check_in_status_for_datetime($DTT_ID);
1791
+		$status_to  = $status_paths[ $cur_status ];
1792
+		// database only records true for checked IN or false for checked OUT
1793
+		// no record ( null ) means checked in NEVER, but we obviously don't save that
1794
+		$new_status = $status_to === EE_Checkin::status_checked_in;
1795
+		// add relation - note Check-ins are always creating new rows
1796
+		// because we are keeping track of Check-ins over time.
1797
+		// Eventually we'll probably want to show a list table
1798
+		// for the individual Check-ins so that they can be managed.
1799
+		$checkin = EE_Checkin::new_instance(
1800
+			[
1801
+				'REG_ID' => $this->ID(),
1802
+				'DTT_ID' => $DTT_ID,
1803
+				'CHK_in' => $new_status,
1804
+			]
1805
+		);
1806
+		// if the record could not be saved then return false
1807
+		if ($checkin->save() === 0) {
1808
+			if (WP_DEBUG) {
1809
+				global $wpdb;
1810
+				$error = sprintf(
1811
+					esc_html__(
1812
+						'Registration check in update failed because of the following database error: %1$s%2$s',
1813
+						'event_espresso'
1814
+					),
1815
+					'<br />',
1816
+					$wpdb->last_error
1817
+				);
1818
+			} else {
1819
+				$error = esc_html__(
1820
+					'Registration check in update failed because of an unknown database error',
1821
+					'event_espresso'
1822
+				);
1823
+			}
1824
+			EE_Error::add_error($error, __FILE__, __FUNCTION__, __LINE__);
1825
+			return false;
1826
+		}
1827
+		// Fire a checked_in and checkout_out action.
1828
+		$checked_status = $status_to === EE_Checkin::status_checked_in
1829
+			? 'checked_in'
1830
+			: 'checked_out';
1831
+		do_action("AHEE__EE_Registration__toggle_checkin_status__{$checked_status}", $this, $DTT_ID);
1832
+		return $status_to;
1833
+	}
1834
+
1835
+
1836
+	/**
1837
+	 * Returns the latest datetime related to this registration (via the ticket attached to the registration).
1838
+	 * "Latest" is defined by the `DTT_EVT_start` column.
1839
+	 *
1840
+	 * @return EE_Datetime|null
1841
+	 * @throws EE_Error
1842
+	 * @throws InvalidArgumentException
1843
+	 * @throws InvalidDataTypeException
1844
+	 * @throws InvalidInterfaceException
1845
+	 * @throws ReflectionException
1846
+	 */
1847
+	public function get_latest_related_datetime(): ?EE_Datetime
1848
+	{
1849
+		return EEM_Datetime::instance()->get_one(
1850
+			[
1851
+				[
1852
+					'Ticket.Registration.REG_ID' => $this->ID(),
1853
+				],
1854
+				'order_by' => ['DTT_EVT_start' => 'DESC'],
1855
+			]
1856
+		);
1857
+	}
1858
+
1859
+
1860
+	/**
1861
+	 * Returns the earliest datetime related to this registration (via the ticket attached to the registration).
1862
+	 * "Earliest" is defined by the `DTT_EVT_start` column.
1863
+	 *
1864
+	 * @return EE_Base_Class|EE_Soft_Delete_Base_Class|NULL
1865
+	 * @throws EE_Error
1866
+	 * @throws InvalidArgumentException
1867
+	 * @throws InvalidDataTypeException
1868
+	 * @throws InvalidInterfaceException
1869
+	 * @throws ReflectionException
1870
+	 */
1871
+	public function get_earliest_related_datetime()
1872
+	{
1873
+		return EEM_Datetime::instance()->get_one(
1874
+			[
1875
+				[
1876
+					'Ticket.Registration.REG_ID' => $this->ID(),
1877
+				],
1878
+				'order_by' => ['DTT_EVT_start' => 'ASC'],
1879
+			]
1880
+		);
1881
+	}
1882
+
1883
+
1884
+	/**
1885
+	 * This method simply returns the check-in status for this registration and the given datetime.
1886
+	 * If neither the datetime nor the checkin values are provided as arguments,
1887
+	 * then this will return the LATEST check-in status for the registration across all datetimes it belongs to.
1888
+	 *
1889
+	 * @param int|null        $DTT_ID  The ID of the datetime we're checking against
1890
+	 *                                 (if empty we'll get the primary datetime for
1891
+	 *                                 this registration (via event) and use it's ID);
1892
+	 * @param EE_Checkin|null $checkin If present, we use the given checkin object rather than the dtt_id.
1893
+	 * @return int                     Integer representing Check-in status.
1894
+	 * @throws EE_Error
1895
+	 * @throws ReflectionException
1896
+	 */
1897
+	public function check_in_status_for_datetime(?int $DTT_ID = 0, ?EE_Checkin $checkin = null): int
1898
+	{
1899
+		if ($checkin instanceof EE_Checkin) {
1900
+			return $checkin->status();
1901
+		}
1902
+
1903
+		if (! $DTT_ID) {
1904
+			return EE_Checkin::status_invalid;
1905
+		}
1906
+
1907
+		$checkin_query_params = [
1908
+			0          => ['DTT_ID' => $DTT_ID],
1909
+			'order_by' => ['CHK_timestamp' => 'DESC'],
1910
+		];
1911
+
1912
+		$checkin = $this->get_first_related(
1913
+			'Checkin',
1914
+			$checkin_query_params
1915
+		);
1916
+		return $checkin instanceof EE_Checkin ? $checkin->status() : EE_Checkin::status_checked_never;
1917
+	}
1918
+
1919
+
1920
+	/**
1921
+	 * This method returns a localized message for the toggled Check-in message.
1922
+	 *
1923
+	 * @param int|null $DTT_ID include specific datetime to get the correct Check-in message.  If not included or null,
1924
+	 *                         then it is assumed Check-in for primary datetime was toggled.
1925
+	 * @param bool     $error  This just flags that you want an error message returned. This is put in so that the error
1926
+	 *                         message can be customized with the attendee name.
1927
+	 * @return string internationalized message
1928
+	 * @throws EE_Error
1929
+	 * @throws ReflectionException
1930
+	 */
1931
+	public function get_checkin_msg(?int $DTT_ID, bool $error = false): string
1932
+	{
1933
+		// let's get the attendee first so we can include the name of the attendee
1934
+		$attendee = $this->get_first_related('Attendee');
1935
+		if ($attendee instanceof EE_Attendee) {
1936
+			if ($error) {
1937
+				return sprintf(
1938
+					esc_html__("%s's check-in status was not changed.", "event_espresso"),
1939
+					$attendee->full_name()
1940
+				);
1941
+			}
1942
+			$cur_status = $this->check_in_status_for_datetime($DTT_ID);
1943
+			// what is the status message going to be?
1944
+			switch ($cur_status) {
1945
+				case EE_Checkin::status_checked_never:
1946
+					return sprintf(
1947
+						esc_html__('%s has been removed from Check-in records', 'event_espresso'),
1948
+						$attendee->full_name()
1949
+					);
1950
+				case EE_Checkin::status_checked_in:
1951
+					return sprintf(esc_html__('%s has been checked in', 'event_espresso'), $attendee->full_name());
1952
+				case EE_Checkin::status_checked_out:
1953
+					return sprintf(esc_html__('%s has been checked out', 'event_espresso'), $attendee->full_name());
1954
+			}
1955
+		}
1956
+		return esc_html__('The check-in status could not be determined.', 'event_espresso');
1957
+	}
1958
+
1959
+
1960
+	/**
1961
+	 * Returns the related EE_Transaction to this registration
1962
+	 *
1963
+	 * @return EE_Transaction
1964
+	 * @throws EE_Error
1965
+	 * @throws EntityNotFoundException
1966
+	 * @throws ReflectionException
1967
+	 */
1968
+	public function transaction(): EE_Transaction
1969
+	{
1970
+		$transaction = $this->get_first_related('Transaction');
1971
+		if (! $transaction instanceof \EE_Transaction) {
1972
+			throw new EntityNotFoundException('Transaction ID', $this->transaction_ID());
1973
+		}
1974
+		return $transaction;
1975
+	}
1976
+
1977
+
1978
+	/**
1979
+	 * get Registration Code
1980
+	 *
1981
+	 * @return string
1982
+	 * @throws EE_Error
1983
+	 * @throws InvalidArgumentException
1984
+	 * @throws InvalidDataTypeException
1985
+	 * @throws InvalidInterfaceException
1986
+	 * @throws ReflectionException
1987
+	 */
1988
+	public function reg_code(): string
1989
+	{
1990
+		return $this->get('REG_code')
1991
+			?: '';
1992
+	}
1993
+
1994
+
1995
+	/**
1996
+	 * @return mixed
1997
+	 * @throws EE_Error
1998
+	 * @throws InvalidArgumentException
1999
+	 * @throws InvalidDataTypeException
2000
+	 * @throws InvalidInterfaceException
2001
+	 * @throws ReflectionException
2002
+	 */
2003
+	public function transaction_ID()
2004
+	{
2005
+		return $this->get('TXN_ID');
2006
+	}
2007
+
2008
+
2009
+	/**
2010
+	 * @return int
2011
+	 * @throws EE_Error
2012
+	 * @throws InvalidArgumentException
2013
+	 * @throws InvalidDataTypeException
2014
+	 * @throws InvalidInterfaceException
2015
+	 * @throws ReflectionException
2016
+	 */
2017
+	public function ticket_ID()
2018
+	{
2019
+		return $this->get('TKT_ID');
2020
+	}
2021
+
2022
+
2023
+	/**
2024
+	 * Set Registration Code
2025
+	 *
2026
+	 * @param RegCode|string $REG_code Registration Code
2027
+	 * @param boolean        $use_default
2028
+	 * @throws EE_Error
2029
+	 * @throws InvalidArgumentException
2030
+	 * @throws InvalidDataTypeException
2031
+	 * @throws InvalidInterfaceException
2032
+	 * @throws ReflectionException
2033
+	 */
2034
+	public function set_reg_code($REG_code, bool $use_default = false)
2035
+	{
2036
+		if (empty($REG_code)) {
2037
+			EE_Error::add_error(
2038
+				esc_html__('REG_code can not be empty.', 'event_espresso'),
2039
+				__FILE__,
2040
+				__FUNCTION__,
2041
+				__LINE__
2042
+			);
2043
+			return;
2044
+		}
2045
+		if (! $this->reg_code()) {
2046
+			parent::set('REG_code', $REG_code, $use_default);
2047
+		} else {
2048
+			EE_Error::doing_it_wrong(
2049
+				__CLASS__ . '::' . __FUNCTION__,
2050
+				esc_html__('Can not change a registration REG_code once it has been set.', 'event_espresso'),
2051
+				'4.6.0'
2052
+			);
2053
+		}
2054
+	}
2055
+
2056
+
2057
+	/**
2058
+	 * Returns all other registrations in the same group as this registrant who have the same ticket option.
2059
+	 * Note, if you want to just get all registrations in the same transaction (group), use:
2060
+	 *    $registration->transaction()->registrations();
2061
+	 *
2062
+	 * @return EE_Registration[] or empty array if this isn't a group registration.
2063
+	 * @throws EE_Error
2064
+	 * @throws InvalidArgumentException
2065
+	 * @throws InvalidDataTypeException
2066
+	 * @throws InvalidInterfaceException
2067
+	 * @throws ReflectionException
2068
+	 * @since 4.5.0
2069
+	 */
2070
+	public function get_all_other_registrations_in_group()
2071
+	{
2072
+		if ($this->group_size() < 2) {
2073
+			return [];
2074
+		}
2075
+
2076
+		$query[0] = [
2077
+			'TXN_ID' => $this->transaction_ID(),
2078
+			'REG_ID' => ['!=', $this->ID()],
2079
+			'TKT_ID' => $this->ticket_ID(),
2080
+		];
2081
+		/** @var EE_Registration[] $registrations */
2082
+		$registrations = $this->get_model()->get_all($query);
2083
+		return $registrations;
2084
+	}
2085
+
2086
+
2087
+	/**
2088
+	 * Return the link to the admin details for the object.
2089
+	 *
2090
+	 * @return string
2091
+	 * @throws EE_Error
2092
+	 * @throws InvalidArgumentException
2093
+	 * @throws InvalidDataTypeException
2094
+	 * @throws InvalidInterfaceException
2095
+	 * @throws ReflectionException
2096
+	 */
2097
+	public function get_admin_details_link()
2098
+	{
2099
+		EE_Registry::instance()->load_helper('URL');
2100
+		return EEH_URL::add_query_args_and_nonce(
2101
+			[
2102
+				'page'    => 'espresso_registrations',
2103
+				'action'  => 'view_registration',
2104
+				'_REG_ID' => $this->ID(),
2105
+			],
2106
+			admin_url('admin.php')
2107
+		);
2108
+	}
2109
+
2110
+
2111
+	/**
2112
+	 * Returns the link to the editor for the object.  Sometimes this is the same as the details.
2113
+	 *
2114
+	 * @return string
2115
+	 * @throws EE_Error
2116
+	 * @throws InvalidArgumentException
2117
+	 * @throws InvalidDataTypeException
2118
+	 * @throws InvalidInterfaceException
2119
+	 * @throws ReflectionException
2120
+	 */
2121
+	public function get_admin_edit_link()
2122
+	{
2123
+		return $this->get_admin_details_link();
2124
+	}
2125
+
2126
+
2127
+	/**
2128
+	 * Returns the link to a settings page for the object.
2129
+	 *
2130
+	 * @return string
2131
+	 * @throws EE_Error
2132
+	 * @throws InvalidArgumentException
2133
+	 * @throws InvalidDataTypeException
2134
+	 * @throws InvalidInterfaceException
2135
+	 * @throws ReflectionException
2136
+	 */
2137
+	public function get_admin_settings_link()
2138
+	{
2139
+		return $this->get_admin_details_link();
2140
+	}
2141
+
2142
+
2143
+	/**
2144
+	 * Returns the link to the "overview" for the object (typically the "list table" view).
2145
+	 *
2146
+	 * @return string
2147
+	 * @throws EE_Error
2148
+	 * @throws InvalidArgumentException
2149
+	 * @throws InvalidDataTypeException
2150
+	 * @throws InvalidInterfaceException
2151
+	 * @throws ReflectionException
2152
+	 */
2153
+	public function get_admin_overview_link()
2154
+	{
2155
+		EE_Registry::instance()->load_helper('URL');
2156
+		return EEH_URL::add_query_args_and_nonce(
2157
+			[
2158
+				'page' => 'espresso_registrations',
2159
+			],
2160
+			admin_url('admin.php')
2161
+		);
2162
+	}
2163
+
2164
+
2165
+	/**
2166
+	 * @param array $query_params
2167
+	 * @return EE_Base_Class[]|EE_Registration[]
2168
+	 * @throws EE_Error
2169
+	 * @throws InvalidArgumentException
2170
+	 * @throws InvalidDataTypeException
2171
+	 * @throws InvalidInterfaceException
2172
+	 * @throws ReflectionException
2173
+	 */
2174
+	public function payments($query_params = [])
2175
+	{
2176
+		return $this->get_many_related('Payment', $query_params);
2177
+	}
2178
+
2179
+
2180
+	/**
2181
+	 * @param array $query_params
2182
+	 * @return EE_Base_Class[]|EE_Registration_Payment[]
2183
+	 * @throws EE_Error
2184
+	 * @throws InvalidArgumentException
2185
+	 * @throws InvalidDataTypeException
2186
+	 * @throws InvalidInterfaceException
2187
+	 * @throws ReflectionException
2188
+	 */
2189
+	public function registration_payments($query_params = [])
2190
+	{
2191
+		return $this->get_many_related('Registration_Payment', $query_params);
2192
+	}
2193
+
2194
+
2195
+	/**
2196
+	 * This grabs the payment method corresponding to the last payment made for the amount owing on the registration.
2197
+	 * Note: if there are no payments on the registration there will be no payment method returned.
2198
+	 *
2199
+	 * @return EE_Payment|EE_Payment_Method|null
2200
+	 * @throws EE_Error
2201
+	 * @throws InvalidArgumentException
2202
+	 * @throws InvalidDataTypeException
2203
+	 * @throws InvalidInterfaceException
2204
+	 */
2205
+	public function payment_method()
2206
+	{
2207
+		return EEM_Payment_Method::instance()->get_last_used_for_registration($this);
2208
+	}
2209
+
2210
+
2211
+	/**
2212
+	 * @return \EE_Line_Item
2213
+	 * @throws EE_Error
2214
+	 * @throws EntityNotFoundException
2215
+	 * @throws InvalidArgumentException
2216
+	 * @throws InvalidDataTypeException
2217
+	 * @throws InvalidInterfaceException
2218
+	 * @throws ReflectionException
2219
+	 */
2220
+	public function ticket_line_item()
2221
+	{
2222
+		$ticket            = $this->ticket();
2223
+		$transaction       = $this->transaction();
2224
+		$line_item         = null;
2225
+		$ticket_line_items = \EEH_Line_Item::get_line_items_by_object_type_and_IDs(
2226
+			$transaction->total_line_item(),
2227
+			'Ticket',
2228
+			[$ticket->ID()]
2229
+		);
2230
+		foreach ($ticket_line_items as $ticket_line_item) {
2231
+			if (
2232
+				$ticket_line_item instanceof \EE_Line_Item
2233
+				&& $ticket_line_item->OBJ_type() === 'Ticket'
2234
+				&& $ticket_line_item->OBJ_ID() === $ticket->ID()
2235
+			) {
2236
+				$line_item = $ticket_line_item;
2237
+				break;
2238
+			}
2239
+		}
2240
+		if (! ($line_item instanceof \EE_Line_Item && $line_item->OBJ_type() === 'Ticket')) {
2241
+			throw new EntityNotFoundException('Line Item Ticket ID', $ticket->ID());
2242
+		}
2243
+		return $line_item;
2244
+	}
2245
+
2246
+
2247
+	/**
2248
+	 * Soft Deletes this model object.
2249
+	 *
2250
+	 * @param string $source function name that called this method
2251
+	 * @return boolean | int
2252
+	 * @throws DomainException
2253
+	 * @throws EE_Error
2254
+	 * @throws EntityNotFoundException
2255
+	 * @throws InvalidArgumentException
2256
+	 * @throws InvalidDataTypeException
2257
+	 * @throws InvalidInterfaceException
2258
+	 * @throws ReflectionException
2259
+	 * @throws RuntimeException
2260
+	 * @throws UnexpectedEntityException
2261
+	 */
2262
+	public function delete()
2263
+	{
2264
+		if ($this->update_extra_meta(EE_Registration::PRE_TRASH_REG_STATUS_KEY, $this->status_ID()) === true) {
2265
+			$this->set_status(EEM_Registration::status_id_cancelled);
2266
+		}
2267
+		return parent::delete();
2268
+	}
2269
+
2270
+
2271
+	/**
2272
+	 * Restores whatever the previous status was on a registration before it was trashed (if possible)
2273
+	 *
2274
+	 * @param string $source function name that called this method
2275
+	 * @return bool|int
2276
+	 * @throws DomainException
2277
+	 * @throws EE_Error
2278
+	 * @throws EntityNotFoundException
2279
+	 * @throws InvalidArgumentException
2280
+	 * @throws InvalidDataTypeException
2281
+	 * @throws InvalidInterfaceException
2282
+	 * @throws ReflectionException
2283
+	 * @throws RuntimeException
2284
+	 * @throws UnexpectedEntityException
2285
+	 */
2286
+	public function restore()
2287
+	{
2288
+		$previous_status = $this->get_extra_meta(
2289
+			EE_Registration::PRE_TRASH_REG_STATUS_KEY,
2290
+			true,
2291
+			EEM_Registration::status_id_cancelled
2292
+		);
2293
+		if ($previous_status) {
2294
+			$this->delete_extra_meta(EE_Registration::PRE_TRASH_REG_STATUS_KEY);
2295
+			$this->set_status($previous_status);
2296
+		}
2297
+		return parent::restore();
2298
+	}
2299
+
2300
+
2301
+	/**
2302
+	 * possibly toggle Registration status based on comparison of REG_paid vs REG_final_price
2303
+	 *
2304
+	 * @param boolean $trigger_set_status_logic  EE_Registration::set_status() can trigger additional logic
2305
+	 *                                           depending on whether the reg status changes to or from "Approved"
2306
+	 * @return boolean whether the Registration status was updated
2307
+	 * @throws DomainException
2308
+	 * @throws EE_Error
2309
+	 * @throws EntityNotFoundException
2310
+	 * @throws InvalidArgumentException
2311
+	 * @throws InvalidDataTypeException
2312
+	 * @throws InvalidInterfaceException
2313
+	 * @throws ReflectionException
2314
+	 * @throws RuntimeException
2315
+	 * @throws UnexpectedEntityException
2316
+	 */
2317
+	public function updateStatusBasedOnTotalPaid($trigger_set_status_logic = true)
2318
+	{
2319
+		$paid  = $this->paid();
2320
+		$price = $this->final_price();
2321
+		switch (true) {
2322
+			// overpaid or paid
2323
+			case EEH_Money::compare_floats($paid, $price, '>'):
2324
+			case EEH_Money::compare_floats($paid, $price):
2325
+				$new_status = EEM_Registration::status_id_approved;
2326
+				break;
2327
+			//  underpaid
2328
+			case EEH_Money::compare_floats($paid, $price, '<'):
2329
+				$new_status = EEM_Registration::status_id_pending_payment;
2330
+				break;
2331
+			// uhhh Houston...
2332
+			default:
2333
+				throw new RuntimeException(
2334
+					esc_html__('The total paid calculation for this registration is inaccurate.', 'event_espresso')
2335
+				);
2336
+		}
2337
+		if ($new_status !== $this->status_ID()) {
2338
+			if ($trigger_set_status_logic) {
2339
+				return $this->set_status($new_status);
2340
+			}
2341
+			parent::set('STS_ID', $new_status);
2342
+			return true;
2343
+		}
2344
+		return false;
2345
+	}
2346
+
2347
+
2348
+	/*************************** DEPRECATED ***************************/
2349
+
2350
+
2351
+	/**
2352
+	 * @deprecated
2353
+	 * @since     4.7.0
2354
+	 */
2355
+	public function price_paid()
2356
+	{
2357
+		EE_Error::doing_it_wrong(
2358
+			'EE_Registration::price_paid()',
2359
+			esc_html__(
2360
+				'This method is deprecated, please use EE_Registration::final_price() instead.',
2361
+				'event_espresso'
2362
+			),
2363
+			'4.7.0'
2364
+		);
2365
+		return $this->final_price();
2366
+	}
2367
+
2368
+
2369
+	/**
2370
+	 * @param float $REG_final_price
2371
+	 * @throws EE_Error
2372
+	 * @throws EntityNotFoundException
2373
+	 * @throws InvalidArgumentException
2374
+	 * @throws InvalidDataTypeException
2375
+	 * @throws InvalidInterfaceException
2376
+	 * @throws ReflectionException
2377
+	 * @throws RuntimeException
2378
+	 * @throws DomainException
2379
+	 * @deprecated
2380
+	 * @since     4.7.0
2381
+	 */
2382
+	public function set_price_paid($REG_final_price = 0.00)
2383
+	{
2384
+		EE_Error::doing_it_wrong(
2385
+			'EE_Registration::set_price_paid()',
2386
+			esc_html__(
2387
+				'This method is deprecated, please use EE_Registration::set_final_price() instead.',
2388
+				'event_espresso'
2389
+			),
2390
+			'4.7.0'
2391
+		);
2392
+		$this->set_final_price($REG_final_price);
2393
+	}
2394
+
2395
+
2396
+	/**
2397
+	 * @return string
2398
+	 * @throws EE_Error
2399
+	 * @throws InvalidArgumentException
2400
+	 * @throws InvalidDataTypeException
2401
+	 * @throws InvalidInterfaceException
2402
+	 * @throws ReflectionException
2403
+	 * @deprecated
2404
+	 * @since 4.7.0
2405
+	 */
2406
+	public function pretty_price_paid()
2407
+	{
2408
+		EE_Error::doing_it_wrong(
2409
+			'EE_Registration::pretty_price_paid()',
2410
+			esc_html__(
2411
+				'This method is deprecated, please use EE_Registration::pretty_final_price() instead.',
2412
+				'event_espresso'
2413
+			),
2414
+			'4.7.0'
2415
+		);
2416
+		return $this->pretty_final_price();
2417
+	}
2418
+
2419
+
2420
+	/**
2421
+	 * Gets the primary datetime related to this registration via the related Event to this registration
2422
+	 *
2423
+	 * @return EE_Datetime
2424
+	 * @throws EE_Error
2425
+	 * @throws EntityNotFoundException
2426
+	 * @throws InvalidArgumentException
2427
+	 * @throws InvalidDataTypeException
2428
+	 * @throws InvalidInterfaceException
2429
+	 * @throws ReflectionException
2430
+	 * @deprecated 4.9.17
2431
+	 */
2432
+	public function get_related_primary_datetime()
2433
+	{
2434
+		EE_Error::doing_it_wrong(
2435
+			__METHOD__,
2436
+			esc_html__(
2437
+				'Use EE_Registration::get_latest_related_datetime() or EE_Registration::get_earliest_related_datetime()',
2438
+				'event_espresso'
2439
+			),
2440
+			'4.9.17',
2441
+			'5.0.0'
2442
+		);
2443
+		return $this->event()->primary_datetime();
2444
+	}
2445
+
2446
+
2447
+	/**
2448
+	 * Returns the contact's name (or "Unknown" if there is no contact.)
2449
+	 *
2450
+	 * @return string
2451
+	 * @throws EE_Error
2452
+	 * @throws InvalidArgumentException
2453
+	 * @throws InvalidDataTypeException
2454
+	 * @throws InvalidInterfaceException
2455
+	 * @throws ReflectionException
2456
+	 * @since 4.10.12.p
2457
+	 */
2458
+	public function name()
2459
+	{
2460
+		return $this->attendeeName();
2461
+	}
2462
+
2463
+
2464
+	/**
2465
+	 * @return bool
2466
+	 * @throws EE_Error
2467
+	 * @throws ReflectionException
2468
+	 */
2469
+	public function wasMoved(): bool
2470
+	{
2471
+		// only need to check 'registration-moved-to' because
2472
+		// the existence of a new REG ID means the registration was moved
2473
+		$reg_moved = $this->get_extra_meta('registration-moved-to', true, []);
2474
+		return isset($reg_moved['NEW_REG_ID']) && $reg_moved['NEW_REG_ID'];
2475
+	}
2476
+
2477
+
2478
+	/**
2479
+	 * @param EE_Payment $payment
2480
+	 * @param float|null $amount
2481
+	 * @return float
2482
+	 * @throws EE_Error
2483
+	 * @throws ReflectionException
2484
+	 * @since 5.0.8.p
2485
+	 */
2486
+	public function applyPayment(EE_Payment $payment, ?float $amount = null): float
2487
+	{
2488
+		// echo "\n\n";
2489
+		// \EEH_Debug_Tools::printr(__FUNCTION__, __CLASS__, __FILE__, __LINE__, 3);
2490
+		// \EEH_Debug_Tools::printr($this->ID(), 'REG ID', __FILE__, __LINE__);
2491
+		$payment_amount = $amount ?? $payment->amount();
2492
+		// ensure $payment_amount is NOT negative
2493
+		$payment_amount = (float) abs($payment_amount);
2494
+		// \EEH_Debug_Tools::printr($payment_amount, 'incoming $payment_amount', __FILE__, __LINE__);
2495
+		// \EEH_Debug_Tools::printr($this->final_price(), 'reg final price', __FILE__, __LINE__);
2496
+		// \EEH_Debug_Tools::printr($this->paid(), 'reg paid to date', __FILE__, __LINE__);
2497
+		$payment_amount = $payment->is_a_refund()
2498
+			? $this->processRefund($payment_amount)
2499
+			: $this->processPayment($payment_amount);
2500
+		// \EEH_Debug_Tools::printr($payment_amount, 'applied payment_amount', __FILE__, __LINE__);
2501
+		if ($payment_amount) {
2502
+			$reg_payment = EEM_Registration_Payment::instance()->get_one(
2503
+				[['REG_ID' => $this->ID(), 'PAY_ID' => $payment->ID()]]
2504
+			);
2505
+			// if existing registration payment exists
2506
+			if ($reg_payment instanceof EE_Registration_Payment) {
2507
+				// echo "\nUPDATE EXISTING REG PAYMENT";
2508
+				// then update that record
2509
+				$reg_payment->set_amount($payment_amount);
2510
+			} else {
2511
+				// echo "\nCREATE NEW REG PAYMENT";
2512
+				// or add new relation between registration and payment and set amount
2513
+				$reg_payment = EE_Registration_Payment::new_instance(
2514
+					[
2515
+						'REG_ID'     => $this->ID(),
2516
+						'PAY_ID'     => $payment->ID(),
2517
+						'RPY_amount' => $payment_amount,
2518
+					]
2519
+				);
2520
+				// $this->_add_relation_to($payment, 'Payment', ['RPY_amount' => $payment_amount]);
2521
+			}
2522
+			$reg_payment->save();
2523
+			// \EEH_Debug_Tools::printr($reg_payment->ID(), '$reg payment ID', __FILE__, __LINE__);
2524
+		}
2525
+		return $payment_amount;
2526
+	}
2527
+
2528
+
2529
+	/**
2530
+	 * @throws EE_Error
2531
+	 * @throws ReflectionException
2532
+	 */
2533
+	private function processPayment(float $payment_amount): float
2534
+	{
2535
+		// echo "\n";
2536
+		// \EEH_Debug_Tools::printr(__FUNCTION__, __CLASS__, __FILE__, __LINE__, 3);
2537
+		$paid  = $this->paid();
2538
+		$owing = $this->final_price() - $paid;
2539
+		// \EEH_Debug_Tools::printr($owing, '$owing', __FILE__, __LINE__);
2540
+		if ($owing <= 0) {
2541
+			return 0.0;
2542
+		}
2543
+		// don't allow payment amount to exceed the incoming amount, OR the amount owing
2544
+		$payment_amount = min($payment_amount, $owing);
2545
+		$paid           = $paid + $payment_amount;
2546
+		// \EEH_Debug_Tools::printr($paid, 'NEW REG PAID AMOUNT', __FILE__, __LINE__);
2547
+		// calculate and set new REG_paid
2548
+		$this->set_paid($paid);
2549
+		// make it stick
2550
+		$this->save();
2551
+		return (float) $payment_amount;
2552
+	}
2553
+
2554
+
2555
+	/**
2556
+	 * @throws ReflectionException
2557
+	 * @throws EE_Error
2558
+	 */
2559
+	private function processRefund(float $payment_amount): float
2560
+	{
2561
+		// echo "\n";
2562
+		// \EEH_Debug_Tools::printr(__FUNCTION__, __CLASS__, __FILE__, __LINE__, 3);
2563
+		$paid = $this->paid();
2564
+		if ($paid <= 0) {
2565
+			return 0.0;
2566
+		}
2567
+		// don't allow refund amount to exceed the incoming amount, OR the amount paid
2568
+		$payment_amount = min($payment_amount, $paid);
2569
+		// calculate and set new REG_paid
2570
+		$paid = $paid - $payment_amount;
2571
+		// \EEH_Debug_Tools::printr($paid, 'NEW REG PAID AMOUNT', __FILE__, __LINE__);
2572
+		$this->set_paid($paid);
2573
+		// make it stick
2574
+		$this->save();
2575
+		// convert payment amount back to a negative value for storage in the db
2576
+		return (float) $payment_amount;
2577
+	}
2578 2578
 }
Please login to merge, or discard this patch.
core/db_classes/EE_Question_Form_Input.class.php 2 patches
Indentation   +371 added lines, -371 removed lines patch added patch discarded remove patch
@@ -15,375 +15,375 @@
 block discarded – undo
15 15
  */
16 16
 class EE_Question_Form_Input
17 17
 {
18
-    protected RequestInterface $request;
19
-
20
-    protected array $form_data;
21
-
22
-    private ?EE_Question $_QST = null;
23
-
24
-
25
-    private ?EE_Answer $_ANS = null;
26
-
27
-    /**
28
-     * $_QST_meta
29
-     * @var array
30
-     */
31
-    private array $_QST_meta = [];
32
-
33
-    /**
34
-     * $QST_input_name
35
-     * @var string
36
-     */
37
-    private string $QST_input_name = '';
38
-
39
-    /**
40
-     * $QST_input_id
41
-     * @var string
42
-     */
43
-    private string $QST_input_id = '';
44
-
45
-    /**
46
-     * $QST_input_class
47
-     * @var string
48
-     */
49
-    private string $QST_input_class = '';
50
-
51
-    private bool $QST_disabled = false;
52
-
53
-
54
-    /**
55
-     * @param EE_Question|null $QST EE_Question object
56
-     * @param EE_Answer|null   $ANS EE_Answer object
57
-     * @param array            $q_meta
58
-     * @throws EE_Error
59
-     * @throws ReflectionException
60
-     */
61
-    public function __construct(EE_Question $QST = null, EE_Answer $ANS = null, array $q_meta = [])
62
-    {
63
-        $this->request   = LoaderFactory::getLoader()->getShared(RequestInterface::class);
64
-        $this->form_data = $this->request->requestParams();
65
-        if (empty($QST) || empty($ANS)) {
66
-            EE_Error::add_error(
67
-                esc_html__(
68
-                    'An error occurred. A valid EE_Question or EE_Answer object was not received.',
69
-                    'event_espresso'
70
-                ),
71
-                __FILE__,
72
-                __FUNCTION__,
73
-                __LINE__
74
-            );
75
-            return null;
76
-        }
77
-        $this->_QST = $QST;
78
-        $this->_ANS = $ANS;
79
-        $this->set_question_form_input_meta($q_meta);
80
-        $this->set_question_form_input_init();
81
-    }
82
-
83
-
84
-    /**
85
-     * sets meta data for the question form input
86
-     *
87
-     * @param array $q_meta
88
-     * @return void
89
-     */
90
-    public function set_question_form_input_meta(array $q_meta = [])
91
-    {
92
-        $default_q_meta  = [
93
-            'att_nmbr'       => 1,
94
-            'ticket_id'      => '',
95
-            'date'           => '',
96
-            'time'           => '',
97
-            'input_name'     => '',
98
-            'input_id'       => '',
99
-            'input_class'    => '',
100
-            'label_class'    => '',
101
-            'input_prefix'   => 'qstn',
102
-            'append_qstn_id' => true,
103
-            'htmlentities'   => true,
104
-            'allow_null'     => false,
105
-        ];
106
-        $this->_QST_meta = array_merge($default_q_meta, $q_meta);
107
-    }
108
-
109
-
110
-    /**
111
-     * @return void
112
-     * @throws EE_Error
113
-     * @throws ReflectionException
114
-     */
115
-    public function set_question_form_input_init()
116
-    {
117
-        $qstn_id = $this->_QST->system_ID() ? $this->_QST->system_ID() : $this->_QST->ID();
118
-        $this->_set_input_name($qstn_id);
119
-        $this->_set_input_id($qstn_id);
120
-        $this->_set_input_class();
121
-        $this->set_question_form_input_answer($qstn_id);
122
-    }
123
-
124
-
125
-    /**
126
-     * @param $qstn_id
127
-     * @return void
128
-     * @throws EE_Error
129
-     * @throws ReflectionException
130
-     */
131
-    private function _set_input_name($qstn_id)
132
-    {
133
-        if (! empty($qstn_id)) {
134
-            $ANS_ID  = $this->get('ANS_ID');
135
-            $qstn_id = ! empty($ANS_ID) ? '[' . $qstn_id . '][' . $ANS_ID . ']' : '[' . $qstn_id . ']';
136
-        }
137
-        $this->QST_input_name = $this->_QST_meta['append_qstn_id'] && ! empty($qstn_id)
138
-            ? $this->_QST_meta['input_prefix'] . $this->_QST_meta['input_name'] . $qstn_id
139
-            : $this->_QST_meta['input_prefix'] . $this->_QST_meta['input_name'];
140
-    }
141
-
142
-
143
-    /**
144
-     * get property values for question form input
145
-     *
146
-     * @param string $property
147
-     * @return mixed
148
-     * @throws EE_Error
149
-     * @throws ReflectionException
150
-     */
151
-    public function get(string $property = '')
152
-    {
153
-        if (! empty($property)) {
154
-            if (EEM_Question::instance()->has_field($property)) {
155
-                return $this->_QST->get($property);
156
-            } elseif (EEM_Answer::instance()->has_field($property)) {
157
-                return $this->_ANS->get($property);
158
-            // } elseif ($this->_question_form_input_property_exists($property)) {
159
-            } elseif (property_exists($this, $property)) {
160
-                return $this->{$property};
161
-            }
162
-        }
163
-        return null;
164
-    }
165
-
166
-
167
-    /**
168
-     * set property values for question form input
169
-     *
170
-     * @param string $property
171
-     * @param mixed  $value
172
-     * @return void
173
-     * @throws EE_Error
174
-     * @throws ReflectionException
175
-     */
176
-    public function set(string $property = '', $value = null)
177
-    {
178
-        if (! empty($property)) {
179
-            if (EEM_Question::instance()->has_field($property)) {
180
-                $this->_QST->set($property, $value);
181
-            } elseif (EEM_Answer::instance()->has_field($property)) {
182
-                $this->_ANS->set($property, $value);
183
-            } elseif (property_exists($this, $property)) {
184
-                $this->{$property} = $value;
185
-            }
186
-        }
187
-    }
188
-
189
-
190
-    /**
191
-     * @param $qstn_id
192
-     * @return void
193
-     * @throws EE_Error
194
-     * @throws ReflectionException
195
-     */
196
-    private function _set_input_id($qstn_id)
197
-    {
198
-        $input_id           = isset($this->_QST_meta['input_id']) && ! empty($this->_QST_meta['input_id'])
199
-            ? $this->_QST_meta['input_id']
200
-            : sanitize_key(strip_tags($this->_QST->get('QST_display_text')));
201
-        $this->QST_input_id = $this->_QST_meta['append_qstn_id'] && ! empty($qstn_id)
202
-            ? $input_id . '-' . $qstn_id
203
-            : $input_id;
204
-    }
205
-
206
-
207
-    /**
208
-     * @return void
209
-     */
210
-    private function _set_input_class()
211
-    {
212
-        $this->QST_input_class = $this->_QST_meta['input_class'] ?? '';
213
-    }
214
-
215
-
216
-    /**
217
-     * @param int|string $qstn_id
218
-     * @return void
219
-     * @throws EE_Error
220
-     * @throws ReflectionException
221
-     */
222
-    public function set_question_form_input_answer($qstn_id)
223
-    {
224
-        // check for answer in $this->form_data in case we are reprocessing a form after an error
225
-        if (
226
-            isset($this->_QST_meta['EVT_ID'])
227
-            && isset($this->_QST_meta['att_nmbr'])
228
-            && isset($this->_QST_meta['date'])
229
-            && isset($this->_QST_meta['time'])
230
-            && isset($this->_QST_meta['price_id'])
231
-        ) {
232
-            $EVT_ID   = $this->_QST_meta['EVT_ID'];
233
-            $att_nmbr = $this->_QST_meta['att_nmbr'];
234
-            $date     = $this->_QST_meta['date'];
235
-            $time     = $this->_QST_meta['time'];
236
-            $price_id = $this->_QST_meta['price_id'];
237
-            if (isset($this->form_data['qstn'][ $EVT_ID ][ $att_nmbr ][ $date ][ $time ][ $price_id ][ $qstn_id ])) {
238
-                $answer = $this->form_data['qstn'][ $EVT_ID ][ $att_nmbr ][ $date ][ $time ][ $price_id ][ $qstn_id ];
239
-                $this->_ANS->set('ANS_value', $answer);
240
-            }
241
-        }
242
-    }
243
-
244
-
245
-    /**
246
-     * @param EE_Base_class $object $object
247
-     * @param array         $input_types
248
-     * @return array
249
-     * @throws EE_Error
250
-     * @throws ReflectionException
251
-     */
252
-    public static function generate_question_form_inputs_for_object(
253
-        EE_Base_class $object,
254
-        array $input_types = []
255
-    ): array {
256
-        $inputs = [];
257
-        $fields = $object->get_model()->field_settings();
258
-        foreach ($fields as $field_ID => $field) {
259
-            if ($field instanceof EE_Model_Field_Base) {
260
-                if (isset($input_types[ $field_ID ])) {
261
-                    // label to display
262
-                    $label = $input_types[ $field_ID ]['label'] ?? $field->get_nicename();
263
-                    // get saved value for field
264
-                    $value = $object->get($field_ID);
265
-                    // if no saved value, then use default
266
-                    $value = $value ?? $field->get_default_value();
267
-                    // determine question type
268
-                    $type = $input_types[ $field_ID ]['type'] ?? 'TEXT';
269
-                    // input name
270
-                    $input_name = isset($input_types[ $field_ID ]['input_name'])
271
-                        ? $input_types[ $field_ID ]['input_name'] . '[' . $field_ID . ']'
272
-                        : $field_ID;
273
-                    // css class for input
274
-                    $class = $input_types[ $field_ID ]['class'] ?? '';
275
-                    // css class for label
276
-                    $label_class = $input_types[ $field_ID ]['label_class'] ?? '';
277
-                    // whether to apply htmlentities to answer
278
-                    $htmlentities = $input_types[ $field_ID ]['htmlentities'] ?? true;
279
-                    // whether to apply htmlentities to answer
280
-                    $label_b4 = $input_types[ $field_ID ]['label_b4'] ?? false;
281
-                    // whether to apply htmlentities to answer
282
-                    $use_desc_4_label = $input_types[ $field_ID ]['use_desc_4_label'] ?? false;
283
-                    // whether input is disabled
284
-                    $disabled = isset($input_types[ $field_ID ]['disabled']) && $input_types[ $field_ID ]['disabled'];
285
-                    // use a different label on mobile devices
286
-                    $add_mobile_label = isset($input_types[ $field_ID ]['add_mobile_label'])
287
-                        && $input_types[ $field_ID ]['add_mobile_label'];
288
-
289
-                    // create EE_Question_Form_Input object
290
-                    $QFI = new EE_Question_Form_Input(
291
-                        EE_Question::new_instance(
292
-                            [
293
-                                'QST_ID'           => 0,
294
-                                'QST_display_text' => $label,
295
-                                'QST_type'         => $type,
296
-                            ]
297
-                        ),
298
-                        EE_Answer::new_instance(
299
-                            [
300
-                                'ANS_ID'    => 0,
301
-                                'QST_ID'    => 0,
302
-                                'REG_ID'    => 0,
303
-                                'ANS_value' => $value,
304
-                            ]
305
-                        ),
306
-                        [
307
-                            'input_id'         => "$field_ID-{$object->ID()}",
308
-                            'input_name'       => $input_name,
309
-                            'input_class'      => "$field_ID $class",
310
-                            'label_class'      => $label_class,
311
-                            'input_prefix'     => '',
312
-                            'append_qstn_id'   => false,
313
-                            'htmlentities'     => $htmlentities,
314
-                            'label_b4'         => $label_b4,
315
-                            'use_desc_4_label' => $use_desc_4_label,
316
-                            'add_mobile_label' => $add_mobile_label,
317
-                        ]
318
-                    );
319
-                    // does question type have options ?
320
-                    if (
321
-                        in_array($type, ['DROPDOWN', 'RADIO_BTN', 'CHECKBOX'])
322
-                        && isset($input_types[ $field_ID ]['options'])
323
-                    ) {
324
-                        foreach ($input_types[ $field_ID ]['options'] as $option) {
325
-                            $option    = stripslashes_deep($option);
326
-                            $option_id = $option['id'] ?? null;
327
-                            $QSO       = EE_Question_Option::new_instance(
328
-                                [
329
-                                    'QSO_value'   => (string) $option_id,
330
-                                    'QSO_desc'    => $option['text'],
331
-                                    'QSO_deleted' => false,
332
-                                ]
333
-                            );
334
-                            // all QST (and ANS) properties can be accessed indirectly thru QFI
335
-                            $QFI->add_temp_option($QSO);
336
-                        }
337
-                    }
338
-                    // we don't want ppl manually changing primary keys cuz that would just lead to total craziness man
339
-                    if ($disabled || $field_ID == $object->get_model()->primary_key_name()) {
340
-                        $QFI->QST_disabled = true;
341
-                    }
342
-                    $inputs[ $field_ID ] = $QFI;
343
-                }
344
-            }
345
-        }
346
-        return $inputs;
347
-    }
348
-
349
-
350
-    /**
351
-     * @param EE_Question_Option $QSO EE_Question_Option
352
-     * @return void
353
-     */
354
-    public function add_temp_option(EE_Question_Option $QSO)
355
-    {
356
-        $this->_QST->add_temp_option($QSO);
357
-    }
358
-
359
-
360
-    /**
361
-     * @param boolean           $notDeletedOptionsOnly            whether to return ALL options, or only the ones which
362
-     *                                                            have not yet been deleted
363
-     * @param string|array|null $selected_value_to_always_include when retrieving options to an ANSWERED question,
364
-     *                                                            we want to usually only show non-deleted options AND
365
-     *                                                            the value that was selected for the answer, whether
366
-     *                                                            it was trashed or not.
367
-     * @return EE_Question_Option[]
368
-     */
369
-    public function options(bool $notDeletedOptionsOnly = true, $selected_value_to_always_include = null): array
370
-    {
371
-        $temp_options = $this->_QST->temp_options();
372
-        return ! empty($temp_options)
373
-            ? $temp_options
374
-            : $this->_QST->options(
375
-                $notDeletedOptionsOnly,
376
-                $selected_value_to_always_include
377
-            );
378
-    }
379
-
380
-
381
-    /**
382
-     * @param mixed $key
383
-     * @return mixed
384
-     */
385
-    public function get_meta($key = false)
386
-    {
387
-        return $key && isset($this->_QST_meta[ $key ]) ? $this->_QST_meta[ $key ] : false;
388
-    }
18
+	protected RequestInterface $request;
19
+
20
+	protected array $form_data;
21
+
22
+	private ?EE_Question $_QST = null;
23
+
24
+
25
+	private ?EE_Answer $_ANS = null;
26
+
27
+	/**
28
+	 * $_QST_meta
29
+	 * @var array
30
+	 */
31
+	private array $_QST_meta = [];
32
+
33
+	/**
34
+	 * $QST_input_name
35
+	 * @var string
36
+	 */
37
+	private string $QST_input_name = '';
38
+
39
+	/**
40
+	 * $QST_input_id
41
+	 * @var string
42
+	 */
43
+	private string $QST_input_id = '';
44
+
45
+	/**
46
+	 * $QST_input_class
47
+	 * @var string
48
+	 */
49
+	private string $QST_input_class = '';
50
+
51
+	private bool $QST_disabled = false;
52
+
53
+
54
+	/**
55
+	 * @param EE_Question|null $QST EE_Question object
56
+	 * @param EE_Answer|null   $ANS EE_Answer object
57
+	 * @param array            $q_meta
58
+	 * @throws EE_Error
59
+	 * @throws ReflectionException
60
+	 */
61
+	public function __construct(EE_Question $QST = null, EE_Answer $ANS = null, array $q_meta = [])
62
+	{
63
+		$this->request   = LoaderFactory::getLoader()->getShared(RequestInterface::class);
64
+		$this->form_data = $this->request->requestParams();
65
+		if (empty($QST) || empty($ANS)) {
66
+			EE_Error::add_error(
67
+				esc_html__(
68
+					'An error occurred. A valid EE_Question or EE_Answer object was not received.',
69
+					'event_espresso'
70
+				),
71
+				__FILE__,
72
+				__FUNCTION__,
73
+				__LINE__
74
+			);
75
+			return null;
76
+		}
77
+		$this->_QST = $QST;
78
+		$this->_ANS = $ANS;
79
+		$this->set_question_form_input_meta($q_meta);
80
+		$this->set_question_form_input_init();
81
+	}
82
+
83
+
84
+	/**
85
+	 * sets meta data for the question form input
86
+	 *
87
+	 * @param array $q_meta
88
+	 * @return void
89
+	 */
90
+	public function set_question_form_input_meta(array $q_meta = [])
91
+	{
92
+		$default_q_meta  = [
93
+			'att_nmbr'       => 1,
94
+			'ticket_id'      => '',
95
+			'date'           => '',
96
+			'time'           => '',
97
+			'input_name'     => '',
98
+			'input_id'       => '',
99
+			'input_class'    => '',
100
+			'label_class'    => '',
101
+			'input_prefix'   => 'qstn',
102
+			'append_qstn_id' => true,
103
+			'htmlentities'   => true,
104
+			'allow_null'     => false,
105
+		];
106
+		$this->_QST_meta = array_merge($default_q_meta, $q_meta);
107
+	}
108
+
109
+
110
+	/**
111
+	 * @return void
112
+	 * @throws EE_Error
113
+	 * @throws ReflectionException
114
+	 */
115
+	public function set_question_form_input_init()
116
+	{
117
+		$qstn_id = $this->_QST->system_ID() ? $this->_QST->system_ID() : $this->_QST->ID();
118
+		$this->_set_input_name($qstn_id);
119
+		$this->_set_input_id($qstn_id);
120
+		$this->_set_input_class();
121
+		$this->set_question_form_input_answer($qstn_id);
122
+	}
123
+
124
+
125
+	/**
126
+	 * @param $qstn_id
127
+	 * @return void
128
+	 * @throws EE_Error
129
+	 * @throws ReflectionException
130
+	 */
131
+	private function _set_input_name($qstn_id)
132
+	{
133
+		if (! empty($qstn_id)) {
134
+			$ANS_ID  = $this->get('ANS_ID');
135
+			$qstn_id = ! empty($ANS_ID) ? '[' . $qstn_id . '][' . $ANS_ID . ']' : '[' . $qstn_id . ']';
136
+		}
137
+		$this->QST_input_name = $this->_QST_meta['append_qstn_id'] && ! empty($qstn_id)
138
+			? $this->_QST_meta['input_prefix'] . $this->_QST_meta['input_name'] . $qstn_id
139
+			: $this->_QST_meta['input_prefix'] . $this->_QST_meta['input_name'];
140
+	}
141
+
142
+
143
+	/**
144
+	 * get property values for question form input
145
+	 *
146
+	 * @param string $property
147
+	 * @return mixed
148
+	 * @throws EE_Error
149
+	 * @throws ReflectionException
150
+	 */
151
+	public function get(string $property = '')
152
+	{
153
+		if (! empty($property)) {
154
+			if (EEM_Question::instance()->has_field($property)) {
155
+				return $this->_QST->get($property);
156
+			} elseif (EEM_Answer::instance()->has_field($property)) {
157
+				return $this->_ANS->get($property);
158
+			// } elseif ($this->_question_form_input_property_exists($property)) {
159
+			} elseif (property_exists($this, $property)) {
160
+				return $this->{$property};
161
+			}
162
+		}
163
+		return null;
164
+	}
165
+
166
+
167
+	/**
168
+	 * set property values for question form input
169
+	 *
170
+	 * @param string $property
171
+	 * @param mixed  $value
172
+	 * @return void
173
+	 * @throws EE_Error
174
+	 * @throws ReflectionException
175
+	 */
176
+	public function set(string $property = '', $value = null)
177
+	{
178
+		if (! empty($property)) {
179
+			if (EEM_Question::instance()->has_field($property)) {
180
+				$this->_QST->set($property, $value);
181
+			} elseif (EEM_Answer::instance()->has_field($property)) {
182
+				$this->_ANS->set($property, $value);
183
+			} elseif (property_exists($this, $property)) {
184
+				$this->{$property} = $value;
185
+			}
186
+		}
187
+	}
188
+
189
+
190
+	/**
191
+	 * @param $qstn_id
192
+	 * @return void
193
+	 * @throws EE_Error
194
+	 * @throws ReflectionException
195
+	 */
196
+	private function _set_input_id($qstn_id)
197
+	{
198
+		$input_id           = isset($this->_QST_meta['input_id']) && ! empty($this->_QST_meta['input_id'])
199
+			? $this->_QST_meta['input_id']
200
+			: sanitize_key(strip_tags($this->_QST->get('QST_display_text')));
201
+		$this->QST_input_id = $this->_QST_meta['append_qstn_id'] && ! empty($qstn_id)
202
+			? $input_id . '-' . $qstn_id
203
+			: $input_id;
204
+	}
205
+
206
+
207
+	/**
208
+	 * @return void
209
+	 */
210
+	private function _set_input_class()
211
+	{
212
+		$this->QST_input_class = $this->_QST_meta['input_class'] ?? '';
213
+	}
214
+
215
+
216
+	/**
217
+	 * @param int|string $qstn_id
218
+	 * @return void
219
+	 * @throws EE_Error
220
+	 * @throws ReflectionException
221
+	 */
222
+	public function set_question_form_input_answer($qstn_id)
223
+	{
224
+		// check for answer in $this->form_data in case we are reprocessing a form after an error
225
+		if (
226
+			isset($this->_QST_meta['EVT_ID'])
227
+			&& isset($this->_QST_meta['att_nmbr'])
228
+			&& isset($this->_QST_meta['date'])
229
+			&& isset($this->_QST_meta['time'])
230
+			&& isset($this->_QST_meta['price_id'])
231
+		) {
232
+			$EVT_ID   = $this->_QST_meta['EVT_ID'];
233
+			$att_nmbr = $this->_QST_meta['att_nmbr'];
234
+			$date     = $this->_QST_meta['date'];
235
+			$time     = $this->_QST_meta['time'];
236
+			$price_id = $this->_QST_meta['price_id'];
237
+			if (isset($this->form_data['qstn'][ $EVT_ID ][ $att_nmbr ][ $date ][ $time ][ $price_id ][ $qstn_id ])) {
238
+				$answer = $this->form_data['qstn'][ $EVT_ID ][ $att_nmbr ][ $date ][ $time ][ $price_id ][ $qstn_id ];
239
+				$this->_ANS->set('ANS_value', $answer);
240
+			}
241
+		}
242
+	}
243
+
244
+
245
+	/**
246
+	 * @param EE_Base_class $object $object
247
+	 * @param array         $input_types
248
+	 * @return array
249
+	 * @throws EE_Error
250
+	 * @throws ReflectionException
251
+	 */
252
+	public static function generate_question_form_inputs_for_object(
253
+		EE_Base_class $object,
254
+		array $input_types = []
255
+	): array {
256
+		$inputs = [];
257
+		$fields = $object->get_model()->field_settings();
258
+		foreach ($fields as $field_ID => $field) {
259
+			if ($field instanceof EE_Model_Field_Base) {
260
+				if (isset($input_types[ $field_ID ])) {
261
+					// label to display
262
+					$label = $input_types[ $field_ID ]['label'] ?? $field->get_nicename();
263
+					// get saved value for field
264
+					$value = $object->get($field_ID);
265
+					// if no saved value, then use default
266
+					$value = $value ?? $field->get_default_value();
267
+					// determine question type
268
+					$type = $input_types[ $field_ID ]['type'] ?? 'TEXT';
269
+					// input name
270
+					$input_name = isset($input_types[ $field_ID ]['input_name'])
271
+						? $input_types[ $field_ID ]['input_name'] . '[' . $field_ID . ']'
272
+						: $field_ID;
273
+					// css class for input
274
+					$class = $input_types[ $field_ID ]['class'] ?? '';
275
+					// css class for label
276
+					$label_class = $input_types[ $field_ID ]['label_class'] ?? '';
277
+					// whether to apply htmlentities to answer
278
+					$htmlentities = $input_types[ $field_ID ]['htmlentities'] ?? true;
279
+					// whether to apply htmlentities to answer
280
+					$label_b4 = $input_types[ $field_ID ]['label_b4'] ?? false;
281
+					// whether to apply htmlentities to answer
282
+					$use_desc_4_label = $input_types[ $field_ID ]['use_desc_4_label'] ?? false;
283
+					// whether input is disabled
284
+					$disabled = isset($input_types[ $field_ID ]['disabled']) && $input_types[ $field_ID ]['disabled'];
285
+					// use a different label on mobile devices
286
+					$add_mobile_label = isset($input_types[ $field_ID ]['add_mobile_label'])
287
+						&& $input_types[ $field_ID ]['add_mobile_label'];
288
+
289
+					// create EE_Question_Form_Input object
290
+					$QFI = new EE_Question_Form_Input(
291
+						EE_Question::new_instance(
292
+							[
293
+								'QST_ID'           => 0,
294
+								'QST_display_text' => $label,
295
+								'QST_type'         => $type,
296
+							]
297
+						),
298
+						EE_Answer::new_instance(
299
+							[
300
+								'ANS_ID'    => 0,
301
+								'QST_ID'    => 0,
302
+								'REG_ID'    => 0,
303
+								'ANS_value' => $value,
304
+							]
305
+						),
306
+						[
307
+							'input_id'         => "$field_ID-{$object->ID()}",
308
+							'input_name'       => $input_name,
309
+							'input_class'      => "$field_ID $class",
310
+							'label_class'      => $label_class,
311
+							'input_prefix'     => '',
312
+							'append_qstn_id'   => false,
313
+							'htmlentities'     => $htmlentities,
314
+							'label_b4'         => $label_b4,
315
+							'use_desc_4_label' => $use_desc_4_label,
316
+							'add_mobile_label' => $add_mobile_label,
317
+						]
318
+					);
319
+					// does question type have options ?
320
+					if (
321
+						in_array($type, ['DROPDOWN', 'RADIO_BTN', 'CHECKBOX'])
322
+						&& isset($input_types[ $field_ID ]['options'])
323
+					) {
324
+						foreach ($input_types[ $field_ID ]['options'] as $option) {
325
+							$option    = stripslashes_deep($option);
326
+							$option_id = $option['id'] ?? null;
327
+							$QSO       = EE_Question_Option::new_instance(
328
+								[
329
+									'QSO_value'   => (string) $option_id,
330
+									'QSO_desc'    => $option['text'],
331
+									'QSO_deleted' => false,
332
+								]
333
+							);
334
+							// all QST (and ANS) properties can be accessed indirectly thru QFI
335
+							$QFI->add_temp_option($QSO);
336
+						}
337
+					}
338
+					// we don't want ppl manually changing primary keys cuz that would just lead to total craziness man
339
+					if ($disabled || $field_ID == $object->get_model()->primary_key_name()) {
340
+						$QFI->QST_disabled = true;
341
+					}
342
+					$inputs[ $field_ID ] = $QFI;
343
+				}
344
+			}
345
+		}
346
+		return $inputs;
347
+	}
348
+
349
+
350
+	/**
351
+	 * @param EE_Question_Option $QSO EE_Question_Option
352
+	 * @return void
353
+	 */
354
+	public function add_temp_option(EE_Question_Option $QSO)
355
+	{
356
+		$this->_QST->add_temp_option($QSO);
357
+	}
358
+
359
+
360
+	/**
361
+	 * @param boolean           $notDeletedOptionsOnly            whether to return ALL options, or only the ones which
362
+	 *                                                            have not yet been deleted
363
+	 * @param string|array|null $selected_value_to_always_include when retrieving options to an ANSWERED question,
364
+	 *                                                            we want to usually only show non-deleted options AND
365
+	 *                                                            the value that was selected for the answer, whether
366
+	 *                                                            it was trashed or not.
367
+	 * @return EE_Question_Option[]
368
+	 */
369
+	public function options(bool $notDeletedOptionsOnly = true, $selected_value_to_always_include = null): array
370
+	{
371
+		$temp_options = $this->_QST->temp_options();
372
+		return ! empty($temp_options)
373
+			? $temp_options
374
+			: $this->_QST->options(
375
+				$notDeletedOptionsOnly,
376
+				$selected_value_to_always_include
377
+			);
378
+	}
379
+
380
+
381
+	/**
382
+	 * @param mixed $key
383
+	 * @return mixed
384
+	 */
385
+	public function get_meta($key = false)
386
+	{
387
+		return $key && isset($this->_QST_meta[ $key ]) ? $this->_QST_meta[ $key ] : false;
388
+	}
389 389
 }
Please login to merge, or discard this patch.
Spacing   +27 added lines, -27 removed lines patch added patch discarded remove patch
@@ -89,7 +89,7 @@  discard block
 block discarded – undo
89 89
      */
90 90
     public function set_question_form_input_meta(array $q_meta = [])
91 91
     {
92
-        $default_q_meta  = [
92
+        $default_q_meta = [
93 93
             'att_nmbr'       => 1,
94 94
             'ticket_id'      => '',
95 95
             'date'           => '',
@@ -130,13 +130,13 @@  discard block
 block discarded – undo
130 130
      */
131 131
     private function _set_input_name($qstn_id)
132 132
     {
133
-        if (! empty($qstn_id)) {
133
+        if ( ! empty($qstn_id)) {
134 134
             $ANS_ID  = $this->get('ANS_ID');
135
-            $qstn_id = ! empty($ANS_ID) ? '[' . $qstn_id . '][' . $ANS_ID . ']' : '[' . $qstn_id . ']';
135
+            $qstn_id = ! empty($ANS_ID) ? '['.$qstn_id.']['.$ANS_ID.']' : '['.$qstn_id.']';
136 136
         }
137 137
         $this->QST_input_name = $this->_QST_meta['append_qstn_id'] && ! empty($qstn_id)
138
-            ? $this->_QST_meta['input_prefix'] . $this->_QST_meta['input_name'] . $qstn_id
139
-            : $this->_QST_meta['input_prefix'] . $this->_QST_meta['input_name'];
138
+            ? $this->_QST_meta['input_prefix'].$this->_QST_meta['input_name'].$qstn_id
139
+            : $this->_QST_meta['input_prefix'].$this->_QST_meta['input_name'];
140 140
     }
141 141
 
142 142
 
@@ -150,7 +150,7 @@  discard block
 block discarded – undo
150 150
      */
151 151
     public function get(string $property = '')
152 152
     {
153
-        if (! empty($property)) {
153
+        if ( ! empty($property)) {
154 154
             if (EEM_Question::instance()->has_field($property)) {
155 155
                 return $this->_QST->get($property);
156 156
             } elseif (EEM_Answer::instance()->has_field($property)) {
@@ -175,7 +175,7 @@  discard block
 block discarded – undo
175 175
      */
176 176
     public function set(string $property = '', $value = null)
177 177
     {
178
-        if (! empty($property)) {
178
+        if ( ! empty($property)) {
179 179
             if (EEM_Question::instance()->has_field($property)) {
180 180
                 $this->_QST->set($property, $value);
181 181
             } elseif (EEM_Answer::instance()->has_field($property)) {
@@ -199,7 +199,7 @@  discard block
 block discarded – undo
199 199
             ? $this->_QST_meta['input_id']
200 200
             : sanitize_key(strip_tags($this->_QST->get('QST_display_text')));
201 201
         $this->QST_input_id = $this->_QST_meta['append_qstn_id'] && ! empty($qstn_id)
202
-            ? $input_id . '-' . $qstn_id
202
+            ? $input_id.'-'.$qstn_id
203 203
             : $input_id;
204 204
     }
205 205
 
@@ -234,8 +234,8 @@  discard block
 block discarded – undo
234 234
             $date     = $this->_QST_meta['date'];
235 235
             $time     = $this->_QST_meta['time'];
236 236
             $price_id = $this->_QST_meta['price_id'];
237
-            if (isset($this->form_data['qstn'][ $EVT_ID ][ $att_nmbr ][ $date ][ $time ][ $price_id ][ $qstn_id ])) {
238
-                $answer = $this->form_data['qstn'][ $EVT_ID ][ $att_nmbr ][ $date ][ $time ][ $price_id ][ $qstn_id ];
237
+            if (isset($this->form_data['qstn'][$EVT_ID][$att_nmbr][$date][$time][$price_id][$qstn_id])) {
238
+                $answer = $this->form_data['qstn'][$EVT_ID][$att_nmbr][$date][$time][$price_id][$qstn_id];
239 239
                 $this->_ANS->set('ANS_value', $answer);
240 240
             }
241 241
         }
@@ -257,34 +257,34 @@  discard block
 block discarded – undo
257 257
         $fields = $object->get_model()->field_settings();
258 258
         foreach ($fields as $field_ID => $field) {
259 259
             if ($field instanceof EE_Model_Field_Base) {
260
-                if (isset($input_types[ $field_ID ])) {
260
+                if (isset($input_types[$field_ID])) {
261 261
                     // label to display
262
-                    $label = $input_types[ $field_ID ]['label'] ?? $field->get_nicename();
262
+                    $label = $input_types[$field_ID]['label'] ?? $field->get_nicename();
263 263
                     // get saved value for field
264 264
                     $value = $object->get($field_ID);
265 265
                     // if no saved value, then use default
266 266
                     $value = $value ?? $field->get_default_value();
267 267
                     // determine question type
268
-                    $type = $input_types[ $field_ID ]['type'] ?? 'TEXT';
268
+                    $type = $input_types[$field_ID]['type'] ?? 'TEXT';
269 269
                     // input name
270
-                    $input_name = isset($input_types[ $field_ID ]['input_name'])
271
-                        ? $input_types[ $field_ID ]['input_name'] . '[' . $field_ID . ']'
270
+                    $input_name = isset($input_types[$field_ID]['input_name'])
271
+                        ? $input_types[$field_ID]['input_name'].'['.$field_ID.']'
272 272
                         : $field_ID;
273 273
                     // css class for input
274
-                    $class = $input_types[ $field_ID ]['class'] ?? '';
274
+                    $class = $input_types[$field_ID]['class'] ?? '';
275 275
                     // css class for label
276
-                    $label_class = $input_types[ $field_ID ]['label_class'] ?? '';
276
+                    $label_class = $input_types[$field_ID]['label_class'] ?? '';
277 277
                     // whether to apply htmlentities to answer
278
-                    $htmlentities = $input_types[ $field_ID ]['htmlentities'] ?? true;
278
+                    $htmlentities = $input_types[$field_ID]['htmlentities'] ?? true;
279 279
                     // whether to apply htmlentities to answer
280
-                    $label_b4 = $input_types[ $field_ID ]['label_b4'] ?? false;
280
+                    $label_b4 = $input_types[$field_ID]['label_b4'] ?? false;
281 281
                     // whether to apply htmlentities to answer
282
-                    $use_desc_4_label = $input_types[ $field_ID ]['use_desc_4_label'] ?? false;
282
+                    $use_desc_4_label = $input_types[$field_ID]['use_desc_4_label'] ?? false;
283 283
                     // whether input is disabled
284
-                    $disabled = isset($input_types[ $field_ID ]['disabled']) && $input_types[ $field_ID ]['disabled'];
284
+                    $disabled = isset($input_types[$field_ID]['disabled']) && $input_types[$field_ID]['disabled'];
285 285
                     // use a different label on mobile devices
286
-                    $add_mobile_label = isset($input_types[ $field_ID ]['add_mobile_label'])
287
-                        && $input_types[ $field_ID ]['add_mobile_label'];
286
+                    $add_mobile_label = isset($input_types[$field_ID]['add_mobile_label'])
287
+                        && $input_types[$field_ID]['add_mobile_label'];
288 288
 
289 289
                     // create EE_Question_Form_Input object
290 290
                     $QFI = new EE_Question_Form_Input(
@@ -319,9 +319,9 @@  discard block
 block discarded – undo
319 319
                     // does question type have options ?
320 320
                     if (
321 321
                         in_array($type, ['DROPDOWN', 'RADIO_BTN', 'CHECKBOX'])
322
-                        && isset($input_types[ $field_ID ]['options'])
322
+                        && isset($input_types[$field_ID]['options'])
323 323
                     ) {
324
-                        foreach ($input_types[ $field_ID ]['options'] as $option) {
324
+                        foreach ($input_types[$field_ID]['options'] as $option) {
325 325
                             $option    = stripslashes_deep($option);
326 326
                             $option_id = $option['id'] ?? null;
327 327
                             $QSO       = EE_Question_Option::new_instance(
@@ -339,7 +339,7 @@  discard block
 block discarded – undo
339 339
                     if ($disabled || $field_ID == $object->get_model()->primary_key_name()) {
340 340
                         $QFI->QST_disabled = true;
341 341
                     }
342
-                    $inputs[ $field_ID ] = $QFI;
342
+                    $inputs[$field_ID] = $QFI;
343 343
                 }
344 344
             }
345 345
         }
@@ -384,6 +384,6 @@  discard block
 block discarded – undo
384 384
      */
385 385
     public function get_meta($key = false)
386 386
     {
387
-        return $key && isset($this->_QST_meta[ $key ]) ? $this->_QST_meta[ $key ] : false;
387
+        return $key && isset($this->_QST_meta[$key]) ? $this->_QST_meta[$key] : false;
388 388
     }
389 389
 }
Please login to merge, or discard this patch.
core/exceptions/InsufficientPermissionsException.php 1 patch
Indentation   +20 added lines, -20 removed lines patch added patch discarded remove patch
@@ -14,24 +14,24 @@
 block discarded – undo
14 14
  */
15 15
 class InsufficientPermissionsException extends \RuntimeException
16 16
 {
17
-    /**
18
-     * @access public
19
-     * @param string          $action
20
-     * @param string          $message
21
-     * @param int             $code
22
-     * @param Exception|null $previous
23
-     */
24
-    public function __construct($action, $message = '', $code = 0, Exception $previous = null)
25
-    {
26
-        if (empty($message)) {
27
-            $message = sprintf(
28
-                esc_html__(
29
-                    'We\'re sorry, but you do not have the required permissions to perform the following action: %1$s',
30
-                    'event_espresso'
31
-                ),
32
-                ucwords(str_replace('_', ' ', $action))
33
-            );
34
-        }
35
-        parent::__construct($message, $code, $previous);
36
-    }
17
+	/**
18
+	 * @access public
19
+	 * @param string          $action
20
+	 * @param string          $message
21
+	 * @param int             $code
22
+	 * @param Exception|null $previous
23
+	 */
24
+	public function __construct($action, $message = '', $code = 0, Exception $previous = null)
25
+	{
26
+		if (empty($message)) {
27
+			$message = sprintf(
28
+				esc_html__(
29
+					'We\'re sorry, but you do not have the required permissions to perform the following action: %1$s',
30
+					'event_espresso'
31
+				),
32
+				ucwords(str_replace('_', ' ', $action))
33
+			);
34
+		}
35
+		parent::__construct($message, $code, $previous);
36
+	}
37 37
 }
Please login to merge, or discard this patch.
caffeinated/admin/new/tickets/Tickets_List_Table.class.php 1 patch
Indentation   +170 added lines, -170 removed lines patch added patch discarded remove patch
@@ -16,174 +16,174 @@
 block discarded – undo
16 16
  */
17 17
 class Tickets_List_Table extends EE_Admin_List_Table
18 18
 {
19
-    protected function _setup_data()
20
-    {
21
-        // \EEH_Debug_Tools::printr(__FUNCTION__, __CLASS__, __FILE__, __LINE__, 2);
22
-        $trashed = $this->_admin_page->get_view() == 'trashed' ? true : false;
23
-        $this->_data = $this->_admin_page->get_default_tickets($this->_per_page, false, $trashed);
24
-        $this->_all_data_count = $this->_admin_page->get_default_tickets($this->_per_page, true, false);
25
-        $this->_trashed_count = $this->_admin_page->get_default_tickets($this->_per_page, true, true);
26
-    }
27
-
28
-
29
-    protected function _set_properties()
30
-    {
31
-        $this->_wp_list_args = array(
32
-            'singular' => esc_html__('ticket', 'event_espresso'),
33
-            'plural'   => esc_html__('tickets', 'event_espresso'),
34
-            'ajax'     => true,
35
-            'screen'   => $this->_admin_page->get_current_screen()->id,
36
-        );
37
-
38
-        $this->_columns = array(
39
-            'cb'              => '<input type="checkbox" />', // Render a checkbox instead of text
40
-            'id'              => esc_html__('ID', 'event_espresso'),
41
-            'TKT_name'        => esc_html__('Name', 'event_espresso'),
42
-            'TKT_description' => esc_html__('Description', 'event_espresso'),
43
-            'TKT_qty'         => esc_html__('Quantity', 'event_espresso'),
44
-            'TKT_uses'        => esc_html__('Uses', 'event_espresso'),
45
-            'TKT_min'         => esc_html__('Minimum', 'event_espresso'),
46
-            'TKT_max'         => esc_html__('Maximum', 'event_espresso'),
47
-            'TKT_price'       => esc_html__('Price', 'event_espresso'),
48
-            'TKT_taxable'     => esc_html__('Taxable', 'event_espresso'),
49
-        );
50
-
51
-        $this->_sortable_columns = array(
52
-            // TRUE means its already sorted
53
-            'id' => array('TKT_ID', false),
54
-            'TKT_name'        => array('TKT_name', true),
55
-            'TKT_description' => array('TKT_description', false),
56
-            'TKT_qty'         => array('TKT_qty', false),
57
-            'TKT_uses'        => array('TKT_uses', false),
58
-            'TKT_min'         => array('TKT_min', false),
59
-            'TKT_max'         => array('TKT_max', false),
60
-            'TKT_price'       => array('TKT_price', false),
61
-        );
62
-
63
-        $this->_hidden_columns = array();
64
-    }
65
-
66
-
67
-    protected function _get_table_filters()
68
-    {
69
-        return [];
70
-    }
71
-
72
-
73
-    protected function _add_view_counts()
74
-    {
75
-        $this->_views['all']['count'] = $this->_all_data_count;
76
-        if (EE_Registry::instance()->CAP->current_user_can('ee_delete_default_tickets', 'trash_ticket')) {
77
-            $this->_views['trashed']['count'] = $this->_trashed_count;
78
-        }
79
-    }
80
-
81
-
82
-    public function column_cb($item)
83
-    {
84
-        return $item->ID() === 1
85
-            ? '<span class="dashicons dashicons-lock"></span>'
86
-            : sprintf(
87
-                '<input type="checkbox" name="checkbox[%1$s]" value="%1$s" />',
88
-                $item->ID()
89
-            );
90
-    }
91
-
92
-
93
-    /**
94
-     * @param EE_Ticket $item
95
-     * @return string
96
-     * @throws EE_Error
97
-     * @throws ReflectionException
98
-     */
99
-    public function column_id($item): string
100
-    {
101
-        $content = '<span class="ee-entity-id">' . $item->ID() . '</span>';
102
-        $content .= '<span class="show-on-mobile-view-only">' . $this->column_TKT_name($item, false) . '</span>';
103
-        return $this->columnContent('id', $content, 'end');
104
-    }
105
-
106
-
107
-    public function column_TKT_name(EE_Ticket $ticket, bool $prep_content = true): string
108
-    {
109
-        // build row actions
110
-        $actions = array();
111
-
112
-        // trash links
113
-        if ($ticket->ID() !== 1) {
114
-            if ($this->_view == 'all') {
115
-                $trash_lnk_url = EE_Admin_Page::add_query_args_and_nonce(array(
116
-                    'action' => 'trash_ticket',
117
-                    'TKT_ID' => $ticket->ID(),
118
-                ), TICKETS_ADMIN_URL);
119
-                $actions['trash'] = '<a href="' . $trash_lnk_url . '" aria-label="'
120
-                                    . esc_attr__('Move Ticket to trash', 'event_espresso') . '">'
121
-                                    . esc_html__('Trash', 'event_espresso') . '</a>';
122
-            } else {
123
-                // restore price link
124
-                $restore_lnk_url = EE_Admin_Page::add_query_args_and_nonce(array(
125
-                    'action' => 'restore_ticket',
126
-                    'TKT_ID' => $ticket->ID(),
127
-                ), TICKETS_ADMIN_URL);
128
-                $actions['restore'] = '<a href="' . $restore_lnk_url . '" aria-label="'
129
-                                      . esc_attr__('Restore Ticket', 'event_espresso') . '">'
130
-                                      . esc_html__('Restore', 'event_espresso') . '</a>';
131
-                // delete price link
132
-                $delete_lnk_url = EE_Admin_Page::add_query_args_and_nonce(array(
133
-                    'action' => 'delete_ticket',
134
-                    'TKT_ID' => $ticket->ID(),
135
-                ), TICKETS_ADMIN_URL);
136
-                $actions['delete'] = '<a href="' . $delete_lnk_url . '" aria-label="'
137
-                                     . esc_attr__('Delete Ticket Permanently', 'event_espresso') . '">'
138
-                                     . esc_html__('Delete Permanently', 'event_espresso') . '</a>';
139
-            }
140
-        }
141
-        // return $ticket->get('TKT_name') . $this->row_actions($actions);
142
-        $content = $prep_content ? $ticket->name() . $this->row_actions($actions) : $ticket->name();
143
-        return $prep_content ? $this->columnContent('TKT_name', $content) : $content;
144
-    }
145
-
146
-
147
-    public function column_TKT_description(EE_Ticket $ticket)
148
-    {
149
-        return $this->columnContent('TKT_description', $ticket->description());
150
-    }
151
-
152
-
153
-    public function column_TKT_qty(EE_Ticket $ticket)
154
-    {
155
-
156
-        return $ticket->get_pretty('TKT_qty', 'text');
157
-        // return $this->columnContent('TKT_qty', $ticket->qty());
158
-    }
159
-
160
-
161
-    public function column_TKT_uses(EE_Ticket $ticket)
162
-    {
163
-        return $ticket->get_pretty('TKT_uses', 'text');
164
-    }
165
-
166
-
167
-    public function column_TKT_min(EE_Ticket $ticket)
168
-    {
169
-        return $ticket->get('TKT_min');
170
-    }
171
-
172
-
173
-    public function column_TKT_max(EE_Ticket $ticket)
174
-    {
175
-        return $ticket->get_pretty('TKT_max', 'text');
176
-    }
177
-
178
-
179
-    public function column_TKT_price(EE_Ticket $ticket)
180
-    {
181
-        return EEH_Template::format_currency($ticket->get('TKT_price'));
182
-    }
183
-
184
-
185
-    public function column_TKT_taxable(EE_Ticket $ticket)
186
-    {
187
-        return $ticket->get('TKT_taxable') ? esc_html__('Yes', 'event_espresso') : esc_html__('No', 'event_espresso');
188
-    }
19
+	protected function _setup_data()
20
+	{
21
+		// \EEH_Debug_Tools::printr(__FUNCTION__, __CLASS__, __FILE__, __LINE__, 2);
22
+		$trashed = $this->_admin_page->get_view() == 'trashed' ? true : false;
23
+		$this->_data = $this->_admin_page->get_default_tickets($this->_per_page, false, $trashed);
24
+		$this->_all_data_count = $this->_admin_page->get_default_tickets($this->_per_page, true, false);
25
+		$this->_trashed_count = $this->_admin_page->get_default_tickets($this->_per_page, true, true);
26
+	}
27
+
28
+
29
+	protected function _set_properties()
30
+	{
31
+		$this->_wp_list_args = array(
32
+			'singular' => esc_html__('ticket', 'event_espresso'),
33
+			'plural'   => esc_html__('tickets', 'event_espresso'),
34
+			'ajax'     => true,
35
+			'screen'   => $this->_admin_page->get_current_screen()->id,
36
+		);
37
+
38
+		$this->_columns = array(
39
+			'cb'              => '<input type="checkbox" />', // Render a checkbox instead of text
40
+			'id'              => esc_html__('ID', 'event_espresso'),
41
+			'TKT_name'        => esc_html__('Name', 'event_espresso'),
42
+			'TKT_description' => esc_html__('Description', 'event_espresso'),
43
+			'TKT_qty'         => esc_html__('Quantity', 'event_espresso'),
44
+			'TKT_uses'        => esc_html__('Uses', 'event_espresso'),
45
+			'TKT_min'         => esc_html__('Minimum', 'event_espresso'),
46
+			'TKT_max'         => esc_html__('Maximum', 'event_espresso'),
47
+			'TKT_price'       => esc_html__('Price', 'event_espresso'),
48
+			'TKT_taxable'     => esc_html__('Taxable', 'event_espresso'),
49
+		);
50
+
51
+		$this->_sortable_columns = array(
52
+			// TRUE means its already sorted
53
+			'id' => array('TKT_ID', false),
54
+			'TKT_name'        => array('TKT_name', true),
55
+			'TKT_description' => array('TKT_description', false),
56
+			'TKT_qty'         => array('TKT_qty', false),
57
+			'TKT_uses'        => array('TKT_uses', false),
58
+			'TKT_min'         => array('TKT_min', false),
59
+			'TKT_max'         => array('TKT_max', false),
60
+			'TKT_price'       => array('TKT_price', false),
61
+		);
62
+
63
+		$this->_hidden_columns = array();
64
+	}
65
+
66
+
67
+	protected function _get_table_filters()
68
+	{
69
+		return [];
70
+	}
71
+
72
+
73
+	protected function _add_view_counts()
74
+	{
75
+		$this->_views['all']['count'] = $this->_all_data_count;
76
+		if (EE_Registry::instance()->CAP->current_user_can('ee_delete_default_tickets', 'trash_ticket')) {
77
+			$this->_views['trashed']['count'] = $this->_trashed_count;
78
+		}
79
+	}
80
+
81
+
82
+	public function column_cb($item)
83
+	{
84
+		return $item->ID() === 1
85
+			? '<span class="dashicons dashicons-lock"></span>'
86
+			: sprintf(
87
+				'<input type="checkbox" name="checkbox[%1$s]" value="%1$s" />',
88
+				$item->ID()
89
+			);
90
+	}
91
+
92
+
93
+	/**
94
+	 * @param EE_Ticket $item
95
+	 * @return string
96
+	 * @throws EE_Error
97
+	 * @throws ReflectionException
98
+	 */
99
+	public function column_id($item): string
100
+	{
101
+		$content = '<span class="ee-entity-id">' . $item->ID() . '</span>';
102
+		$content .= '<span class="show-on-mobile-view-only">' . $this->column_TKT_name($item, false) . '</span>';
103
+		return $this->columnContent('id', $content, 'end');
104
+	}
105
+
106
+
107
+	public function column_TKT_name(EE_Ticket $ticket, bool $prep_content = true): string
108
+	{
109
+		// build row actions
110
+		$actions = array();
111
+
112
+		// trash links
113
+		if ($ticket->ID() !== 1) {
114
+			if ($this->_view == 'all') {
115
+				$trash_lnk_url = EE_Admin_Page::add_query_args_and_nonce(array(
116
+					'action' => 'trash_ticket',
117
+					'TKT_ID' => $ticket->ID(),
118
+				), TICKETS_ADMIN_URL);
119
+				$actions['trash'] = '<a href="' . $trash_lnk_url . '" aria-label="'
120
+									. esc_attr__('Move Ticket to trash', 'event_espresso') . '">'
121
+									. esc_html__('Trash', 'event_espresso') . '</a>';
122
+			} else {
123
+				// restore price link
124
+				$restore_lnk_url = EE_Admin_Page::add_query_args_and_nonce(array(
125
+					'action' => 'restore_ticket',
126
+					'TKT_ID' => $ticket->ID(),
127
+				), TICKETS_ADMIN_URL);
128
+				$actions['restore'] = '<a href="' . $restore_lnk_url . '" aria-label="'
129
+									  . esc_attr__('Restore Ticket', 'event_espresso') . '">'
130
+									  . esc_html__('Restore', 'event_espresso') . '</a>';
131
+				// delete price link
132
+				$delete_lnk_url = EE_Admin_Page::add_query_args_and_nonce(array(
133
+					'action' => 'delete_ticket',
134
+					'TKT_ID' => $ticket->ID(),
135
+				), TICKETS_ADMIN_URL);
136
+				$actions['delete'] = '<a href="' . $delete_lnk_url . '" aria-label="'
137
+									 . esc_attr__('Delete Ticket Permanently', 'event_espresso') . '">'
138
+									 . esc_html__('Delete Permanently', 'event_espresso') . '</a>';
139
+			}
140
+		}
141
+		// return $ticket->get('TKT_name') . $this->row_actions($actions);
142
+		$content = $prep_content ? $ticket->name() . $this->row_actions($actions) : $ticket->name();
143
+		return $prep_content ? $this->columnContent('TKT_name', $content) : $content;
144
+	}
145
+
146
+
147
+	public function column_TKT_description(EE_Ticket $ticket)
148
+	{
149
+		return $this->columnContent('TKT_description', $ticket->description());
150
+	}
151
+
152
+
153
+	public function column_TKT_qty(EE_Ticket $ticket)
154
+	{
155
+
156
+		return $ticket->get_pretty('TKT_qty', 'text');
157
+		// return $this->columnContent('TKT_qty', $ticket->qty());
158
+	}
159
+
160
+
161
+	public function column_TKT_uses(EE_Ticket $ticket)
162
+	{
163
+		return $ticket->get_pretty('TKT_uses', 'text');
164
+	}
165
+
166
+
167
+	public function column_TKT_min(EE_Ticket $ticket)
168
+	{
169
+		return $ticket->get('TKT_min');
170
+	}
171
+
172
+
173
+	public function column_TKT_max(EE_Ticket $ticket)
174
+	{
175
+		return $ticket->get_pretty('TKT_max', 'text');
176
+	}
177
+
178
+
179
+	public function column_TKT_price(EE_Ticket $ticket)
180
+	{
181
+		return EEH_Template::format_currency($ticket->get('TKT_price'));
182
+	}
183
+
184
+
185
+	public function column_TKT_taxable(EE_Ticket $ticket)
186
+	{
187
+		return $ticket->get('TKT_taxable') ? esc_html__('Yes', 'event_espresso') : esc_html__('No', 'event_espresso');
188
+	}
189 189
 }
Please login to merge, or discard this patch.