@@ -28,707 +28,707 @@ |
||
28 | 28 | */ |
29 | 29 | class RestIncomingQueryParamMetadata |
30 | 30 | { |
31 | - private $query_param_key; |
|
32 | - private $query_param_value; |
|
33 | - /** |
|
34 | - * @var RestIncomingQueryParamContext |
|
35 | - */ |
|
36 | - private $context; |
|
37 | - |
|
38 | - /** |
|
39 | - * @var EE_Model_Field_Base|null |
|
40 | - */ |
|
41 | - private $field; |
|
42 | - |
|
43 | - /** |
|
44 | - * @var string same as $query_param_key but has the * and anything after it removed |
|
45 | - */ |
|
46 | - private $query_param_key_sans_stars; |
|
47 | - |
|
48 | - /** |
|
49 | - * @var string for timezone or timezone offset |
|
50 | - */ |
|
51 | - private $timezone; |
|
52 | - |
|
53 | - /** |
|
54 | - * @var boolean if the field in $query_param_key is for a GMT field (eg `EVT_modified_gmt`) |
|
55 | - */ |
|
56 | - private $is_gmt_field = false; |
|
57 | - |
|
58 | - /** |
|
59 | - * RestIncomingQueryParamMetadata constructor. |
|
60 | - * You probably want to call |
|
61 | - * @param string $query_param_key |
|
62 | - * @param string $query_param_value |
|
63 | - * @param RestIncomingQueryParamContext $context |
|
64 | - */ |
|
65 | - public function __construct($query_param_key, $query_param_value, RestIncomingQueryParamContext $context) |
|
66 | - { |
|
67 | - $this->query_param_key = $query_param_key; |
|
68 | - $this->query_param_value = $query_param_value; |
|
69 | - $this->context = $context; |
|
70 | - $this->determineFieldAndTimezone(); |
|
71 | - } |
|
72 | - |
|
73 | - /** |
|
74 | - * Gets the query parameter key. This may have been modified (see setQueryParamValue()) |
|
75 | - * @return string |
|
76 | - */ |
|
77 | - public function getQueryParamKey() |
|
78 | - { |
|
79 | - return $this->query_param_key; |
|
80 | - } |
|
81 | - |
|
82 | - /** |
|
83 | - * Modifies the query parameter key passed in (Eg this is done when rewriting the simplified specified operator REST |
|
84 | - * query parameters into the legacy structure) |
|
85 | - * @param string|array|int|float $query_param_value |
|
86 | - */ |
|
87 | - private function setQueryParamValue($query_param_value) |
|
88 | - { |
|
89 | - $this->query_param_value = $query_param_value; |
|
90 | - } |
|
91 | - |
|
92 | - /** |
|
93 | - * Gets the original query parameter value passed in. |
|
94 | - * @return string |
|
95 | - */ |
|
96 | - public function getQueryParamValue() |
|
97 | - { |
|
98 | - return $this->query_param_value; |
|
99 | - } |
|
100 | - |
|
101 | - /** |
|
102 | - * Gets the context object. |
|
103 | - * @return RestIncomingQueryParamContext |
|
104 | - */ |
|
105 | - public function getContext() |
|
106 | - { |
|
107 | - return $this->context; |
|
108 | - } |
|
109 | - |
|
110 | - /** |
|
111 | - * Sets the query parameter key. This may be used to rewrite a key into its non-GMT alternative. |
|
112 | - * @param string $query_param_key |
|
113 | - */ |
|
114 | - private function setQueryParamKey($query_param_key) |
|
115 | - { |
|
116 | - $this->query_param_key = $query_param_key; |
|
117 | - } |
|
118 | - |
|
119 | - /** |
|
120 | - * Gets the field the query parameter key indicated. This may be null (in cases where the query parameter key |
|
121 | - * did not indicate a field, eg if it were `OR`). |
|
122 | - * @return EE_Model_Field_Base|null |
|
123 | - */ |
|
124 | - public function getField() |
|
125 | - { |
|
126 | - return $this->field; |
|
127 | - } |
|
128 | - |
|
129 | - /** |
|
130 | - * Gets the query parameter key (with the star and everything afterwards removed). |
|
131 | - * @return string |
|
132 | - */ |
|
133 | - public function getQueryParamKeySansStars() |
|
134 | - { |
|
135 | - return $this->query_param_key_sans_stars; |
|
136 | - } |
|
137 | - |
|
138 | - /** |
|
139 | - * Gets the timezone associated with this model (the site timezone, except for GMT datetime fields). |
|
140 | - * @return string |
|
141 | - */ |
|
142 | - public function getTimezone() |
|
143 | - { |
|
144 | - return $this->timezone; |
|
145 | - } |
|
146 | - |
|
147 | - /** |
|
148 | - * Returns whether or not this is a GMT field |
|
149 | - * @return boolean |
|
150 | - */ |
|
151 | - public function isGmtField() |
|
152 | - { |
|
153 | - return $this->is_gmt_field; |
|
154 | - } |
|
155 | - |
|
156 | - /** |
|
157 | - * Sets the field indicated by the query parameter key (might be null). |
|
158 | - * @param EE_Model_Field_Base|null $field |
|
159 | - */ |
|
160 | - private function setField(EE_Model_Field_Base $field = null) |
|
161 | - { |
|
162 | - $this->field = $field; |
|
163 | - } |
|
164 | - |
|
165 | - /** |
|
166 | - * Sets the query parameter key-with-stars-removed. |
|
167 | - * @param string $query_param_key_sans_stars |
|
168 | - */ |
|
169 | - private function setQueryParamKeySansStars($query_param_key_sans_stars) |
|
170 | - { |
|
171 | - $this->query_param_key_sans_stars = $query_param_key_sans_stars; |
|
172 | - } |
|
173 | - |
|
174 | - /** |
|
175 | - * Sets the timezone (this could be a timezeon offset string). |
|
176 | - * @param string $timezone |
|
177 | - */ |
|
178 | - private function setTimezone($timezone) |
|
179 | - { |
|
180 | - $this->timezone = $timezone; |
|
181 | - } |
|
182 | - |
|
183 | - /** |
|
184 | - * @param mixed $is_gmt_field |
|
185 | - */ |
|
186 | - private function setIsGmtField($is_gmt_field) |
|
187 | - { |
|
188 | - $this->is_gmt_field = $is_gmt_field; |
|
189 | - } |
|
190 | - |
|
191 | - /** |
|
192 | - * Determines what field, query param name, and query param name without stars, and timezone to use. |
|
193 | - * @since 4.9.72.p |
|
194 | - * @type EE_Model_Field_Base $field |
|
195 | - * @return void { |
|
196 | - * @throws EE_Error |
|
197 | - * @throws InvalidDataTypeException |
|
198 | - * @throws InvalidInterfaceException |
|
199 | - * @throws InvalidArgumentException |
|
200 | - */ |
|
201 | - private function determineFieldAndTimezone() |
|
202 | - { |
|
203 | - $this->setQueryParamKeySansStars(ModelDataTranslator::removeStarsAndAnythingAfterFromConditionQueryParamKey( |
|
204 | - $this->getQueryParamKey() |
|
205 | - )); |
|
206 | - $this->setField(ModelDataTranslator::deduceFieldFromQueryParam( |
|
207 | - $this->getQueryParamKeySansStars(), |
|
208 | - $this->getContext()->getModel() |
|
209 | - )); |
|
210 | - // double-check is it a *_gmt field? |
|
211 | - if ( |
|
212 | - !$this->getField() instanceof EE_Model_Field_Base |
|
213 | - && ModelDataTranslator::isGmtDateFieldName($this->getQueryParamKeySansStars()) |
|
214 | - ) { |
|
215 | - // yep, take off '_gmt', and find the field |
|
216 | - $this->setQueryParamKey(ModelDataTranslator::removeGmtFromFieldName($this->getQueryParamKeySansStars())); |
|
217 | - $this->setField(ModelDataTranslator::deduceFieldFromQueryParam( |
|
218 | - $this->getQueryParamKey(), |
|
219 | - $this->context->getModel() |
|
220 | - )); |
|
221 | - $this->setTimezone('UTC'); |
|
222 | - $this->setIsGmtField(true); |
|
223 | - } elseif ($this->getField() instanceof EE_Datetime_Field) { |
|
224 | - // so it's not a GMT field. Set the timezone on the model to the default |
|
225 | - $this->setTimezone(EEH_DTT_Helper::get_valid_timezone_string()); |
|
226 | - } else { |
|
227 | - // just keep using what's already set for the timezone |
|
228 | - $this->setTimezone($this->context->getModel()->get_timezone()); |
|
229 | - } |
|
230 | - $this->assertOnlyAdminCanReadPasswordFields(); |
|
231 | - } |
|
232 | - |
|
233 | - /** |
|
234 | - * Throws an exception if a non-admin is trying to query by password. |
|
235 | - * @since 4.9.74.p |
|
236 | - * @throws RestException |
|
237 | - */ |
|
238 | - private function assertOnlyAdminCanReadPasswordFields() |
|
239 | - { |
|
240 | - if ( |
|
241 | - $this->getField() instanceof EE_Password_Field |
|
242 | - && ! current_user_can(EE_Restriction_Generator_Base::get_default_restrictions_cap()) |
|
243 | - ) { |
|
244 | - // only full admins can query by password. sorry bub! |
|
245 | - throw new RestException( |
|
246 | - 'only_admins_can_query_by_password', |
|
247 | - // @codingStandardsIgnoreStart |
|
248 | - esc_html__('You attempted to filter by a password field without the needed privileges. Only a full admin is allowed to do that.', 'event_espresso'), |
|
249 | - // @codingStandardsIgnoreEnd |
|
250 | - array( |
|
251 | - 'status' => 403 |
|
252 | - ) |
|
253 | - ); |
|
254 | - } |
|
255 | - } |
|
256 | - |
|
257 | - /** |
|
258 | - * Given a ton of input, determines the value to use for the models. |
|
259 | - * @since 4.9.72.p |
|
260 | - * @return array|null |
|
261 | - * @throws DomainException |
|
262 | - * @throws EE_Error |
|
263 | - * @throws RestException |
|
264 | - * @throws DomainException |
|
265 | - */ |
|
266 | - public function determineConditionsQueryParameterValue() |
|
267 | - { |
|
268 | - if ($this->valueIsArrayDuringRead()) { |
|
269 | - return $this->determineModelValueGivenRestInputArray(); |
|
270 | - } |
|
271 | - return ModelDataTranslator::prepareFieldValueFromJson( |
|
272 | - $this->getField(), |
|
273 | - $this->getQueryParamValue(), |
|
274 | - $this->getContext()->getRequestedVersion(), |
|
275 | - $this->getTimezone() |
|
276 | - ); |
|
277 | - } |
|
278 | - |
|
279 | - /** |
|
280 | - * Given that the array value provided was itself an array, handles finding the correct value to pass to the model. |
|
281 | - * @since 4.9.72.p |
|
282 | - * @return array|null |
|
283 | - * @throws RestException |
|
284 | - */ |
|
285 | - private function determineModelValueGivenRestInputArray() |
|
286 | - { |
|
287 | - $this->transformSimplifiedSpecifiedOperatorSyntaxIntoStandardSyntax(); |
|
288 | - // did they specify an operator? |
|
289 | - if ($this->valueIsLegacySpecifiedOperator()) { |
|
290 | - $query_param_value = $this->getQueryParamValue(); |
|
291 | - $sub_array_key = $query_param_value[0]; |
|
292 | - $translated_value = array($sub_array_key); |
|
293 | - if ($this->operatorIsNAry($sub_array_key)) { |
|
294 | - $translated_value[] = $this->prepareValuesFromJson($query_param_value[1]); |
|
295 | - } elseif ($this->operatorIsTernary($sub_array_key)) { |
|
296 | - $translated_value[] = array( |
|
297 | - $this->prepareValuesFromJson($query_param_value[1][0]), |
|
298 | - $this->prepareValuesFromJson($query_param_value[1][1]) |
|
299 | - ); |
|
300 | - } elseif ($this->operatorIsLike($sub_array_key)) { |
|
301 | - // we want to leave this value mostly-as-is (eg don't force it to be a float |
|
302 | - // or a boolean or an enum value. Leave it as-is with wildcards etc) |
|
303 | - // but do verify it at least doesn't have any serialized data |
|
304 | - ModelDataTranslator::throwExceptionIfContainsSerializedData($query_param_value[1]); |
|
305 | - $translated_value[] = $query_param_value[1]; |
|
306 | - } elseif ($this->operatorIsUnary($sub_array_key)) { |
|
307 | - // no arguments should have been provided, so don't look for any |
|
308 | - } elseif ($this->operatorisBinary($sub_array_key)) { |
|
309 | - // it's a valid operator, but none of the exceptions. Treat it normally. |
|
310 | - $translated_value[] = $this->prepareValuesFromJson($query_param_value[1]); |
|
311 | - } else { |
|
312 | - // so they provided a valid operator, but wrong number of arguments |
|
313 | - $this->throwWrongNumberOfArgsExceptionIfDebugging($sub_array_key); |
|
314 | - $translated_value = null; |
|
315 | - } |
|
316 | - } else { |
|
317 | - // so they didn't provide a valid operator |
|
318 | - // if we aren't in debug mode, then just try our best to fulfill the user's request |
|
319 | - $this->throwInvalidOperatorExceptionIfDebugging(); |
|
320 | - $translated_value = null; |
|
321 | - } |
|
322 | - return $translated_value; |
|
323 | - } |
|
324 | - |
|
325 | - /** |
|
326 | - * Returns if this request is a "read" request and the value provided was an array. |
|
327 | - * This will indicate is such things as `array('<', 123)` and `array('IN', array(1,2,3))` are acceptable or not. |
|
328 | - * @since 4.9.72.p |
|
329 | - * @return boolean |
|
330 | - */ |
|
331 | - private function valueIsArrayDuringRead() |
|
332 | - { |
|
333 | - return !$this->getContext()->isWriting() && is_array($this->getQueryParamValue()); |
|
334 | - } |
|
335 | - |
|
336 | - /** |
|
337 | - * Returns if the value provided was an associative array (we should have already verified it's an array of some |
|
338 | - * sort). If the value is an associative array, it had better be in the simplified specified operator structure. |
|
339 | - * @since 4.9.72.p |
|
340 | - * @return boolean |
|
341 | - */ |
|
342 | - private function valueIsAssociativeArray() |
|
343 | - { |
|
344 | - return !EEH_Array::is_array_numerically_and_sequentially_indexed($this->getQueryParamValue()); |
|
345 | - } |
|
346 | - |
|
347 | - /** |
|
348 | - * Checks if the array value is itself an array that fits into the simplified specified operator structure |
|
349 | - * (eg `array('!=' => 123)`). |
|
350 | - * @since 4.9.72.p |
|
351 | - * @return boolean |
|
352 | - */ |
|
353 | - private function valueIsSimplifiedSpecifiedOperator() |
|
354 | - { |
|
355 | - return count($this->getQueryParamValue()) === 1 |
|
356 | - && array_key_exists( |
|
357 | - key($this->getQueryParamValue()), |
|
358 | - $this->getContext()->getModel()->valid_operators() |
|
359 | - ); |
|
360 | - } |
|
361 | - |
|
362 | - /** |
|
363 | - * Throws an exception if the sub-value is an array (eg `array('!=' => array())`). It needs to just be a string, |
|
364 | - * of either comma-separated-values, or a JSON array. |
|
365 | - * @since 4.9.72.p |
|
366 | - * @param $sub_array_key |
|
367 | - * @param $sub_array_value |
|
368 | - * @throws RestException |
|
369 | - */ |
|
370 | - private function assertSubValueIsntArray($sub_array_key, $sub_array_value) |
|
371 | - { |
|
372 | - if (is_array($sub_array_value) && EED_Core_Rest_Api::debugMode()) { |
|
373 | - throw new RestException( |
|
374 | - 'csv_or_json_string_only', |
|
375 | - sprintf( |
|
376 | - /* translators: 1: variable name*/ |
|
377 | - esc_html__( |
|
378 | - 'The value provided for the operator "%1$s" should be comma-separated value string or a JSON array.', |
|
379 | - 'event_espresso' |
|
380 | - ), |
|
381 | - $sub_array_key |
|
382 | - ), |
|
383 | - array( |
|
384 | - 'status' => 400, |
|
385 | - ) |
|
386 | - ); |
|
387 | - } |
|
388 | - } |
|
389 | - |
|
390 | - /** |
|
391 | - * Determines if the sub-array key is an operator taking 3 or more operators. |
|
392 | - * @since 4.9.72.p |
|
393 | - * @param $sub_array_key |
|
394 | - * @return boolean |
|
395 | - */ |
|
396 | - private function subArrayKeyIsNonBinaryOperator($sub_array_key) |
|
397 | - { |
|
398 | - return array_key_exists( |
|
399 | - $sub_array_key, |
|
400 | - array_merge( |
|
401 | - $this->getContext()->getModel()->valid_in_style_operators(), |
|
402 | - $this->getContext()->getModel()->valid_between_style_operators() |
|
403 | - ) |
|
404 | - ); |
|
405 | - } |
|
406 | - |
|
407 | - /** |
|
408 | - * Given that the $sub_array_key is a string, checks if it's an operator taking only 1 argument. |
|
409 | - * @since 4.9.72.p |
|
410 | - * @param string $sub_array_key |
|
411 | - * @return boolean |
|
412 | - */ |
|
413 | - private function subArrayKeyIsUnaryOperator($sub_array_key) |
|
414 | - { |
|
415 | - return array_key_exists( |
|
416 | - $sub_array_key, |
|
417 | - $this->getContext()->getModel()->valid_null_style_operators() |
|
418 | - ); |
|
419 | - } |
|
420 | - |
|
421 | - /** |
|
422 | - * Parses the $sub_array_value string into an array (given it could either be a comma-separated-list or a JSON |
|
423 | - * array). eg `"1,2,3"` or `"[1,2,3]"` into `array(1,2,3)`. |
|
424 | - * @since 4.9.72.p |
|
425 | - * @param $sub_array_value |
|
426 | - * @return array|mixed|object |
|
427 | - */ |
|
428 | - private function extractQuickStyleSpecifiedOperatorValue($sub_array_value) |
|
429 | - { |
|
430 | - // the value should be JSON or CSV |
|
431 | - $values = json_decode($sub_array_value); |
|
432 | - if (!is_array($values)) { |
|
433 | - $values = array_filter( |
|
434 | - array_map( |
|
435 | - 'trim', |
|
436 | - explode( |
|
437 | - ',', |
|
438 | - $sub_array_value |
|
439 | - ) |
|
440 | - ) |
|
441 | - ); |
|
442 | - } |
|
443 | - return $values; |
|
444 | - } |
|
445 | - |
|
446 | - /** |
|
447 | - * Throws an exception if the value isn't a simplified specified operator (only called when we expect that). |
|
448 | - * @since 4.9.72.p |
|
449 | - * @throws RestException |
|
450 | - */ |
|
451 | - private function assertSimplifiedSpecifiedOperator() |
|
452 | - { |
|
453 | - if (!$this->valueIsSimplifiedSpecifiedOperator() && EED_Core_Rest_Api::debugMode()) { |
|
454 | - throw new RestException( |
|
455 | - 'numerically_indexed_array_of_values_only', |
|
456 | - sprintf( |
|
457 | - /* translators: 1: variable name*/ |
|
458 | - esc_html__( |
|
459 | - 'The array provided for the parameter "%1$s" should be numerically indexed.', |
|
460 | - 'event_espresso' |
|
461 | - ), |
|
462 | - $this->getQueryParamKey() |
|
463 | - ), |
|
464 | - array( |
|
465 | - 'status' => 400, |
|
466 | - ) |
|
467 | - ); |
|
468 | - } |
|
469 | - } |
|
470 | - |
|
471 | - /** |
|
472 | - * If query_param_value were in the simplified specific operator structure, change it into the legacy structure. |
|
473 | - * @since 4.9.72.p |
|
474 | - * @throws RestException |
|
475 | - */ |
|
476 | - private function transformSimplifiedSpecifiedOperatorSyntaxIntoStandardSyntax() |
|
477 | - { |
|
478 | - if ($this->valueIsAssociativeArray()) { |
|
479 | - $this->assertSimplifiedSpecifiedOperator(); |
|
480 | - $query_param_value = $this->getQueryParamValue(); |
|
481 | - $sub_array_value = reset($query_param_value); |
|
482 | - $sub_array_key = key($query_param_value); |
|
483 | - $this->assertSubValueIsntArray($sub_array_key, $sub_array_value); |
|
484 | - // they're doing something like "&where[EVT_ID][IN]=1,2,3" or "&where[EVT_ID][>]=5" |
|
485 | - if ($this->subArrayKeyIsNonBinaryOperator($sub_array_key)) { |
|
486 | - $this->setQueryParamValue(array( |
|
487 | - $sub_array_key, |
|
488 | - $this->extractQuickStyleSpecifiedOperatorValue($sub_array_value) |
|
489 | - )); |
|
490 | - } elseif ($this->subArrayKeyIsUnaryOperator($sub_array_key)) { |
|
491 | - $this->setQueryParamValue(array($sub_array_key)); |
|
492 | - } else { |
|
493 | - $this->setQueryParamValue(array($sub_array_key, $sub_array_value)); |
|
494 | - } |
|
495 | - } |
|
496 | - } |
|
497 | - |
|
498 | - /** |
|
499 | - * Returns true is the value is an array using the legacy structure to specify the operator. Eg `array('!=',123)`. |
|
500 | - * @since 4.9.72.p |
|
501 | - * @return boolean |
|
502 | - */ |
|
503 | - private function valueIsLegacySpecifiedOperator() |
|
504 | - { |
|
505 | - $valid_operators = $this->getContext()->getModel()->valid_operators(); |
|
506 | - $query_param_value = $this->getQueryParamValue(); |
|
507 | - return isset($query_param_value[0]) |
|
508 | - && isset($valid_operators[ $query_param_value[0] ]); |
|
509 | - } |
|
510 | - |
|
511 | - /** |
|
512 | - * Returns true if the value specified operator accepts arbitrary number of arguments, like "IN". |
|
513 | - * @since 4.9.72.p |
|
514 | - * @param $operator |
|
515 | - * @return boolean |
|
516 | - */ |
|
517 | - private function operatorIsNAry($operator) |
|
518 | - { |
|
519 | - $valueArray = $this->getQueryParamValue(); |
|
520 | - return array_key_exists( |
|
521 | - $operator, |
|
522 | - $this->getContext()->getModel()->valid_in_style_operators() |
|
523 | - ) |
|
524 | - && isset($valueArray[1]) |
|
525 | - && is_array($valueArray[1]) |
|
526 | - && !isset($valueArray[2]); |
|
527 | - } |
|
528 | - |
|
529 | - /** |
|
530 | - * Returns true if the operator accepts 3 arguments (eg "BETWEEN"). |
|
531 | - * So we're looking for a value that looks like |
|
532 | - * `array('BETWEEN', array('2015-01-01T00:00:00', '2016-01-01T00:00:00'))`. |
|
533 | - * @since 4.9.72.p |
|
534 | - * @param $operator |
|
535 | - * @return boolean |
|
536 | - */ |
|
537 | - private function operatorIsTernary($operator) |
|
538 | - { |
|
539 | - $query_param_value = $this->getQueryParamValue(); |
|
540 | - return array_key_exists($operator, $this->getContext()->getModel()->valid_between_style_operators()) |
|
541 | - && isset($query_param_value[1]) |
|
542 | - && is_array($query_param_value[1]) |
|
543 | - && isset($query_param_value[1][0], $query_param_value[1][1]) |
|
544 | - && !isset($query_param_value[1][2]) |
|
545 | - && !isset($query_param_value[2]); |
|
546 | - } |
|
547 | - |
|
548 | - /** |
|
549 | - * Returns true if the operator is a similar to LIKE, indicating the value may have wildcards we should leave alone. |
|
550 | - * @since 4.9.72.p |
|
551 | - * @param $operator |
|
552 | - * @return boolean |
|
553 | - */ |
|
554 | - private function operatorIsLike($operator) |
|
555 | - { |
|
556 | - $query_param_value = $this->getQueryParamValue(); |
|
557 | - return array_key_exists($operator, $this->getContext()->getModel()->valid_like_style_operators()) |
|
558 | - && isset($query_param_value[1]) |
|
559 | - && !isset($query_param_value[2]); |
|
560 | - } |
|
561 | - |
|
562 | - /** |
|
563 | - * Returns true if the operator only takes one argument (eg it's like `IS NULL`). |
|
564 | - * @since 4.9.72.p |
|
565 | - * @param $operator |
|
566 | - * @return boolean |
|
567 | - */ |
|
568 | - private function operatorIsUnary($operator) |
|
569 | - { |
|
570 | - $query_param_value = $this->getQueryParamValue(); |
|
571 | - return array_key_exists($operator, $this->getContext()->getModel()->valid_null_style_operators()) |
|
572 | - && !isset($query_param_value[1]); |
|
573 | - } |
|
574 | - |
|
575 | - /** |
|
576 | - * Returns true if the operator specified is a binary opeator (eg `=`, `!=`) |
|
577 | - * @since 4.9.72.p |
|
578 | - * @param $operator |
|
579 | - * @return boolean |
|
580 | - */ |
|
581 | - private function operatorisBinary($operator) |
|
582 | - { |
|
583 | - $query_param_value = $this->getQueryParamValue(); |
|
584 | - $model = $this->getContext()->getModel(); |
|
585 | - return isset($query_param_value[1]) |
|
586 | - && !isset($query_param_value[2]) |
|
587 | - && !array_key_exists( |
|
588 | - $operator, |
|
589 | - array_merge( |
|
590 | - $model->valid_in_style_operators(), |
|
591 | - $model->valid_null_style_operators(), |
|
592 | - $model->valid_like_style_operators(), |
|
593 | - $model->valid_between_style_operators() |
|
594 | - ) |
|
595 | - ); |
|
596 | - } |
|
597 | - |
|
598 | - /** |
|
599 | - * If we're debugging, throws an exception saying that the wrong number of arguments was provided. |
|
600 | - * @since 4.9.72.p |
|
601 | - * @param $operator |
|
602 | - * @throws RestException |
|
603 | - */ |
|
604 | - private function throwWrongNumberOfArgsExceptionIfDebugging($operator) |
|
605 | - { |
|
606 | - if (EED_Core_Rest_Api::debugMode()) { |
|
607 | - throw new RestException( |
|
608 | - 'wrong_number_of_arguments', |
|
609 | - sprintf( |
|
610 | - esc_html__( |
|
611 | - 'The operator you provided, "%1$s" had the wrong number of arguments', |
|
612 | - 'event_espresso' |
|
613 | - ), |
|
614 | - $operator |
|
615 | - ), |
|
616 | - array( |
|
617 | - 'status' => 400, |
|
618 | - ) |
|
619 | - ); |
|
620 | - } |
|
621 | - } |
|
622 | - |
|
623 | - /** |
|
624 | - * Wrapper for ModelDataTranslator::prepareFieldValuesFromJson(), just a tad more DRY. |
|
625 | - * @since 4.9.72.p |
|
626 | - * @param $value |
|
627 | - * @return mixed |
|
628 | - * @throws RestException |
|
629 | - */ |
|
630 | - private function prepareValuesFromJson($value) |
|
631 | - { |
|
632 | - return ModelDataTranslator::prepareFieldValuesFromJson( |
|
633 | - $this->getField(), |
|
634 | - $value, |
|
635 | - $this->getContext()->getRequestedVersion(), |
|
636 | - $this->getTimezone() |
|
637 | - ); |
|
638 | - } |
|
639 | - |
|
640 | - /** |
|
641 | - * Throws an exception if an invalid operator was specified and we're debugging. |
|
642 | - * @since 4.9.72.p |
|
643 | - * @throws RestException |
|
644 | - */ |
|
645 | - private function throwInvalidOperatorExceptionIfDebugging() |
|
646 | - { |
|
647 | - // so they didn't provide a valid operator |
|
648 | - if (EED_Core_Rest_Api::debugMode()) { |
|
649 | - throw new RestException( |
|
650 | - 'invalid_operator', |
|
651 | - sprintf( |
|
652 | - esc_html__( |
|
653 | - 'You provided an invalid parameter, with key "%1$s" and value "%2$s"', |
|
654 | - 'event_espresso' |
|
655 | - ), |
|
656 | - $this->getQueryParamKey(), |
|
657 | - $this->getQueryParamValue() |
|
658 | - ), |
|
659 | - array( |
|
660 | - 'status' => 400, |
|
661 | - ) |
|
662 | - ); |
|
663 | - } |
|
664 | - } |
|
665 | - |
|
666 | - /** |
|
667 | - * Returns true if the query_param_key was a logic query parameter, eg `OR`, `AND`, `NOT`, `OR*`, etc. |
|
668 | - * @since 4.9.72.p |
|
669 | - * @return boolean |
|
670 | - */ |
|
671 | - private function isLogicQueryParam() |
|
672 | - { |
|
673 | - return in_array($this->getQueryParamKeySansStars(), $this->getContext()->getModel()->logic_query_param_keys()); |
|
674 | - } |
|
675 | - |
|
676 | - |
|
677 | - /** |
|
678 | - * If the query param isn't for a field, it must be a nested query parameter which requires different logic. |
|
679 | - * @since 4.9.72.p |
|
680 | - * @return array |
|
681 | - * @throws DomainException |
|
682 | - * @throws EE_Error |
|
683 | - * @throws RestException |
|
684 | - * @throws InvalidDataTypeException |
|
685 | - * @throws InvalidInterfaceException |
|
686 | - * @throws InvalidArgumentException |
|
687 | - */ |
|
688 | - public function determineNestedConditionQueryParameters() |
|
689 | - { |
|
690 | - |
|
691 | - // so this param doesn't correspond to a field eh? |
|
692 | - if ($this->getContext()->isWriting()) { |
|
693 | - // always tell API clients about invalid parameters when they're creating data. Otherwise, |
|
694 | - // they are probably going to create invalid data |
|
695 | - throw new RestException( |
|
696 | - 'invalid_field', |
|
697 | - sprintf( |
|
698 | - /* translators: 1: variable name */ |
|
699 | - esc_html__('You have provided an invalid parameter: "%1$s"', 'event_espresso'), |
|
700 | - $this->getQueryParamKey() |
|
701 | - ) |
|
702 | - ); |
|
703 | - } |
|
704 | - // so it's not for a field, is it a logic query param key? |
|
705 | - if ($this->isLogicQueryParam()) { |
|
706 | - return ModelDataTranslator::prepareConditionsQueryParamsForModels( |
|
707 | - $this->getQueryParamValue(), |
|
708 | - $this->getContext()->getModel(), |
|
709 | - $this->getContext()->getRequestedVersion() |
|
710 | - ); |
|
711 | - } |
|
712 | - if (EED_Core_Rest_Api::debugMode()) { |
|
713 | - // only tell API clients they got it wrong if we're in debug mode |
|
714 | - // otherwise try our best ot fulfill their request by ignoring this invalid data |
|
715 | - throw new RestException( |
|
716 | - 'invalid_parameter', |
|
717 | - sprintf( |
|
718 | - /* translators: 1: variable name */ |
|
719 | - esc_html__( |
|
720 | - 'You provided an invalid parameter, with key "%1$s"', |
|
721 | - 'event_espresso' |
|
722 | - ), |
|
723 | - $this->getQueryParamKey() |
|
724 | - ), |
|
725 | - array( |
|
726 | - 'status' => 400, |
|
727 | - ) |
|
728 | - ); |
|
729 | - } |
|
730 | - return null; |
|
731 | - } |
|
31 | + private $query_param_key; |
|
32 | + private $query_param_value; |
|
33 | + /** |
|
34 | + * @var RestIncomingQueryParamContext |
|
35 | + */ |
|
36 | + private $context; |
|
37 | + |
|
38 | + /** |
|
39 | + * @var EE_Model_Field_Base|null |
|
40 | + */ |
|
41 | + private $field; |
|
42 | + |
|
43 | + /** |
|
44 | + * @var string same as $query_param_key but has the * and anything after it removed |
|
45 | + */ |
|
46 | + private $query_param_key_sans_stars; |
|
47 | + |
|
48 | + /** |
|
49 | + * @var string for timezone or timezone offset |
|
50 | + */ |
|
51 | + private $timezone; |
|
52 | + |
|
53 | + /** |
|
54 | + * @var boolean if the field in $query_param_key is for a GMT field (eg `EVT_modified_gmt`) |
|
55 | + */ |
|
56 | + private $is_gmt_field = false; |
|
57 | + |
|
58 | + /** |
|
59 | + * RestIncomingQueryParamMetadata constructor. |
|
60 | + * You probably want to call |
|
61 | + * @param string $query_param_key |
|
62 | + * @param string $query_param_value |
|
63 | + * @param RestIncomingQueryParamContext $context |
|
64 | + */ |
|
65 | + public function __construct($query_param_key, $query_param_value, RestIncomingQueryParamContext $context) |
|
66 | + { |
|
67 | + $this->query_param_key = $query_param_key; |
|
68 | + $this->query_param_value = $query_param_value; |
|
69 | + $this->context = $context; |
|
70 | + $this->determineFieldAndTimezone(); |
|
71 | + } |
|
72 | + |
|
73 | + /** |
|
74 | + * Gets the query parameter key. This may have been modified (see setQueryParamValue()) |
|
75 | + * @return string |
|
76 | + */ |
|
77 | + public function getQueryParamKey() |
|
78 | + { |
|
79 | + return $this->query_param_key; |
|
80 | + } |
|
81 | + |
|
82 | + /** |
|
83 | + * Modifies the query parameter key passed in (Eg this is done when rewriting the simplified specified operator REST |
|
84 | + * query parameters into the legacy structure) |
|
85 | + * @param string|array|int|float $query_param_value |
|
86 | + */ |
|
87 | + private function setQueryParamValue($query_param_value) |
|
88 | + { |
|
89 | + $this->query_param_value = $query_param_value; |
|
90 | + } |
|
91 | + |
|
92 | + /** |
|
93 | + * Gets the original query parameter value passed in. |
|
94 | + * @return string |
|
95 | + */ |
|
96 | + public function getQueryParamValue() |
|
97 | + { |
|
98 | + return $this->query_param_value; |
|
99 | + } |
|
100 | + |
|
101 | + /** |
|
102 | + * Gets the context object. |
|
103 | + * @return RestIncomingQueryParamContext |
|
104 | + */ |
|
105 | + public function getContext() |
|
106 | + { |
|
107 | + return $this->context; |
|
108 | + } |
|
109 | + |
|
110 | + /** |
|
111 | + * Sets the query parameter key. This may be used to rewrite a key into its non-GMT alternative. |
|
112 | + * @param string $query_param_key |
|
113 | + */ |
|
114 | + private function setQueryParamKey($query_param_key) |
|
115 | + { |
|
116 | + $this->query_param_key = $query_param_key; |
|
117 | + } |
|
118 | + |
|
119 | + /** |
|
120 | + * Gets the field the query parameter key indicated. This may be null (in cases where the query parameter key |
|
121 | + * did not indicate a field, eg if it were `OR`). |
|
122 | + * @return EE_Model_Field_Base|null |
|
123 | + */ |
|
124 | + public function getField() |
|
125 | + { |
|
126 | + return $this->field; |
|
127 | + } |
|
128 | + |
|
129 | + /** |
|
130 | + * Gets the query parameter key (with the star and everything afterwards removed). |
|
131 | + * @return string |
|
132 | + */ |
|
133 | + public function getQueryParamKeySansStars() |
|
134 | + { |
|
135 | + return $this->query_param_key_sans_stars; |
|
136 | + } |
|
137 | + |
|
138 | + /** |
|
139 | + * Gets the timezone associated with this model (the site timezone, except for GMT datetime fields). |
|
140 | + * @return string |
|
141 | + */ |
|
142 | + public function getTimezone() |
|
143 | + { |
|
144 | + return $this->timezone; |
|
145 | + } |
|
146 | + |
|
147 | + /** |
|
148 | + * Returns whether or not this is a GMT field |
|
149 | + * @return boolean |
|
150 | + */ |
|
151 | + public function isGmtField() |
|
152 | + { |
|
153 | + return $this->is_gmt_field; |
|
154 | + } |
|
155 | + |
|
156 | + /** |
|
157 | + * Sets the field indicated by the query parameter key (might be null). |
|
158 | + * @param EE_Model_Field_Base|null $field |
|
159 | + */ |
|
160 | + private function setField(EE_Model_Field_Base $field = null) |
|
161 | + { |
|
162 | + $this->field = $field; |
|
163 | + } |
|
164 | + |
|
165 | + /** |
|
166 | + * Sets the query parameter key-with-stars-removed. |
|
167 | + * @param string $query_param_key_sans_stars |
|
168 | + */ |
|
169 | + private function setQueryParamKeySansStars($query_param_key_sans_stars) |
|
170 | + { |
|
171 | + $this->query_param_key_sans_stars = $query_param_key_sans_stars; |
|
172 | + } |
|
173 | + |
|
174 | + /** |
|
175 | + * Sets the timezone (this could be a timezeon offset string). |
|
176 | + * @param string $timezone |
|
177 | + */ |
|
178 | + private function setTimezone($timezone) |
|
179 | + { |
|
180 | + $this->timezone = $timezone; |
|
181 | + } |
|
182 | + |
|
183 | + /** |
|
184 | + * @param mixed $is_gmt_field |
|
185 | + */ |
|
186 | + private function setIsGmtField($is_gmt_field) |
|
187 | + { |
|
188 | + $this->is_gmt_field = $is_gmt_field; |
|
189 | + } |
|
190 | + |
|
191 | + /** |
|
192 | + * Determines what field, query param name, and query param name without stars, and timezone to use. |
|
193 | + * @since 4.9.72.p |
|
194 | + * @type EE_Model_Field_Base $field |
|
195 | + * @return void { |
|
196 | + * @throws EE_Error |
|
197 | + * @throws InvalidDataTypeException |
|
198 | + * @throws InvalidInterfaceException |
|
199 | + * @throws InvalidArgumentException |
|
200 | + */ |
|
201 | + private function determineFieldAndTimezone() |
|
202 | + { |
|
203 | + $this->setQueryParamKeySansStars(ModelDataTranslator::removeStarsAndAnythingAfterFromConditionQueryParamKey( |
|
204 | + $this->getQueryParamKey() |
|
205 | + )); |
|
206 | + $this->setField(ModelDataTranslator::deduceFieldFromQueryParam( |
|
207 | + $this->getQueryParamKeySansStars(), |
|
208 | + $this->getContext()->getModel() |
|
209 | + )); |
|
210 | + // double-check is it a *_gmt field? |
|
211 | + if ( |
|
212 | + !$this->getField() instanceof EE_Model_Field_Base |
|
213 | + && ModelDataTranslator::isGmtDateFieldName($this->getQueryParamKeySansStars()) |
|
214 | + ) { |
|
215 | + // yep, take off '_gmt', and find the field |
|
216 | + $this->setQueryParamKey(ModelDataTranslator::removeGmtFromFieldName($this->getQueryParamKeySansStars())); |
|
217 | + $this->setField(ModelDataTranslator::deduceFieldFromQueryParam( |
|
218 | + $this->getQueryParamKey(), |
|
219 | + $this->context->getModel() |
|
220 | + )); |
|
221 | + $this->setTimezone('UTC'); |
|
222 | + $this->setIsGmtField(true); |
|
223 | + } elseif ($this->getField() instanceof EE_Datetime_Field) { |
|
224 | + // so it's not a GMT field. Set the timezone on the model to the default |
|
225 | + $this->setTimezone(EEH_DTT_Helper::get_valid_timezone_string()); |
|
226 | + } else { |
|
227 | + // just keep using what's already set for the timezone |
|
228 | + $this->setTimezone($this->context->getModel()->get_timezone()); |
|
229 | + } |
|
230 | + $this->assertOnlyAdminCanReadPasswordFields(); |
|
231 | + } |
|
232 | + |
|
233 | + /** |
|
234 | + * Throws an exception if a non-admin is trying to query by password. |
|
235 | + * @since 4.9.74.p |
|
236 | + * @throws RestException |
|
237 | + */ |
|
238 | + private function assertOnlyAdminCanReadPasswordFields() |
|
239 | + { |
|
240 | + if ( |
|
241 | + $this->getField() instanceof EE_Password_Field |
|
242 | + && ! current_user_can(EE_Restriction_Generator_Base::get_default_restrictions_cap()) |
|
243 | + ) { |
|
244 | + // only full admins can query by password. sorry bub! |
|
245 | + throw new RestException( |
|
246 | + 'only_admins_can_query_by_password', |
|
247 | + // @codingStandardsIgnoreStart |
|
248 | + esc_html__('You attempted to filter by a password field without the needed privileges. Only a full admin is allowed to do that.', 'event_espresso'), |
|
249 | + // @codingStandardsIgnoreEnd |
|
250 | + array( |
|
251 | + 'status' => 403 |
|
252 | + ) |
|
253 | + ); |
|
254 | + } |
|
255 | + } |
|
256 | + |
|
257 | + /** |
|
258 | + * Given a ton of input, determines the value to use for the models. |
|
259 | + * @since 4.9.72.p |
|
260 | + * @return array|null |
|
261 | + * @throws DomainException |
|
262 | + * @throws EE_Error |
|
263 | + * @throws RestException |
|
264 | + * @throws DomainException |
|
265 | + */ |
|
266 | + public function determineConditionsQueryParameterValue() |
|
267 | + { |
|
268 | + if ($this->valueIsArrayDuringRead()) { |
|
269 | + return $this->determineModelValueGivenRestInputArray(); |
|
270 | + } |
|
271 | + return ModelDataTranslator::prepareFieldValueFromJson( |
|
272 | + $this->getField(), |
|
273 | + $this->getQueryParamValue(), |
|
274 | + $this->getContext()->getRequestedVersion(), |
|
275 | + $this->getTimezone() |
|
276 | + ); |
|
277 | + } |
|
278 | + |
|
279 | + /** |
|
280 | + * Given that the array value provided was itself an array, handles finding the correct value to pass to the model. |
|
281 | + * @since 4.9.72.p |
|
282 | + * @return array|null |
|
283 | + * @throws RestException |
|
284 | + */ |
|
285 | + private function determineModelValueGivenRestInputArray() |
|
286 | + { |
|
287 | + $this->transformSimplifiedSpecifiedOperatorSyntaxIntoStandardSyntax(); |
|
288 | + // did they specify an operator? |
|
289 | + if ($this->valueIsLegacySpecifiedOperator()) { |
|
290 | + $query_param_value = $this->getQueryParamValue(); |
|
291 | + $sub_array_key = $query_param_value[0]; |
|
292 | + $translated_value = array($sub_array_key); |
|
293 | + if ($this->operatorIsNAry($sub_array_key)) { |
|
294 | + $translated_value[] = $this->prepareValuesFromJson($query_param_value[1]); |
|
295 | + } elseif ($this->operatorIsTernary($sub_array_key)) { |
|
296 | + $translated_value[] = array( |
|
297 | + $this->prepareValuesFromJson($query_param_value[1][0]), |
|
298 | + $this->prepareValuesFromJson($query_param_value[1][1]) |
|
299 | + ); |
|
300 | + } elseif ($this->operatorIsLike($sub_array_key)) { |
|
301 | + // we want to leave this value mostly-as-is (eg don't force it to be a float |
|
302 | + // or a boolean or an enum value. Leave it as-is with wildcards etc) |
|
303 | + // but do verify it at least doesn't have any serialized data |
|
304 | + ModelDataTranslator::throwExceptionIfContainsSerializedData($query_param_value[1]); |
|
305 | + $translated_value[] = $query_param_value[1]; |
|
306 | + } elseif ($this->operatorIsUnary($sub_array_key)) { |
|
307 | + // no arguments should have been provided, so don't look for any |
|
308 | + } elseif ($this->operatorisBinary($sub_array_key)) { |
|
309 | + // it's a valid operator, but none of the exceptions. Treat it normally. |
|
310 | + $translated_value[] = $this->prepareValuesFromJson($query_param_value[1]); |
|
311 | + } else { |
|
312 | + // so they provided a valid operator, but wrong number of arguments |
|
313 | + $this->throwWrongNumberOfArgsExceptionIfDebugging($sub_array_key); |
|
314 | + $translated_value = null; |
|
315 | + } |
|
316 | + } else { |
|
317 | + // so they didn't provide a valid operator |
|
318 | + // if we aren't in debug mode, then just try our best to fulfill the user's request |
|
319 | + $this->throwInvalidOperatorExceptionIfDebugging(); |
|
320 | + $translated_value = null; |
|
321 | + } |
|
322 | + return $translated_value; |
|
323 | + } |
|
324 | + |
|
325 | + /** |
|
326 | + * Returns if this request is a "read" request and the value provided was an array. |
|
327 | + * This will indicate is such things as `array('<', 123)` and `array('IN', array(1,2,3))` are acceptable or not. |
|
328 | + * @since 4.9.72.p |
|
329 | + * @return boolean |
|
330 | + */ |
|
331 | + private function valueIsArrayDuringRead() |
|
332 | + { |
|
333 | + return !$this->getContext()->isWriting() && is_array($this->getQueryParamValue()); |
|
334 | + } |
|
335 | + |
|
336 | + /** |
|
337 | + * Returns if the value provided was an associative array (we should have already verified it's an array of some |
|
338 | + * sort). If the value is an associative array, it had better be in the simplified specified operator structure. |
|
339 | + * @since 4.9.72.p |
|
340 | + * @return boolean |
|
341 | + */ |
|
342 | + private function valueIsAssociativeArray() |
|
343 | + { |
|
344 | + return !EEH_Array::is_array_numerically_and_sequentially_indexed($this->getQueryParamValue()); |
|
345 | + } |
|
346 | + |
|
347 | + /** |
|
348 | + * Checks if the array value is itself an array that fits into the simplified specified operator structure |
|
349 | + * (eg `array('!=' => 123)`). |
|
350 | + * @since 4.9.72.p |
|
351 | + * @return boolean |
|
352 | + */ |
|
353 | + private function valueIsSimplifiedSpecifiedOperator() |
|
354 | + { |
|
355 | + return count($this->getQueryParamValue()) === 1 |
|
356 | + && array_key_exists( |
|
357 | + key($this->getQueryParamValue()), |
|
358 | + $this->getContext()->getModel()->valid_operators() |
|
359 | + ); |
|
360 | + } |
|
361 | + |
|
362 | + /** |
|
363 | + * Throws an exception if the sub-value is an array (eg `array('!=' => array())`). It needs to just be a string, |
|
364 | + * of either comma-separated-values, or a JSON array. |
|
365 | + * @since 4.9.72.p |
|
366 | + * @param $sub_array_key |
|
367 | + * @param $sub_array_value |
|
368 | + * @throws RestException |
|
369 | + */ |
|
370 | + private function assertSubValueIsntArray($sub_array_key, $sub_array_value) |
|
371 | + { |
|
372 | + if (is_array($sub_array_value) && EED_Core_Rest_Api::debugMode()) { |
|
373 | + throw new RestException( |
|
374 | + 'csv_or_json_string_only', |
|
375 | + sprintf( |
|
376 | + /* translators: 1: variable name*/ |
|
377 | + esc_html__( |
|
378 | + 'The value provided for the operator "%1$s" should be comma-separated value string or a JSON array.', |
|
379 | + 'event_espresso' |
|
380 | + ), |
|
381 | + $sub_array_key |
|
382 | + ), |
|
383 | + array( |
|
384 | + 'status' => 400, |
|
385 | + ) |
|
386 | + ); |
|
387 | + } |
|
388 | + } |
|
389 | + |
|
390 | + /** |
|
391 | + * Determines if the sub-array key is an operator taking 3 or more operators. |
|
392 | + * @since 4.9.72.p |
|
393 | + * @param $sub_array_key |
|
394 | + * @return boolean |
|
395 | + */ |
|
396 | + private function subArrayKeyIsNonBinaryOperator($sub_array_key) |
|
397 | + { |
|
398 | + return array_key_exists( |
|
399 | + $sub_array_key, |
|
400 | + array_merge( |
|
401 | + $this->getContext()->getModel()->valid_in_style_operators(), |
|
402 | + $this->getContext()->getModel()->valid_between_style_operators() |
|
403 | + ) |
|
404 | + ); |
|
405 | + } |
|
406 | + |
|
407 | + /** |
|
408 | + * Given that the $sub_array_key is a string, checks if it's an operator taking only 1 argument. |
|
409 | + * @since 4.9.72.p |
|
410 | + * @param string $sub_array_key |
|
411 | + * @return boolean |
|
412 | + */ |
|
413 | + private function subArrayKeyIsUnaryOperator($sub_array_key) |
|
414 | + { |
|
415 | + return array_key_exists( |
|
416 | + $sub_array_key, |
|
417 | + $this->getContext()->getModel()->valid_null_style_operators() |
|
418 | + ); |
|
419 | + } |
|
420 | + |
|
421 | + /** |
|
422 | + * Parses the $sub_array_value string into an array (given it could either be a comma-separated-list or a JSON |
|
423 | + * array). eg `"1,2,3"` or `"[1,2,3]"` into `array(1,2,3)`. |
|
424 | + * @since 4.9.72.p |
|
425 | + * @param $sub_array_value |
|
426 | + * @return array|mixed|object |
|
427 | + */ |
|
428 | + private function extractQuickStyleSpecifiedOperatorValue($sub_array_value) |
|
429 | + { |
|
430 | + // the value should be JSON or CSV |
|
431 | + $values = json_decode($sub_array_value); |
|
432 | + if (!is_array($values)) { |
|
433 | + $values = array_filter( |
|
434 | + array_map( |
|
435 | + 'trim', |
|
436 | + explode( |
|
437 | + ',', |
|
438 | + $sub_array_value |
|
439 | + ) |
|
440 | + ) |
|
441 | + ); |
|
442 | + } |
|
443 | + return $values; |
|
444 | + } |
|
445 | + |
|
446 | + /** |
|
447 | + * Throws an exception if the value isn't a simplified specified operator (only called when we expect that). |
|
448 | + * @since 4.9.72.p |
|
449 | + * @throws RestException |
|
450 | + */ |
|
451 | + private function assertSimplifiedSpecifiedOperator() |
|
452 | + { |
|
453 | + if (!$this->valueIsSimplifiedSpecifiedOperator() && EED_Core_Rest_Api::debugMode()) { |
|
454 | + throw new RestException( |
|
455 | + 'numerically_indexed_array_of_values_only', |
|
456 | + sprintf( |
|
457 | + /* translators: 1: variable name*/ |
|
458 | + esc_html__( |
|
459 | + 'The array provided for the parameter "%1$s" should be numerically indexed.', |
|
460 | + 'event_espresso' |
|
461 | + ), |
|
462 | + $this->getQueryParamKey() |
|
463 | + ), |
|
464 | + array( |
|
465 | + 'status' => 400, |
|
466 | + ) |
|
467 | + ); |
|
468 | + } |
|
469 | + } |
|
470 | + |
|
471 | + /** |
|
472 | + * If query_param_value were in the simplified specific operator structure, change it into the legacy structure. |
|
473 | + * @since 4.9.72.p |
|
474 | + * @throws RestException |
|
475 | + */ |
|
476 | + private function transformSimplifiedSpecifiedOperatorSyntaxIntoStandardSyntax() |
|
477 | + { |
|
478 | + if ($this->valueIsAssociativeArray()) { |
|
479 | + $this->assertSimplifiedSpecifiedOperator(); |
|
480 | + $query_param_value = $this->getQueryParamValue(); |
|
481 | + $sub_array_value = reset($query_param_value); |
|
482 | + $sub_array_key = key($query_param_value); |
|
483 | + $this->assertSubValueIsntArray($sub_array_key, $sub_array_value); |
|
484 | + // they're doing something like "&where[EVT_ID][IN]=1,2,3" or "&where[EVT_ID][>]=5" |
|
485 | + if ($this->subArrayKeyIsNonBinaryOperator($sub_array_key)) { |
|
486 | + $this->setQueryParamValue(array( |
|
487 | + $sub_array_key, |
|
488 | + $this->extractQuickStyleSpecifiedOperatorValue($sub_array_value) |
|
489 | + )); |
|
490 | + } elseif ($this->subArrayKeyIsUnaryOperator($sub_array_key)) { |
|
491 | + $this->setQueryParamValue(array($sub_array_key)); |
|
492 | + } else { |
|
493 | + $this->setQueryParamValue(array($sub_array_key, $sub_array_value)); |
|
494 | + } |
|
495 | + } |
|
496 | + } |
|
497 | + |
|
498 | + /** |
|
499 | + * Returns true is the value is an array using the legacy structure to specify the operator. Eg `array('!=',123)`. |
|
500 | + * @since 4.9.72.p |
|
501 | + * @return boolean |
|
502 | + */ |
|
503 | + private function valueIsLegacySpecifiedOperator() |
|
504 | + { |
|
505 | + $valid_operators = $this->getContext()->getModel()->valid_operators(); |
|
506 | + $query_param_value = $this->getQueryParamValue(); |
|
507 | + return isset($query_param_value[0]) |
|
508 | + && isset($valid_operators[ $query_param_value[0] ]); |
|
509 | + } |
|
510 | + |
|
511 | + /** |
|
512 | + * Returns true if the value specified operator accepts arbitrary number of arguments, like "IN". |
|
513 | + * @since 4.9.72.p |
|
514 | + * @param $operator |
|
515 | + * @return boolean |
|
516 | + */ |
|
517 | + private function operatorIsNAry($operator) |
|
518 | + { |
|
519 | + $valueArray = $this->getQueryParamValue(); |
|
520 | + return array_key_exists( |
|
521 | + $operator, |
|
522 | + $this->getContext()->getModel()->valid_in_style_operators() |
|
523 | + ) |
|
524 | + && isset($valueArray[1]) |
|
525 | + && is_array($valueArray[1]) |
|
526 | + && !isset($valueArray[2]); |
|
527 | + } |
|
528 | + |
|
529 | + /** |
|
530 | + * Returns true if the operator accepts 3 arguments (eg "BETWEEN"). |
|
531 | + * So we're looking for a value that looks like |
|
532 | + * `array('BETWEEN', array('2015-01-01T00:00:00', '2016-01-01T00:00:00'))`. |
|
533 | + * @since 4.9.72.p |
|
534 | + * @param $operator |
|
535 | + * @return boolean |
|
536 | + */ |
|
537 | + private function operatorIsTernary($operator) |
|
538 | + { |
|
539 | + $query_param_value = $this->getQueryParamValue(); |
|
540 | + return array_key_exists($operator, $this->getContext()->getModel()->valid_between_style_operators()) |
|
541 | + && isset($query_param_value[1]) |
|
542 | + && is_array($query_param_value[1]) |
|
543 | + && isset($query_param_value[1][0], $query_param_value[1][1]) |
|
544 | + && !isset($query_param_value[1][2]) |
|
545 | + && !isset($query_param_value[2]); |
|
546 | + } |
|
547 | + |
|
548 | + /** |
|
549 | + * Returns true if the operator is a similar to LIKE, indicating the value may have wildcards we should leave alone. |
|
550 | + * @since 4.9.72.p |
|
551 | + * @param $operator |
|
552 | + * @return boolean |
|
553 | + */ |
|
554 | + private function operatorIsLike($operator) |
|
555 | + { |
|
556 | + $query_param_value = $this->getQueryParamValue(); |
|
557 | + return array_key_exists($operator, $this->getContext()->getModel()->valid_like_style_operators()) |
|
558 | + && isset($query_param_value[1]) |
|
559 | + && !isset($query_param_value[2]); |
|
560 | + } |
|
561 | + |
|
562 | + /** |
|
563 | + * Returns true if the operator only takes one argument (eg it's like `IS NULL`). |
|
564 | + * @since 4.9.72.p |
|
565 | + * @param $operator |
|
566 | + * @return boolean |
|
567 | + */ |
|
568 | + private function operatorIsUnary($operator) |
|
569 | + { |
|
570 | + $query_param_value = $this->getQueryParamValue(); |
|
571 | + return array_key_exists($operator, $this->getContext()->getModel()->valid_null_style_operators()) |
|
572 | + && !isset($query_param_value[1]); |
|
573 | + } |
|
574 | + |
|
575 | + /** |
|
576 | + * Returns true if the operator specified is a binary opeator (eg `=`, `!=`) |
|
577 | + * @since 4.9.72.p |
|
578 | + * @param $operator |
|
579 | + * @return boolean |
|
580 | + */ |
|
581 | + private function operatorisBinary($operator) |
|
582 | + { |
|
583 | + $query_param_value = $this->getQueryParamValue(); |
|
584 | + $model = $this->getContext()->getModel(); |
|
585 | + return isset($query_param_value[1]) |
|
586 | + && !isset($query_param_value[2]) |
|
587 | + && !array_key_exists( |
|
588 | + $operator, |
|
589 | + array_merge( |
|
590 | + $model->valid_in_style_operators(), |
|
591 | + $model->valid_null_style_operators(), |
|
592 | + $model->valid_like_style_operators(), |
|
593 | + $model->valid_between_style_operators() |
|
594 | + ) |
|
595 | + ); |
|
596 | + } |
|
597 | + |
|
598 | + /** |
|
599 | + * If we're debugging, throws an exception saying that the wrong number of arguments was provided. |
|
600 | + * @since 4.9.72.p |
|
601 | + * @param $operator |
|
602 | + * @throws RestException |
|
603 | + */ |
|
604 | + private function throwWrongNumberOfArgsExceptionIfDebugging($operator) |
|
605 | + { |
|
606 | + if (EED_Core_Rest_Api::debugMode()) { |
|
607 | + throw new RestException( |
|
608 | + 'wrong_number_of_arguments', |
|
609 | + sprintf( |
|
610 | + esc_html__( |
|
611 | + 'The operator you provided, "%1$s" had the wrong number of arguments', |
|
612 | + 'event_espresso' |
|
613 | + ), |
|
614 | + $operator |
|
615 | + ), |
|
616 | + array( |
|
617 | + 'status' => 400, |
|
618 | + ) |
|
619 | + ); |
|
620 | + } |
|
621 | + } |
|
622 | + |
|
623 | + /** |
|
624 | + * Wrapper for ModelDataTranslator::prepareFieldValuesFromJson(), just a tad more DRY. |
|
625 | + * @since 4.9.72.p |
|
626 | + * @param $value |
|
627 | + * @return mixed |
|
628 | + * @throws RestException |
|
629 | + */ |
|
630 | + private function prepareValuesFromJson($value) |
|
631 | + { |
|
632 | + return ModelDataTranslator::prepareFieldValuesFromJson( |
|
633 | + $this->getField(), |
|
634 | + $value, |
|
635 | + $this->getContext()->getRequestedVersion(), |
|
636 | + $this->getTimezone() |
|
637 | + ); |
|
638 | + } |
|
639 | + |
|
640 | + /** |
|
641 | + * Throws an exception if an invalid operator was specified and we're debugging. |
|
642 | + * @since 4.9.72.p |
|
643 | + * @throws RestException |
|
644 | + */ |
|
645 | + private function throwInvalidOperatorExceptionIfDebugging() |
|
646 | + { |
|
647 | + // so they didn't provide a valid operator |
|
648 | + if (EED_Core_Rest_Api::debugMode()) { |
|
649 | + throw new RestException( |
|
650 | + 'invalid_operator', |
|
651 | + sprintf( |
|
652 | + esc_html__( |
|
653 | + 'You provided an invalid parameter, with key "%1$s" and value "%2$s"', |
|
654 | + 'event_espresso' |
|
655 | + ), |
|
656 | + $this->getQueryParamKey(), |
|
657 | + $this->getQueryParamValue() |
|
658 | + ), |
|
659 | + array( |
|
660 | + 'status' => 400, |
|
661 | + ) |
|
662 | + ); |
|
663 | + } |
|
664 | + } |
|
665 | + |
|
666 | + /** |
|
667 | + * Returns true if the query_param_key was a logic query parameter, eg `OR`, `AND`, `NOT`, `OR*`, etc. |
|
668 | + * @since 4.9.72.p |
|
669 | + * @return boolean |
|
670 | + */ |
|
671 | + private function isLogicQueryParam() |
|
672 | + { |
|
673 | + return in_array($this->getQueryParamKeySansStars(), $this->getContext()->getModel()->logic_query_param_keys()); |
|
674 | + } |
|
675 | + |
|
676 | + |
|
677 | + /** |
|
678 | + * If the query param isn't for a field, it must be a nested query parameter which requires different logic. |
|
679 | + * @since 4.9.72.p |
|
680 | + * @return array |
|
681 | + * @throws DomainException |
|
682 | + * @throws EE_Error |
|
683 | + * @throws RestException |
|
684 | + * @throws InvalidDataTypeException |
|
685 | + * @throws InvalidInterfaceException |
|
686 | + * @throws InvalidArgumentException |
|
687 | + */ |
|
688 | + public function determineNestedConditionQueryParameters() |
|
689 | + { |
|
690 | + |
|
691 | + // so this param doesn't correspond to a field eh? |
|
692 | + if ($this->getContext()->isWriting()) { |
|
693 | + // always tell API clients about invalid parameters when they're creating data. Otherwise, |
|
694 | + // they are probably going to create invalid data |
|
695 | + throw new RestException( |
|
696 | + 'invalid_field', |
|
697 | + sprintf( |
|
698 | + /* translators: 1: variable name */ |
|
699 | + esc_html__('You have provided an invalid parameter: "%1$s"', 'event_espresso'), |
|
700 | + $this->getQueryParamKey() |
|
701 | + ) |
|
702 | + ); |
|
703 | + } |
|
704 | + // so it's not for a field, is it a logic query param key? |
|
705 | + if ($this->isLogicQueryParam()) { |
|
706 | + return ModelDataTranslator::prepareConditionsQueryParamsForModels( |
|
707 | + $this->getQueryParamValue(), |
|
708 | + $this->getContext()->getModel(), |
|
709 | + $this->getContext()->getRequestedVersion() |
|
710 | + ); |
|
711 | + } |
|
712 | + if (EED_Core_Rest_Api::debugMode()) { |
|
713 | + // only tell API clients they got it wrong if we're in debug mode |
|
714 | + // otherwise try our best ot fulfill their request by ignoring this invalid data |
|
715 | + throw new RestException( |
|
716 | + 'invalid_parameter', |
|
717 | + sprintf( |
|
718 | + /* translators: 1: variable name */ |
|
719 | + esc_html__( |
|
720 | + 'You provided an invalid parameter, with key "%1$s"', |
|
721 | + 'event_espresso' |
|
722 | + ), |
|
723 | + $this->getQueryParamKey() |
|
724 | + ), |
|
725 | + array( |
|
726 | + 'status' => 400, |
|
727 | + ) |
|
728 | + ); |
|
729 | + } |
|
730 | + return null; |
|
731 | + } |
|
732 | 732 | } |
733 | 733 | // End of file RestQueryParamMetadata.php |
734 | 734 | // Location: EventEspresso\core\libraries\rest_api/RestQueryParamMetadata.php |
@@ -209,7 +209,7 @@ discard block |
||
209 | 209 | )); |
210 | 210 | // double-check is it a *_gmt field? |
211 | 211 | if ( |
212 | - !$this->getField() instanceof EE_Model_Field_Base |
|
212 | + ! $this->getField() instanceof EE_Model_Field_Base |
|
213 | 213 | && ModelDataTranslator::isGmtDateFieldName($this->getQueryParamKeySansStars()) |
214 | 214 | ) { |
215 | 215 | // yep, take off '_gmt', and find the field |
@@ -330,7 +330,7 @@ discard block |
||
330 | 330 | */ |
331 | 331 | private function valueIsArrayDuringRead() |
332 | 332 | { |
333 | - return !$this->getContext()->isWriting() && is_array($this->getQueryParamValue()); |
|
333 | + return ! $this->getContext()->isWriting() && is_array($this->getQueryParamValue()); |
|
334 | 334 | } |
335 | 335 | |
336 | 336 | /** |
@@ -341,7 +341,7 @@ discard block |
||
341 | 341 | */ |
342 | 342 | private function valueIsAssociativeArray() |
343 | 343 | { |
344 | - return !EEH_Array::is_array_numerically_and_sequentially_indexed($this->getQueryParamValue()); |
|
344 | + return ! EEH_Array::is_array_numerically_and_sequentially_indexed($this->getQueryParamValue()); |
|
345 | 345 | } |
346 | 346 | |
347 | 347 | /** |
@@ -429,7 +429,7 @@ discard block |
||
429 | 429 | { |
430 | 430 | // the value should be JSON or CSV |
431 | 431 | $values = json_decode($sub_array_value); |
432 | - if (!is_array($values)) { |
|
432 | + if ( ! is_array($values)) { |
|
433 | 433 | $values = array_filter( |
434 | 434 | array_map( |
435 | 435 | 'trim', |
@@ -450,7 +450,7 @@ discard block |
||
450 | 450 | */ |
451 | 451 | private function assertSimplifiedSpecifiedOperator() |
452 | 452 | { |
453 | - if (!$this->valueIsSimplifiedSpecifiedOperator() && EED_Core_Rest_Api::debugMode()) { |
|
453 | + if ( ! $this->valueIsSimplifiedSpecifiedOperator() && EED_Core_Rest_Api::debugMode()) { |
|
454 | 454 | throw new RestException( |
455 | 455 | 'numerically_indexed_array_of_values_only', |
456 | 456 | sprintf( |
@@ -505,7 +505,7 @@ discard block |
||
505 | 505 | $valid_operators = $this->getContext()->getModel()->valid_operators(); |
506 | 506 | $query_param_value = $this->getQueryParamValue(); |
507 | 507 | return isset($query_param_value[0]) |
508 | - && isset($valid_operators[ $query_param_value[0] ]); |
|
508 | + && isset($valid_operators[$query_param_value[0]]); |
|
509 | 509 | } |
510 | 510 | |
511 | 511 | /** |
@@ -523,7 +523,7 @@ discard block |
||
523 | 523 | ) |
524 | 524 | && isset($valueArray[1]) |
525 | 525 | && is_array($valueArray[1]) |
526 | - && !isset($valueArray[2]); |
|
526 | + && ! isset($valueArray[2]); |
|
527 | 527 | } |
528 | 528 | |
529 | 529 | /** |
@@ -541,8 +541,8 @@ discard block |
||
541 | 541 | && isset($query_param_value[1]) |
542 | 542 | && is_array($query_param_value[1]) |
543 | 543 | && isset($query_param_value[1][0], $query_param_value[1][1]) |
544 | - && !isset($query_param_value[1][2]) |
|
545 | - && !isset($query_param_value[2]); |
|
544 | + && ! isset($query_param_value[1][2]) |
|
545 | + && ! isset($query_param_value[2]); |
|
546 | 546 | } |
547 | 547 | |
548 | 548 | /** |
@@ -556,7 +556,7 @@ discard block |
||
556 | 556 | $query_param_value = $this->getQueryParamValue(); |
557 | 557 | return array_key_exists($operator, $this->getContext()->getModel()->valid_like_style_operators()) |
558 | 558 | && isset($query_param_value[1]) |
559 | - && !isset($query_param_value[2]); |
|
559 | + && ! isset($query_param_value[2]); |
|
560 | 560 | } |
561 | 561 | |
562 | 562 | /** |
@@ -569,7 +569,7 @@ discard block |
||
569 | 569 | { |
570 | 570 | $query_param_value = $this->getQueryParamValue(); |
571 | 571 | return array_key_exists($operator, $this->getContext()->getModel()->valid_null_style_operators()) |
572 | - && !isset($query_param_value[1]); |
|
572 | + && ! isset($query_param_value[1]); |
|
573 | 573 | } |
574 | 574 | |
575 | 575 | /** |
@@ -583,8 +583,8 @@ discard block |
||
583 | 583 | $query_param_value = $this->getQueryParamValue(); |
584 | 584 | $model = $this->getContext()->getModel(); |
585 | 585 | return isset($query_param_value[1]) |
586 | - && !isset($query_param_value[2]) |
|
587 | - && !array_key_exists( |
|
586 | + && ! isset($query_param_value[2]) |
|
587 | + && ! array_key_exists( |
|
588 | 588 | $operator, |
589 | 589 | array_merge( |
590 | 590 | $model->valid_in_style_operators(), |
@@ -12,39 +12,39 @@ |
||
12 | 12 | class ChangesIn40834 extends ChangesInBase |
13 | 13 | { |
14 | 14 | |
15 | - /** |
|
16 | - * Adds hooks so requests to 4.8.29 don't have the checkin endpoints |
|
17 | - */ |
|
18 | - public function setHooks() |
|
19 | - { |
|
20 | - // set a hook to remove the checkout/checkout endpoints if the request |
|
21 | - // is for lower than 4.8.33 |
|
22 | - add_filter( |
|
23 | - 'FHEE__EventEspresso\core\libraries\rest_api\controllers\Base___get_response_headers', |
|
24 | - array($this, 'removeResponseHeaders'), |
|
25 | - 10, |
|
26 | - 3 |
|
27 | - ); |
|
28 | - } |
|
15 | + /** |
|
16 | + * Adds hooks so requests to 4.8.29 don't have the checkin endpoints |
|
17 | + */ |
|
18 | + public function setHooks() |
|
19 | + { |
|
20 | + // set a hook to remove the checkout/checkout endpoints if the request |
|
21 | + // is for lower than 4.8.33 |
|
22 | + add_filter( |
|
23 | + 'FHEE__EventEspresso\core\libraries\rest_api\controllers\Base___get_response_headers', |
|
24 | + array($this, 'removeResponseHeaders'), |
|
25 | + 10, |
|
26 | + 3 |
|
27 | + ); |
|
28 | + } |
|
29 | 29 | |
30 | 30 | |
31 | - /** |
|
32 | - * Removes the checkin and checkout endpoints from the index for requests |
|
33 | - * to api versions lowers than 4.8.33 |
|
34 | - * |
|
35 | - * @param array $response_headers |
|
36 | - * @param Base $controller |
|
37 | - * @param string $requested_version |
|
38 | - * @return array like $routes_on_this_version |
|
39 | - */ |
|
40 | - public function removeResponseHeaders($response_headers, $controller, $requested_version) |
|
41 | - { |
|
42 | - if ( |
|
43 | - $controller instanceof Base |
|
44 | - && $this->appliesToVersion($requested_version) |
|
45 | - ) { |
|
46 | - return array(); |
|
47 | - } |
|
48 | - return $response_headers; |
|
49 | - } |
|
31 | + /** |
|
32 | + * Removes the checkin and checkout endpoints from the index for requests |
|
33 | + * to api versions lowers than 4.8.33 |
|
34 | + * |
|
35 | + * @param array $response_headers |
|
36 | + * @param Base $controller |
|
37 | + * @param string $requested_version |
|
38 | + * @return array like $routes_on_this_version |
|
39 | + */ |
|
40 | + public function removeResponseHeaders($response_headers, $controller, $requested_version) |
|
41 | + { |
|
42 | + if ( |
|
43 | + $controller instanceof Base |
|
44 | + && $this->appliesToVersion($requested_version) |
|
45 | + ) { |
|
46 | + return array(); |
|
47 | + } |
|
48 | + return $response_headers; |
|
49 | + } |
|
50 | 50 | } |
@@ -57,7 +57,7 @@ discard block |
||
57 | 57 | */ |
58 | 58 | public function mapping($refresh = false) |
59 | 59 | { |
60 | - if (! $this->mapping || $refresh) { |
|
60 | + if ( ! $this->mapping || $refresh) { |
|
61 | 61 | $this->mapping = $this->generateNewMapping(); |
62 | 62 | } |
63 | 63 | return $this->mapping; |
@@ -81,7 +81,7 @@ discard block |
||
81 | 81 | foreach ($models_with_calculated_fields as $model_name) { |
82 | 82 | $calculator = $this->factory->createFromModel($model_name); |
83 | 83 | foreach (array_keys(call_user_func(array($calculator, 'schemaForCalculations'))) as $field_name) { |
84 | - $mapping[ $model_name ][ $field_name ] = get_class($calculator); |
|
84 | + $mapping[$model_name][$field_name] = get_class($calculator); |
|
85 | 85 | } |
86 | 86 | } |
87 | 87 | return apply_filters( |
@@ -108,8 +108,8 @@ discard block |
||
108 | 108 | foreach ($map_for_model as $calculation_index => $calculations_class) { |
109 | 109 | $calculator = $this->factory->createFromClassname($calculations_class); |
110 | 110 | $schema = call_user_func(array($calculator, 'schemaForCalculation'), $calculation_index); |
111 | - if (! empty($schema)) { |
|
112 | - $schema_map[ $map_model ][ $calculation_index ] = $schema; |
|
111 | + if ( ! empty($schema)) { |
|
112 | + $schema_map[$map_model][$calculation_index] = $schema; |
|
113 | 113 | } |
114 | 114 | } |
115 | 115 | } |
@@ -126,8 +126,8 @@ discard block |
||
126 | 126 | public function retrieveCalculatedFieldsForModel(EEM_Base $model) |
127 | 127 | { |
128 | 128 | $mapping = $this->mapping(); |
129 | - if (isset($mapping[ $model->get_this_model_name() ])) { |
|
130 | - return array_keys($mapping[ $model->get_this_model_name() ]); |
|
129 | + if (isset($mapping[$model->get_this_model_name()])) { |
|
130 | + return array_keys($mapping[$model->get_this_model_name()]); |
|
131 | 131 | } |
132 | 132 | return array(); |
133 | 133 | } |
@@ -140,7 +140,7 @@ discard block |
||
140 | 140 | */ |
141 | 141 | public function getJsonSchemaForModel(EEM_Base $model) |
142 | 142 | { |
143 | - if (! $this->mapping_schema) { |
|
143 | + if ( ! $this->mapping_schema) { |
|
144 | 144 | $this->mapping_schema = $this->generateNewMappingSchema(); |
145 | 145 | } |
146 | 146 | return array( |
@@ -149,8 +149,8 @@ discard block |
||
149 | 149 | 'event_espresso' |
150 | 150 | ), |
151 | 151 | 'type' => 'object', |
152 | - 'properties' => isset($this->mapping_schema[ $model->get_this_model_name() ]) |
|
153 | - ? $this->mapping_schema[ $model->get_this_model_name() ] |
|
152 | + 'properties' => isset($this->mapping_schema[$model->get_this_model_name()]) |
|
153 | + ? $this->mapping_schema[$model->get_this_model_name()] |
|
154 | 154 | : array(), |
155 | 155 | 'additionalProperties' => false, |
156 | 156 | 'readonly' => true, |
@@ -179,10 +179,10 @@ discard block |
||
179 | 179 | ) { |
180 | 180 | $mapping = $this->mapping(); |
181 | 181 | if ( |
182 | - isset($mapping[ $model->get_this_model_name() ]) |
|
183 | - && isset($mapping[ $model->get_this_model_name() ][ $field_name ]) |
|
182 | + isset($mapping[$model->get_this_model_name()]) |
|
183 | + && isset($mapping[$model->get_this_model_name()][$field_name]) |
|
184 | 184 | ) { |
185 | - $classname = $mapping[ $model->get_this_model_name() ][ $field_name ]; |
|
185 | + $classname = $mapping[$model->get_this_model_name()][$field_name]; |
|
186 | 186 | $calculator = $this->factory->createFromClassname($classname); |
187 | 187 | $class_method_name = EEH_Inflector::camelize_all_but_first($field_name); |
188 | 188 | return call_user_func(array($calculator, $class_method_name), $wpdb_row, $rest_request, $controller); |
@@ -21,178 +21,178 @@ |
||
21 | 21 | */ |
22 | 22 | class CalculatedModelFields |
23 | 23 | { |
24 | - /** |
|
25 | - * @var array |
|
26 | - */ |
|
27 | - protected $mapping; |
|
28 | - |
|
29 | - /** |
|
30 | - * @var array |
|
31 | - */ |
|
32 | - protected $mapping_schema; |
|
33 | - |
|
34 | - /** |
|
35 | - * @var CalculatedModelFieldsFactory |
|
36 | - */ |
|
37 | - private $factory; |
|
38 | - |
|
39 | - /** |
|
40 | - * CalculatedModelFields constructor. |
|
41 | - * @param CalculatedModelFieldsFactory $factory |
|
42 | - */ |
|
43 | - public function __construct(CalculatedModelFieldsFactory $factory) |
|
44 | - { |
|
45 | - $this->factory = $factory; |
|
46 | - } |
|
47 | - /** |
|
48 | - * @param bool $refresh |
|
49 | - * @return array top-level-keys are model names (eg "Event") |
|
50 | - * next-level are the calculated field names AND method names on classes |
|
51 | - * which perform calculations, values are the fully qualified classnames which do the calculations |
|
52 | - * These callbacks should accept as arguments: |
|
53 | - * the wpdb row results, |
|
54 | - * the WP_Request object, |
|
55 | - * the controller object |
|
56 | - */ |
|
57 | - public function mapping($refresh = false) |
|
58 | - { |
|
59 | - if (! $this->mapping || $refresh) { |
|
60 | - $this->mapping = $this->generateNewMapping(); |
|
61 | - } |
|
62 | - return $this->mapping; |
|
63 | - } |
|
64 | - |
|
65 | - |
|
66 | - /** |
|
67 | - * Generates a new mapping between model calculated fields and their callbacks |
|
68 | - * |
|
69 | - * @return array |
|
70 | - */ |
|
71 | - protected function generateNewMapping() |
|
72 | - { |
|
73 | - $mapping = array(); |
|
74 | - $models_with_calculated_fields = array( |
|
75 | - 'Attendee', |
|
76 | - 'Datetime', |
|
77 | - 'Event', |
|
78 | - 'Registration' |
|
79 | - ); |
|
80 | - foreach ($models_with_calculated_fields as $model_name) { |
|
81 | - $calculator = $this->factory->createFromModel($model_name); |
|
82 | - foreach (array_keys(call_user_func(array($calculator, 'schemaForCalculations'))) as $field_name) { |
|
83 | - $mapping[ $model_name ][ $field_name ] = get_class($calculator); |
|
84 | - } |
|
85 | - } |
|
86 | - return apply_filters( |
|
87 | - 'FHEE__EventEspresso\core\libraries\rest_api\Calculated_Model_Fields__mapping', |
|
88 | - $mapping |
|
89 | - ); |
|
90 | - } |
|
91 | - |
|
92 | - |
|
93 | - /** |
|
94 | - * Generates the schema for each calculation index in the calculation map. |
|
95 | - * |
|
96 | - * @return array |
|
97 | - * @throws UnexpectedEntityException |
|
98 | - */ |
|
99 | - protected function generateNewMappingSchema() |
|
100 | - { |
|
101 | - $schema_map = array(); |
|
102 | - foreach ($this->mapping() as $map_model => $map_for_model) { |
|
103 | - /** |
|
104 | - * @var string $calculation_index |
|
105 | - * @var string $calculations_class |
|
106 | - */ |
|
107 | - foreach ($map_for_model as $calculation_index => $calculations_class) { |
|
108 | - $calculator = $this->factory->createFromClassname($calculations_class); |
|
109 | - $schema = call_user_func(array($calculator, 'schemaForCalculation'), $calculation_index); |
|
110 | - if (! empty($schema)) { |
|
111 | - $schema_map[ $map_model ][ $calculation_index ] = $schema; |
|
112 | - } |
|
113 | - } |
|
114 | - } |
|
115 | - return $schema_map; |
|
116 | - } |
|
117 | - |
|
118 | - |
|
119 | - /** |
|
120 | - * Gets the known calculated fields for model |
|
121 | - * |
|
122 | - * @param EEM_Base $model |
|
123 | - * @return array allowable values for this field |
|
124 | - */ |
|
125 | - public function retrieveCalculatedFieldsForModel(EEM_Base $model) |
|
126 | - { |
|
127 | - $mapping = $this->mapping(); |
|
128 | - if (isset($mapping[ $model->get_this_model_name() ])) { |
|
129 | - return array_keys($mapping[ $model->get_this_model_name() ]); |
|
130 | - } |
|
131 | - return array(); |
|
132 | - } |
|
133 | - |
|
134 | - |
|
135 | - /** |
|
136 | - * Returns the JsonSchema for the calculated fields on the given model. |
|
137 | - * @param EEM_Base $model |
|
138 | - * @return array |
|
139 | - */ |
|
140 | - public function getJsonSchemaForModel(EEM_Base $model) |
|
141 | - { |
|
142 | - if (! $this->mapping_schema) { |
|
143 | - $this->mapping_schema = $this->generateNewMappingSchema(); |
|
144 | - } |
|
145 | - return array( |
|
146 | - 'description' => esc_html__( |
|
147 | - 'Available calculated fields for this model. Fields are only present in the response if explicitly requested', |
|
148 | - 'event_espresso' |
|
149 | - ), |
|
150 | - 'type' => 'object', |
|
151 | - 'properties' => isset($this->mapping_schema[ $model->get_this_model_name() ]) |
|
152 | - ? $this->mapping_schema[ $model->get_this_model_name() ] |
|
153 | - : array(), |
|
154 | - 'additionalProperties' => false, |
|
155 | - 'readonly' => true, |
|
156 | - ); |
|
157 | - } |
|
158 | - |
|
159 | - |
|
160 | - /** |
|
161 | - * Retrieves the value for this calculation |
|
162 | - * |
|
163 | - * @param EEM_Base $model |
|
164 | - * @param string $field_name |
|
165 | - * @param array $wpdb_row |
|
166 | - * @param $rest_request |
|
167 | - * @param BaseController $controller |
|
168 | - * @return mixed|null |
|
169 | - * @throws RestException |
|
170 | - * @throws UnexpectedEntityException |
|
171 | - */ |
|
172 | - public function retrieveCalculatedFieldValue( |
|
173 | - EEM_Base $model, |
|
174 | - $field_name, |
|
175 | - $wpdb_row, |
|
176 | - $rest_request, |
|
177 | - Base $controller |
|
178 | - ) { |
|
179 | - $mapping = $this->mapping(); |
|
180 | - if ( |
|
181 | - isset($mapping[ $model->get_this_model_name() ]) |
|
182 | - && isset($mapping[ $model->get_this_model_name() ][ $field_name ]) |
|
183 | - ) { |
|
184 | - $classname = $mapping[ $model->get_this_model_name() ][ $field_name ]; |
|
185 | - $calculator = $this->factory->createFromClassname($classname); |
|
186 | - $class_method_name = EEH_Inflector::camelize_all_but_first($field_name); |
|
187 | - return call_user_func(array($calculator, $class_method_name), $wpdb_row, $rest_request, $controller); |
|
188 | - } |
|
189 | - throw new RestException( |
|
190 | - 'calculated_field_does_not_exist', |
|
191 | - sprintf( |
|
192 | - esc_html__('There is no calculated field %1$s on resource %2$s', 'event_espresso'), |
|
193 | - $field_name, |
|
194 | - $model->get_this_model_name() |
|
195 | - ) |
|
196 | - ); |
|
197 | - } |
|
24 | + /** |
|
25 | + * @var array |
|
26 | + */ |
|
27 | + protected $mapping; |
|
28 | + |
|
29 | + /** |
|
30 | + * @var array |
|
31 | + */ |
|
32 | + protected $mapping_schema; |
|
33 | + |
|
34 | + /** |
|
35 | + * @var CalculatedModelFieldsFactory |
|
36 | + */ |
|
37 | + private $factory; |
|
38 | + |
|
39 | + /** |
|
40 | + * CalculatedModelFields constructor. |
|
41 | + * @param CalculatedModelFieldsFactory $factory |
|
42 | + */ |
|
43 | + public function __construct(CalculatedModelFieldsFactory $factory) |
|
44 | + { |
|
45 | + $this->factory = $factory; |
|
46 | + } |
|
47 | + /** |
|
48 | + * @param bool $refresh |
|
49 | + * @return array top-level-keys are model names (eg "Event") |
|
50 | + * next-level are the calculated field names AND method names on classes |
|
51 | + * which perform calculations, values are the fully qualified classnames which do the calculations |
|
52 | + * These callbacks should accept as arguments: |
|
53 | + * the wpdb row results, |
|
54 | + * the WP_Request object, |
|
55 | + * the controller object |
|
56 | + */ |
|
57 | + public function mapping($refresh = false) |
|
58 | + { |
|
59 | + if (! $this->mapping || $refresh) { |
|
60 | + $this->mapping = $this->generateNewMapping(); |
|
61 | + } |
|
62 | + return $this->mapping; |
|
63 | + } |
|
64 | + |
|
65 | + |
|
66 | + /** |
|
67 | + * Generates a new mapping between model calculated fields and their callbacks |
|
68 | + * |
|
69 | + * @return array |
|
70 | + */ |
|
71 | + protected function generateNewMapping() |
|
72 | + { |
|
73 | + $mapping = array(); |
|
74 | + $models_with_calculated_fields = array( |
|
75 | + 'Attendee', |
|
76 | + 'Datetime', |
|
77 | + 'Event', |
|
78 | + 'Registration' |
|
79 | + ); |
|
80 | + foreach ($models_with_calculated_fields as $model_name) { |
|
81 | + $calculator = $this->factory->createFromModel($model_name); |
|
82 | + foreach (array_keys(call_user_func(array($calculator, 'schemaForCalculations'))) as $field_name) { |
|
83 | + $mapping[ $model_name ][ $field_name ] = get_class($calculator); |
|
84 | + } |
|
85 | + } |
|
86 | + return apply_filters( |
|
87 | + 'FHEE__EventEspresso\core\libraries\rest_api\Calculated_Model_Fields__mapping', |
|
88 | + $mapping |
|
89 | + ); |
|
90 | + } |
|
91 | + |
|
92 | + |
|
93 | + /** |
|
94 | + * Generates the schema for each calculation index in the calculation map. |
|
95 | + * |
|
96 | + * @return array |
|
97 | + * @throws UnexpectedEntityException |
|
98 | + */ |
|
99 | + protected function generateNewMappingSchema() |
|
100 | + { |
|
101 | + $schema_map = array(); |
|
102 | + foreach ($this->mapping() as $map_model => $map_for_model) { |
|
103 | + /** |
|
104 | + * @var string $calculation_index |
|
105 | + * @var string $calculations_class |
|
106 | + */ |
|
107 | + foreach ($map_for_model as $calculation_index => $calculations_class) { |
|
108 | + $calculator = $this->factory->createFromClassname($calculations_class); |
|
109 | + $schema = call_user_func(array($calculator, 'schemaForCalculation'), $calculation_index); |
|
110 | + if (! empty($schema)) { |
|
111 | + $schema_map[ $map_model ][ $calculation_index ] = $schema; |
|
112 | + } |
|
113 | + } |
|
114 | + } |
|
115 | + return $schema_map; |
|
116 | + } |
|
117 | + |
|
118 | + |
|
119 | + /** |
|
120 | + * Gets the known calculated fields for model |
|
121 | + * |
|
122 | + * @param EEM_Base $model |
|
123 | + * @return array allowable values for this field |
|
124 | + */ |
|
125 | + public function retrieveCalculatedFieldsForModel(EEM_Base $model) |
|
126 | + { |
|
127 | + $mapping = $this->mapping(); |
|
128 | + if (isset($mapping[ $model->get_this_model_name() ])) { |
|
129 | + return array_keys($mapping[ $model->get_this_model_name() ]); |
|
130 | + } |
|
131 | + return array(); |
|
132 | + } |
|
133 | + |
|
134 | + |
|
135 | + /** |
|
136 | + * Returns the JsonSchema for the calculated fields on the given model. |
|
137 | + * @param EEM_Base $model |
|
138 | + * @return array |
|
139 | + */ |
|
140 | + public function getJsonSchemaForModel(EEM_Base $model) |
|
141 | + { |
|
142 | + if (! $this->mapping_schema) { |
|
143 | + $this->mapping_schema = $this->generateNewMappingSchema(); |
|
144 | + } |
|
145 | + return array( |
|
146 | + 'description' => esc_html__( |
|
147 | + 'Available calculated fields for this model. Fields are only present in the response if explicitly requested', |
|
148 | + 'event_espresso' |
|
149 | + ), |
|
150 | + 'type' => 'object', |
|
151 | + 'properties' => isset($this->mapping_schema[ $model->get_this_model_name() ]) |
|
152 | + ? $this->mapping_schema[ $model->get_this_model_name() ] |
|
153 | + : array(), |
|
154 | + 'additionalProperties' => false, |
|
155 | + 'readonly' => true, |
|
156 | + ); |
|
157 | + } |
|
158 | + |
|
159 | + |
|
160 | + /** |
|
161 | + * Retrieves the value for this calculation |
|
162 | + * |
|
163 | + * @param EEM_Base $model |
|
164 | + * @param string $field_name |
|
165 | + * @param array $wpdb_row |
|
166 | + * @param $rest_request |
|
167 | + * @param BaseController $controller |
|
168 | + * @return mixed|null |
|
169 | + * @throws RestException |
|
170 | + * @throws UnexpectedEntityException |
|
171 | + */ |
|
172 | + public function retrieveCalculatedFieldValue( |
|
173 | + EEM_Base $model, |
|
174 | + $field_name, |
|
175 | + $wpdb_row, |
|
176 | + $rest_request, |
|
177 | + Base $controller |
|
178 | + ) { |
|
179 | + $mapping = $this->mapping(); |
|
180 | + if ( |
|
181 | + isset($mapping[ $model->get_this_model_name() ]) |
|
182 | + && isset($mapping[ $model->get_this_model_name() ][ $field_name ]) |
|
183 | + ) { |
|
184 | + $classname = $mapping[ $model->get_this_model_name() ][ $field_name ]; |
|
185 | + $calculator = $this->factory->createFromClassname($classname); |
|
186 | + $class_method_name = EEH_Inflector::camelize_all_but_first($field_name); |
|
187 | + return call_user_func(array($calculator, $class_method_name), $wpdb_row, $rest_request, $controller); |
|
188 | + } |
|
189 | + throw new RestException( |
|
190 | + 'calculated_field_does_not_exist', |
|
191 | + sprintf( |
|
192 | + esc_html__('There is no calculated field %1$s on resource %2$s', 'event_espresso'), |
|
193 | + $field_name, |
|
194 | + $model->get_this_model_name() |
|
195 | + ) |
|
196 | + ); |
|
197 | + } |
|
198 | 198 | } |
@@ -114,10 +114,10 @@ discard block |
||
114 | 114 | foreach ($this->resource_changes as $version => $model_classnames) { |
115 | 115 | foreach ($model_classnames as $model_classname => $extra_fields) { |
116 | 116 | foreach ($extra_fields as $fieldname => $field_data) { |
117 | - $this->resource_changes[ $model_classname ][ $fieldname ]['name'] = $fieldname; |
|
117 | + $this->resource_changes[$model_classname][$fieldname]['name'] = $fieldname; |
|
118 | 118 | foreach ($defaults as $attribute => $default_value) { |
119 | - if (! isset($this->resource_changes[ $model_classname ][ $fieldname ][ $attribute ])) { |
|
120 | - $this->resource_changes[ $model_classname ][ $fieldname ][ $attribute ] = $default_value; |
|
119 | + if ( ! isset($this->resource_changes[$model_classname][$fieldname][$attribute])) { |
|
120 | + $this->resource_changes[$model_classname][$fieldname][$attribute] = $default_value; |
|
121 | 121 | } |
122 | 122 | } |
123 | 123 | } |
@@ -139,7 +139,7 @@ discard block |
||
139 | 139 | $model_changes = array(); |
140 | 140 | foreach ($this->modelChanges() as $version => $models_changed_in_version) { |
141 | 141 | if ($version <= EED_Core_Rest_Api::core_version() && $version > $this->requestedVersion()) { |
142 | - $model_changes[ $version ] = $models_changed_in_version; |
|
142 | + $model_changes[$version] = $models_changed_in_version; |
|
143 | 143 | } |
144 | 144 | } |
145 | 145 | $this->cached_model_changes_between_requested_version_and_current = $model_changes; |
@@ -161,7 +161,7 @@ discard block |
||
161 | 161 | $resource_changes = array(); |
162 | 162 | foreach ($this->resourceChanges() as $version => $model_classnames) { |
163 | 163 | if ($version <= EED_Core_Rest_Api::core_version() && $version > $this->requestedVersion()) { |
164 | - $resource_changes[ $version ] = $model_classnames; |
|
164 | + $resource_changes[$version] = $model_classnames; |
|
165 | 165 | } |
166 | 166 | } |
167 | 167 | $this->cached_resource_changes_between_requested_version_and_current = $resource_changes; |
@@ -212,7 +212,7 @@ discard block |
||
212 | 212 | foreach ($this->modelChangesBetweenRequestedVersionAndCurrent() as $version => $models_changed) { |
213 | 213 | foreach ($models_changed as $model_name => $new_indicator_or_fields_added) { |
214 | 214 | if ($new_indicator_or_fields_added === ModelVersionInfo::MODEL_ADDED) { |
215 | - unset($all_models_in_current_version[ $model_name ]); |
|
215 | + unset($all_models_in_current_version[$model_name]); |
|
216 | 216 | } |
217 | 217 | } |
218 | 218 | } |
@@ -237,7 +237,7 @@ discard block |
||
237 | 237 | public function isModelNameInThisVersion($model_name) |
238 | 238 | { |
239 | 239 | $model_names = $this->modelsForRequestedVersion(); |
240 | - if (isset($model_names[ $model_name ])) { |
|
240 | + if (isset($model_names[$model_name])) { |
|
241 | 241 | return true; |
242 | 242 | } else { |
243 | 243 | return false; |
@@ -280,7 +280,7 @@ discard block |
||
280 | 280 | */ |
281 | 281 | public function fieldsOnModelInThisVersion($model) |
282 | 282 | { |
283 | - if (! isset($this->cached_fields_on_models[ $model->get_this_model_name() ])) { |
|
283 | + if ( ! isset($this->cached_fields_on_models[$model->get_this_model_name()])) { |
|
284 | 284 | // get all model changes between the requested version and current core version |
285 | 285 | $changes = $this->modelChangesBetweenRequestedVersionAndCurrent(); |
286 | 286 | // fetch all fields currently on this model |
@@ -288,12 +288,12 @@ discard block |
||
288 | 288 | // remove all fields that have been added since |
289 | 289 | foreach ($changes as $version => $changes_in_version) { |
290 | 290 | if ( |
291 | - isset($changes_in_version[ $model->get_this_model_name() ]) |
|
292 | - && $changes_in_version[ $model->get_this_model_name() ] !== ModelVersionInfo::MODEL_ADDED |
|
291 | + isset($changes_in_version[$model->get_this_model_name()]) |
|
292 | + && $changes_in_version[$model->get_this_model_name()] !== ModelVersionInfo::MODEL_ADDED |
|
293 | 293 | ) { |
294 | 294 | $current_fields = array_diff_key( |
295 | 295 | $current_fields, |
296 | - array_flip($changes_in_version[ $model->get_this_model_name() ]) |
|
296 | + array_flip($changes_in_version[$model->get_this_model_name()]) |
|
297 | 297 | ); |
298 | 298 | } |
299 | 299 | } |
@@ -448,7 +448,7 @@ discard block |
||
448 | 448 | $relations = array(); |
449 | 449 | foreach ($model->relation_settings() as $relation_name => $relation_obj) { |
450 | 450 | if ($this->isModelNameInThisVersion($relation_name)) { |
451 | - $relations[ $relation_name ] = $relation_obj; |
|
451 | + $relations[$relation_name] = $relation_obj; |
|
452 | 452 | } |
453 | 453 | } |
454 | 454 | // filter the results, but use the old filter name |
@@ -20,441 +20,441 @@ |
||
20 | 20 | */ |
21 | 21 | class ModelVersionInfo |
22 | 22 | { |
23 | - /** |
|
24 | - * Constant used in the $_model_changes array to indicate that a model |
|
25 | - * was completely new in this version |
|
26 | - */ |
|
27 | - const MODEL_ADDED = 'model_added_in_this_version'; |
|
28 | - |
|
29 | - /** |
|
30 | - * Top-level keys are versions (major and minor version numbers, eg "4.6") |
|
31 | - * next-level keys are model names (eg "Event") that underwent some change in that version |
|
32 | - * and the value is either Model_Version_Info::model_added (indicating the model is completely NEW in this version), |
|
33 | - * or it's an array where the values are model field names, |
|
34 | - * or API resource properties (ie, non-model fields that appear in REST API results) |
|
35 | - * If a version is missing then we don't know anything about what changes it introduced from the previous version |
|
36 | - * |
|
37 | - * @var array |
|
38 | - */ |
|
39 | - protected $model_changes = array(); |
|
40 | - |
|
41 | - /** |
|
42 | - * top-level keys are version numbers, |
|
43 | - * next-level keys are model CLASSNAMES (even parent classnames), |
|
44 | - * and next-level keys are extra resource properties to attach to those models' resources, |
|
45 | - * and next-level key-value pairs, where the keys are: |
|
46 | - * 'raw', 'type', 'nullable', 'table_alias', 'table_column', 'always_available' |
|
47 | - * |
|
48 | - * @var array |
|
49 | - */ |
|
50 | - protected $resource_changes = array(); |
|
51 | - |
|
52 | - /** |
|
53 | - * @var string indicating what version of the API was requested |
|
54 | - * (eg although core might be at version 4.8.11, they may have sent a request |
|
55 | - * for 4.6) |
|
56 | - */ |
|
57 | - protected $requested_version = null; |
|
58 | - |
|
59 | - /** |
|
60 | - * Keys are model names, values are their classnames. |
|
61 | - * We cache this so we only need to calculate this once per request |
|
62 | - * |
|
63 | - * @var array |
|
64 | - */ |
|
65 | - protected $cached_models_for_requested_version = null; |
|
66 | - |
|
67 | - /** |
|
68 | - * @var array |
|
69 | - */ |
|
70 | - protected $cached_model_changes_between_requested_version_and_current = null; |
|
71 | - |
|
72 | - /** |
|
73 | - * @var array |
|
74 | - */ |
|
75 | - protected $cached_resource_changes_between_requested_version_and_current = null; |
|
76 | - |
|
77 | - /** |
|
78 | - * 2d array where top-level keys are model names, 2nd-level keys are field names |
|
79 | - * and values are the actual field objects |
|
80 | - * |
|
81 | - * @var array |
|
82 | - */ |
|
83 | - protected $cached_fields_on_models = array(); |
|
84 | - |
|
85 | - |
|
86 | - /** |
|
87 | - * Model_Version_Info constructor. |
|
88 | - * |
|
89 | - * @param string $requested_version |
|
90 | - */ |
|
91 | - public function __construct($requested_version) |
|
92 | - { |
|
93 | - $this->requested_version = (string) $requested_version; |
|
94 | - $this->model_changes = array( |
|
95 | - '4.8.29' => array( |
|
96 | - // first version where the REST API is in EE core, so no need |
|
97 | - // to specify how its different from the previous |
|
98 | - ), |
|
99 | - ); |
|
100 | - // setup data for "extra" fields added onto resources which don't actually exist on models |
|
101 | - $this->resource_changes = apply_filters( |
|
102 | - 'FHEE__Model_Version_Info___construct__extra_resource_properties_for_models', |
|
103 | - array() |
|
104 | - ); |
|
105 | - $defaults = array( |
|
106 | - 'raw' => false, |
|
107 | - 'type' => 'N/A', |
|
108 | - 'nullable' => true, |
|
109 | - 'table_alias' => 'N/A', |
|
110 | - 'table_column' => 'N/A', |
|
111 | - 'always_available' => true, |
|
112 | - ); |
|
113 | - foreach ($this->resource_changes as $version => $model_classnames) { |
|
114 | - foreach ($model_classnames as $model_classname => $extra_fields) { |
|
115 | - foreach ($extra_fields as $fieldname => $field_data) { |
|
116 | - $this->resource_changes[ $model_classname ][ $fieldname ]['name'] = $fieldname; |
|
117 | - foreach ($defaults as $attribute => $default_value) { |
|
118 | - if (! isset($this->resource_changes[ $model_classname ][ $fieldname ][ $attribute ])) { |
|
119 | - $this->resource_changes[ $model_classname ][ $fieldname ][ $attribute ] = $default_value; |
|
120 | - } |
|
121 | - } |
|
122 | - } |
|
123 | - } |
|
124 | - } |
|
125 | - } |
|
126 | - |
|
127 | - |
|
128 | - /** |
|
129 | - * Returns a slice of Model_Version_Info::model_changes()'s array |
|
130 | - * indicating exactly what changes happened between the current core version, |
|
131 | - * and the version requested |
|
132 | - * |
|
133 | - * @return array |
|
134 | - */ |
|
135 | - public function modelChangesBetweenRequestedVersionAndCurrent() |
|
136 | - { |
|
137 | - if ($this->cached_model_changes_between_requested_version_and_current === null) { |
|
138 | - $model_changes = array(); |
|
139 | - foreach ($this->modelChanges() as $version => $models_changed_in_version) { |
|
140 | - if ($version <= EED_Core_Rest_Api::core_version() && $version > $this->requestedVersion()) { |
|
141 | - $model_changes[ $version ] = $models_changed_in_version; |
|
142 | - } |
|
143 | - } |
|
144 | - $this->cached_model_changes_between_requested_version_and_current = $model_changes; |
|
145 | - } |
|
146 | - return $this->cached_model_changes_between_requested_version_and_current; |
|
147 | - } |
|
148 | - |
|
149 | - |
|
150 | - /** |
|
151 | - * Returns a slice of Model_Version_Info::model_changes()'s array |
|
152 | - * indicating exactly what changes happened between the current core version, |
|
153 | - * and the version requested |
|
154 | - * |
|
155 | - * @return array |
|
156 | - */ |
|
157 | - public function resourceChangesBetweenRequestedVersionAndCurrent() |
|
158 | - { |
|
159 | - if ($this->cached_resource_changes_between_requested_version_and_current === null) { |
|
160 | - $resource_changes = array(); |
|
161 | - foreach ($this->resourceChanges() as $version => $model_classnames) { |
|
162 | - if ($version <= EED_Core_Rest_Api::core_version() && $version > $this->requestedVersion()) { |
|
163 | - $resource_changes[ $version ] = $model_classnames; |
|
164 | - } |
|
165 | - } |
|
166 | - $this->cached_resource_changes_between_requested_version_and_current = $resource_changes; |
|
167 | - } |
|
168 | - return $this->cached_resource_changes_between_requested_version_and_current; |
|
169 | - } |
|
170 | - |
|
171 | - |
|
172 | - /** |
|
173 | - * If a request was sent to 'wp-json/ee/v4.7/events' this would be '4.7' |
|
174 | - * |
|
175 | - * @return string like '4.6' |
|
176 | - */ |
|
177 | - public function requestedVersion() |
|
178 | - { |
|
179 | - return $this->requested_version; |
|
180 | - } |
|
181 | - |
|
182 | - |
|
183 | - /** |
|
184 | - * Returns an array describing how the models have changed in each version of core |
|
185 | - * that supports the API (starting at 4.6) |
|
186 | - * Top-level keys are versions (major and minor version numbers, eg "4.6") |
|
187 | - * next-level keys are model names (eg "Event") that underwent some change in that version |
|
188 | - * and the value is either NULL (indicating the model is completely NEW in this version), |
|
189 | - * or it's an array where fields are value names. |
|
190 | - * If a version is missing then we don't know anything about what changes it introduced from the previous version |
|
191 | - * |
|
192 | - * @return array |
|
193 | - */ |
|
194 | - public function modelChanges() |
|
195 | - { |
|
196 | - return $this->model_changes; |
|
197 | - } |
|
198 | - |
|
199 | - |
|
200 | - /** |
|
201 | - * Takes into account the requested version, and the current version, and |
|
202 | - * what changed between the two, and tries to return. |
|
203 | - * Analogous to EE_Registry::instance()->non_abstract_db_models |
|
204 | - * |
|
205 | - * @return array keys are model names, values are their classname |
|
206 | - */ |
|
207 | - public function modelsForRequestedVersion() |
|
208 | - { |
|
209 | - if ($this->cached_models_for_requested_version === null) { |
|
210 | - $all_models_in_current_version = EE_Registry::instance()->non_abstract_db_models; |
|
211 | - foreach ($this->modelChangesBetweenRequestedVersionAndCurrent() as $version => $models_changed) { |
|
212 | - foreach ($models_changed as $model_name => $new_indicator_or_fields_added) { |
|
213 | - if ($new_indicator_or_fields_added === ModelVersionInfo::MODEL_ADDED) { |
|
214 | - unset($all_models_in_current_version[ $model_name ]); |
|
215 | - } |
|
216 | - } |
|
217 | - } |
|
218 | - $this->cached_models_for_requested_version = apply_filters( |
|
219 | - 'FHEE__EventEspresso_core_libraries_rest_api__models_for_requested_version', |
|
220 | - $all_models_in_current_version, |
|
221 | - $this |
|
222 | - ); |
|
223 | - } |
|
224 | - return $this->cached_models_for_requested_version; |
|
225 | - } |
|
226 | - |
|
227 | - |
|
228 | - /** |
|
229 | - * Determines if this is a valid model name in the requested version. |
|
230 | - * Similar to EE_Registry::instance()->is_model_name(), but takes the requested |
|
231 | - * version's models into account |
|
232 | - * |
|
233 | - * @param string $model_name eg 'Event' |
|
234 | - * @return boolean |
|
235 | - */ |
|
236 | - public function isModelNameInThisVersion($model_name) |
|
237 | - { |
|
238 | - $model_names = $this->modelsForRequestedVersion(); |
|
239 | - if (isset($model_names[ $model_name ])) { |
|
240 | - return true; |
|
241 | - } else { |
|
242 | - return false; |
|
243 | - } |
|
244 | - } |
|
245 | - |
|
246 | - |
|
247 | - /** |
|
248 | - * Wrapper for EE_Registry::instance()->load_model(), but takes the requested |
|
249 | - * version's models into account |
|
250 | - * |
|
251 | - * @param string $model_name |
|
252 | - * @return \EEM_Base |
|
253 | - * @throws \EE_Error |
|
254 | - */ |
|
255 | - public function loadModel($model_name) |
|
256 | - { |
|
257 | - if ($this->isModelNameInThisVersion($model_name)) { |
|
258 | - return EE_Registry::instance()->load_model($model_name); |
|
259 | - } else { |
|
260 | - throw new \EE_Error( |
|
261 | - sprintf( |
|
262 | - esc_html__( |
|
263 | - 'Cannot load model "%1$s" because it does not exist in version %2$s of Event Espresso', |
|
264 | - 'event_espresso' |
|
265 | - ), |
|
266 | - $model_name, |
|
267 | - $this->requestedVersion() |
|
268 | - ) |
|
269 | - ); |
|
270 | - } |
|
271 | - } |
|
272 | - |
|
273 | - |
|
274 | - /** |
|
275 | - * Gets all the fields that should exist on this model right now |
|
276 | - * |
|
277 | - * @param \EEM_Base $model |
|
278 | - * @return array|\EE_Model_Field_Base[] |
|
279 | - */ |
|
280 | - public function fieldsOnModelInThisVersion($model) |
|
281 | - { |
|
282 | - if (! isset($this->cached_fields_on_models[ $model->get_this_model_name() ])) { |
|
283 | - // get all model changes between the requested version and current core version |
|
284 | - $changes = $this->modelChangesBetweenRequestedVersionAndCurrent(); |
|
285 | - // fetch all fields currently on this model |
|
286 | - $current_fields = $model->field_settings(); |
|
287 | - // remove all fields that have been added since |
|
288 | - foreach ($changes as $version => $changes_in_version) { |
|
289 | - if ( |
|
290 | - isset($changes_in_version[ $model->get_this_model_name() ]) |
|
291 | - && $changes_in_version[ $model->get_this_model_name() ] !== ModelVersionInfo::MODEL_ADDED |
|
292 | - ) { |
|
293 | - $current_fields = array_diff_key( |
|
294 | - $current_fields, |
|
295 | - array_flip($changes_in_version[ $model->get_this_model_name() ]) |
|
296 | - ); |
|
297 | - } |
|
298 | - } |
|
299 | - $this->cached_fields_on_models = $current_fields; |
|
300 | - } |
|
301 | - return $this->cached_fields_on_models; |
|
302 | - } |
|
303 | - |
|
304 | - |
|
305 | - /** |
|
306 | - * Determines if $object is of one of the classes of $classes. Similar to |
|
307 | - * in_array(), except this checks if $object is a subclass of the classnames provided |
|
308 | - * in $classnames |
|
309 | - * |
|
310 | - * @param object $object |
|
311 | - * @param array $classnames |
|
312 | - * @return boolean |
|
313 | - */ |
|
314 | - public function isSubclassOfOne($object, $classnames) |
|
315 | - { |
|
316 | - foreach ($classnames as $classname) { |
|
317 | - if (is_a($object, $classname)) { |
|
318 | - return true; |
|
319 | - } |
|
320 | - } |
|
321 | - return false; |
|
322 | - } |
|
323 | - |
|
324 | - |
|
325 | - /** |
|
326 | - * Returns the list of model field classes that that the API basically ignores |
|
327 | - * |
|
328 | - * @return array |
|
329 | - */ |
|
330 | - public function fieldsIgnored() |
|
331 | - { |
|
332 | - return apply_filters( |
|
333 | - 'FHEE__Controller_Model_Read_fields_ignored', |
|
334 | - array() |
|
335 | - ); |
|
336 | - } |
|
337 | - |
|
338 | - |
|
339 | - /** |
|
340 | - * If this field one that should be ignored by the API? |
|
341 | - * |
|
342 | - * @param EE_Model_Field_Base |
|
343 | - * @return boolean |
|
344 | - */ |
|
345 | - public function fieldIsIgnored($field_obj) |
|
346 | - { |
|
347 | - return $this->isSubclassOfOne($field_obj, $this->fieldsIgnored()); |
|
348 | - } |
|
349 | - |
|
350 | - |
|
351 | - /** |
|
352 | - * Returns the list of model field classes that have a "raw" and non-raw formats. |
|
353 | - * Normally the "raw" versions are only accessible to those who can edit them. |
|
354 | - * |
|
355 | - * @return array an array of EE_Model_Field_Base child classnames |
|
356 | - */ |
|
357 | - public function fieldsThatHaveRenderedFormat() |
|
358 | - { |
|
359 | - return apply_filters( |
|
360 | - 'FHEE__Controller_Model_Read__fields_raw', |
|
361 | - array('EE_Post_Content_Field', 'EE_Full_HTML_Field') |
|
362 | - ); |
|
363 | - } |
|
364 | - |
|
365 | - |
|
366 | - /** |
|
367 | - * If this field one that has a raw format |
|
368 | - * |
|
369 | - * @param EE_Model_Field_Base |
|
370 | - * @return boolean |
|
371 | - */ |
|
372 | - public function fieldHasRenderedFormat($field_obj) |
|
373 | - { |
|
374 | - return $this->isSubclassOfOne($field_obj, $this->fieldsThatHaveRenderedFormat()); |
|
375 | - } |
|
376 | - |
|
377 | - |
|
378 | - /** |
|
379 | - * Returns the list of model field classes that have a "_pretty" and non-pretty versions. |
|
380 | - * The pretty version of the field is NOT query-able or editable, but requires no extra permissions |
|
381 | - * to view |
|
382 | - * |
|
383 | - * @return array an array of EE_Model_Field_Base child classnames |
|
384 | - */ |
|
385 | - public function fieldsThatHavePrettyFormat() |
|
386 | - { |
|
387 | - return apply_filters( |
|
388 | - 'FHEE__Controller_Model_Read__fields_pretty', |
|
389 | - array('EE_Enum_Integer_Field', 'EE_Enum_Text_Field', 'EE_Money_Field') |
|
390 | - ); |
|
391 | - } |
|
392 | - |
|
393 | - |
|
394 | - /** |
|
395 | - * If this field one that has a pretty equivalent |
|
396 | - * |
|
397 | - * @param EE_Model_Field_Base |
|
398 | - * @return boolean |
|
399 | - */ |
|
400 | - public function fieldHasPrettyFormat($field_obj) |
|
401 | - { |
|
402 | - return $this->isSubclassOfOne($field_obj, $this->fieldsThatHavePrettyFormat()); |
|
403 | - } |
|
404 | - |
|
405 | - |
|
406 | - /** |
|
407 | - * Returns an array describing what extra API resource properties have been added through the versions |
|
408 | - * |
|
409 | - * @return array @see $this->_extra_resource_properties_for_models |
|
410 | - */ |
|
411 | - public function resourceChanges() |
|
412 | - { |
|
413 | - return $this->resource_changes; |
|
414 | - } |
|
415 | - |
|
416 | - |
|
417 | - /** |
|
418 | - * Returns an array where keys are extra resource properties in this version of the API, |
|
419 | - * and values are key-value pairs describing the new properties. @see Model_Version::_resource_changes |
|
420 | - * |
|
421 | - * @param \EEM_Base $model |
|
422 | - * @return array |
|
423 | - */ |
|
424 | - public function extraResourcePropertiesForModel($model) |
|
425 | - { |
|
426 | - $extra_properties = array(); |
|
427 | - foreach ($this->resourceChangesBetweenRequestedVersionAndCurrent() as $version => $model_classnames) { |
|
428 | - foreach ($model_classnames as $model_classname => $properties_added_in_this_version) { |
|
429 | - if (is_subclass_of($model, $model_classname)) { |
|
430 | - $extra_properties = array_merge($extra_properties, $properties_added_in_this_version); |
|
431 | - } |
|
432 | - } |
|
433 | - } |
|
434 | - return $extra_properties; |
|
435 | - } |
|
436 | - |
|
437 | - |
|
438 | - /** |
|
439 | - * Gets all the related models for the specified model. It's good to use this |
|
440 | - * in case this model didn't exist for this version or something |
|
441 | - * |
|
442 | - * @param \EEM_Base $model |
|
443 | - * @return \EE_Model_Relation_Base[] |
|
444 | - */ |
|
445 | - public function relationSettings(\EEM_Base $model) |
|
446 | - { |
|
447 | - $relations = array(); |
|
448 | - foreach ($model->relation_settings() as $relation_name => $relation_obj) { |
|
449 | - if ($this->isModelNameInThisVersion($relation_name)) { |
|
450 | - $relations[ $relation_name ] = $relation_obj; |
|
451 | - } |
|
452 | - } |
|
453 | - // filter the results, but use the old filter name |
|
454 | - return apply_filters( |
|
455 | - 'FHEE__Read__create_entity_from_wpdb_result__related_models_to_include', |
|
456 | - $relations, |
|
457 | - $model |
|
458 | - ); |
|
459 | - } |
|
23 | + /** |
|
24 | + * Constant used in the $_model_changes array to indicate that a model |
|
25 | + * was completely new in this version |
|
26 | + */ |
|
27 | + const MODEL_ADDED = 'model_added_in_this_version'; |
|
28 | + |
|
29 | + /** |
|
30 | + * Top-level keys are versions (major and minor version numbers, eg "4.6") |
|
31 | + * next-level keys are model names (eg "Event") that underwent some change in that version |
|
32 | + * and the value is either Model_Version_Info::model_added (indicating the model is completely NEW in this version), |
|
33 | + * or it's an array where the values are model field names, |
|
34 | + * or API resource properties (ie, non-model fields that appear in REST API results) |
|
35 | + * If a version is missing then we don't know anything about what changes it introduced from the previous version |
|
36 | + * |
|
37 | + * @var array |
|
38 | + */ |
|
39 | + protected $model_changes = array(); |
|
40 | + |
|
41 | + /** |
|
42 | + * top-level keys are version numbers, |
|
43 | + * next-level keys are model CLASSNAMES (even parent classnames), |
|
44 | + * and next-level keys are extra resource properties to attach to those models' resources, |
|
45 | + * and next-level key-value pairs, where the keys are: |
|
46 | + * 'raw', 'type', 'nullable', 'table_alias', 'table_column', 'always_available' |
|
47 | + * |
|
48 | + * @var array |
|
49 | + */ |
|
50 | + protected $resource_changes = array(); |
|
51 | + |
|
52 | + /** |
|
53 | + * @var string indicating what version of the API was requested |
|
54 | + * (eg although core might be at version 4.8.11, they may have sent a request |
|
55 | + * for 4.6) |
|
56 | + */ |
|
57 | + protected $requested_version = null; |
|
58 | + |
|
59 | + /** |
|
60 | + * Keys are model names, values are their classnames. |
|
61 | + * We cache this so we only need to calculate this once per request |
|
62 | + * |
|
63 | + * @var array |
|
64 | + */ |
|
65 | + protected $cached_models_for_requested_version = null; |
|
66 | + |
|
67 | + /** |
|
68 | + * @var array |
|
69 | + */ |
|
70 | + protected $cached_model_changes_between_requested_version_and_current = null; |
|
71 | + |
|
72 | + /** |
|
73 | + * @var array |
|
74 | + */ |
|
75 | + protected $cached_resource_changes_between_requested_version_and_current = null; |
|
76 | + |
|
77 | + /** |
|
78 | + * 2d array where top-level keys are model names, 2nd-level keys are field names |
|
79 | + * and values are the actual field objects |
|
80 | + * |
|
81 | + * @var array |
|
82 | + */ |
|
83 | + protected $cached_fields_on_models = array(); |
|
84 | + |
|
85 | + |
|
86 | + /** |
|
87 | + * Model_Version_Info constructor. |
|
88 | + * |
|
89 | + * @param string $requested_version |
|
90 | + */ |
|
91 | + public function __construct($requested_version) |
|
92 | + { |
|
93 | + $this->requested_version = (string) $requested_version; |
|
94 | + $this->model_changes = array( |
|
95 | + '4.8.29' => array( |
|
96 | + // first version where the REST API is in EE core, so no need |
|
97 | + // to specify how its different from the previous |
|
98 | + ), |
|
99 | + ); |
|
100 | + // setup data for "extra" fields added onto resources which don't actually exist on models |
|
101 | + $this->resource_changes = apply_filters( |
|
102 | + 'FHEE__Model_Version_Info___construct__extra_resource_properties_for_models', |
|
103 | + array() |
|
104 | + ); |
|
105 | + $defaults = array( |
|
106 | + 'raw' => false, |
|
107 | + 'type' => 'N/A', |
|
108 | + 'nullable' => true, |
|
109 | + 'table_alias' => 'N/A', |
|
110 | + 'table_column' => 'N/A', |
|
111 | + 'always_available' => true, |
|
112 | + ); |
|
113 | + foreach ($this->resource_changes as $version => $model_classnames) { |
|
114 | + foreach ($model_classnames as $model_classname => $extra_fields) { |
|
115 | + foreach ($extra_fields as $fieldname => $field_data) { |
|
116 | + $this->resource_changes[ $model_classname ][ $fieldname ]['name'] = $fieldname; |
|
117 | + foreach ($defaults as $attribute => $default_value) { |
|
118 | + if (! isset($this->resource_changes[ $model_classname ][ $fieldname ][ $attribute ])) { |
|
119 | + $this->resource_changes[ $model_classname ][ $fieldname ][ $attribute ] = $default_value; |
|
120 | + } |
|
121 | + } |
|
122 | + } |
|
123 | + } |
|
124 | + } |
|
125 | + } |
|
126 | + |
|
127 | + |
|
128 | + /** |
|
129 | + * Returns a slice of Model_Version_Info::model_changes()'s array |
|
130 | + * indicating exactly what changes happened between the current core version, |
|
131 | + * and the version requested |
|
132 | + * |
|
133 | + * @return array |
|
134 | + */ |
|
135 | + public function modelChangesBetweenRequestedVersionAndCurrent() |
|
136 | + { |
|
137 | + if ($this->cached_model_changes_between_requested_version_and_current === null) { |
|
138 | + $model_changes = array(); |
|
139 | + foreach ($this->modelChanges() as $version => $models_changed_in_version) { |
|
140 | + if ($version <= EED_Core_Rest_Api::core_version() && $version > $this->requestedVersion()) { |
|
141 | + $model_changes[ $version ] = $models_changed_in_version; |
|
142 | + } |
|
143 | + } |
|
144 | + $this->cached_model_changes_between_requested_version_and_current = $model_changes; |
|
145 | + } |
|
146 | + return $this->cached_model_changes_between_requested_version_and_current; |
|
147 | + } |
|
148 | + |
|
149 | + |
|
150 | + /** |
|
151 | + * Returns a slice of Model_Version_Info::model_changes()'s array |
|
152 | + * indicating exactly what changes happened between the current core version, |
|
153 | + * and the version requested |
|
154 | + * |
|
155 | + * @return array |
|
156 | + */ |
|
157 | + public function resourceChangesBetweenRequestedVersionAndCurrent() |
|
158 | + { |
|
159 | + if ($this->cached_resource_changes_between_requested_version_and_current === null) { |
|
160 | + $resource_changes = array(); |
|
161 | + foreach ($this->resourceChanges() as $version => $model_classnames) { |
|
162 | + if ($version <= EED_Core_Rest_Api::core_version() && $version > $this->requestedVersion()) { |
|
163 | + $resource_changes[ $version ] = $model_classnames; |
|
164 | + } |
|
165 | + } |
|
166 | + $this->cached_resource_changes_between_requested_version_and_current = $resource_changes; |
|
167 | + } |
|
168 | + return $this->cached_resource_changes_between_requested_version_and_current; |
|
169 | + } |
|
170 | + |
|
171 | + |
|
172 | + /** |
|
173 | + * If a request was sent to 'wp-json/ee/v4.7/events' this would be '4.7' |
|
174 | + * |
|
175 | + * @return string like '4.6' |
|
176 | + */ |
|
177 | + public function requestedVersion() |
|
178 | + { |
|
179 | + return $this->requested_version; |
|
180 | + } |
|
181 | + |
|
182 | + |
|
183 | + /** |
|
184 | + * Returns an array describing how the models have changed in each version of core |
|
185 | + * that supports the API (starting at 4.6) |
|
186 | + * Top-level keys are versions (major and minor version numbers, eg "4.6") |
|
187 | + * next-level keys are model names (eg "Event") that underwent some change in that version |
|
188 | + * and the value is either NULL (indicating the model is completely NEW in this version), |
|
189 | + * or it's an array where fields are value names. |
|
190 | + * If a version is missing then we don't know anything about what changes it introduced from the previous version |
|
191 | + * |
|
192 | + * @return array |
|
193 | + */ |
|
194 | + public function modelChanges() |
|
195 | + { |
|
196 | + return $this->model_changes; |
|
197 | + } |
|
198 | + |
|
199 | + |
|
200 | + /** |
|
201 | + * Takes into account the requested version, and the current version, and |
|
202 | + * what changed between the two, and tries to return. |
|
203 | + * Analogous to EE_Registry::instance()->non_abstract_db_models |
|
204 | + * |
|
205 | + * @return array keys are model names, values are their classname |
|
206 | + */ |
|
207 | + public function modelsForRequestedVersion() |
|
208 | + { |
|
209 | + if ($this->cached_models_for_requested_version === null) { |
|
210 | + $all_models_in_current_version = EE_Registry::instance()->non_abstract_db_models; |
|
211 | + foreach ($this->modelChangesBetweenRequestedVersionAndCurrent() as $version => $models_changed) { |
|
212 | + foreach ($models_changed as $model_name => $new_indicator_or_fields_added) { |
|
213 | + if ($new_indicator_or_fields_added === ModelVersionInfo::MODEL_ADDED) { |
|
214 | + unset($all_models_in_current_version[ $model_name ]); |
|
215 | + } |
|
216 | + } |
|
217 | + } |
|
218 | + $this->cached_models_for_requested_version = apply_filters( |
|
219 | + 'FHEE__EventEspresso_core_libraries_rest_api__models_for_requested_version', |
|
220 | + $all_models_in_current_version, |
|
221 | + $this |
|
222 | + ); |
|
223 | + } |
|
224 | + return $this->cached_models_for_requested_version; |
|
225 | + } |
|
226 | + |
|
227 | + |
|
228 | + /** |
|
229 | + * Determines if this is a valid model name in the requested version. |
|
230 | + * Similar to EE_Registry::instance()->is_model_name(), but takes the requested |
|
231 | + * version's models into account |
|
232 | + * |
|
233 | + * @param string $model_name eg 'Event' |
|
234 | + * @return boolean |
|
235 | + */ |
|
236 | + public function isModelNameInThisVersion($model_name) |
|
237 | + { |
|
238 | + $model_names = $this->modelsForRequestedVersion(); |
|
239 | + if (isset($model_names[ $model_name ])) { |
|
240 | + return true; |
|
241 | + } else { |
|
242 | + return false; |
|
243 | + } |
|
244 | + } |
|
245 | + |
|
246 | + |
|
247 | + /** |
|
248 | + * Wrapper for EE_Registry::instance()->load_model(), but takes the requested |
|
249 | + * version's models into account |
|
250 | + * |
|
251 | + * @param string $model_name |
|
252 | + * @return \EEM_Base |
|
253 | + * @throws \EE_Error |
|
254 | + */ |
|
255 | + public function loadModel($model_name) |
|
256 | + { |
|
257 | + if ($this->isModelNameInThisVersion($model_name)) { |
|
258 | + return EE_Registry::instance()->load_model($model_name); |
|
259 | + } else { |
|
260 | + throw new \EE_Error( |
|
261 | + sprintf( |
|
262 | + esc_html__( |
|
263 | + 'Cannot load model "%1$s" because it does not exist in version %2$s of Event Espresso', |
|
264 | + 'event_espresso' |
|
265 | + ), |
|
266 | + $model_name, |
|
267 | + $this->requestedVersion() |
|
268 | + ) |
|
269 | + ); |
|
270 | + } |
|
271 | + } |
|
272 | + |
|
273 | + |
|
274 | + /** |
|
275 | + * Gets all the fields that should exist on this model right now |
|
276 | + * |
|
277 | + * @param \EEM_Base $model |
|
278 | + * @return array|\EE_Model_Field_Base[] |
|
279 | + */ |
|
280 | + public function fieldsOnModelInThisVersion($model) |
|
281 | + { |
|
282 | + if (! isset($this->cached_fields_on_models[ $model->get_this_model_name() ])) { |
|
283 | + // get all model changes between the requested version and current core version |
|
284 | + $changes = $this->modelChangesBetweenRequestedVersionAndCurrent(); |
|
285 | + // fetch all fields currently on this model |
|
286 | + $current_fields = $model->field_settings(); |
|
287 | + // remove all fields that have been added since |
|
288 | + foreach ($changes as $version => $changes_in_version) { |
|
289 | + if ( |
|
290 | + isset($changes_in_version[ $model->get_this_model_name() ]) |
|
291 | + && $changes_in_version[ $model->get_this_model_name() ] !== ModelVersionInfo::MODEL_ADDED |
|
292 | + ) { |
|
293 | + $current_fields = array_diff_key( |
|
294 | + $current_fields, |
|
295 | + array_flip($changes_in_version[ $model->get_this_model_name() ]) |
|
296 | + ); |
|
297 | + } |
|
298 | + } |
|
299 | + $this->cached_fields_on_models = $current_fields; |
|
300 | + } |
|
301 | + return $this->cached_fields_on_models; |
|
302 | + } |
|
303 | + |
|
304 | + |
|
305 | + /** |
|
306 | + * Determines if $object is of one of the classes of $classes. Similar to |
|
307 | + * in_array(), except this checks if $object is a subclass of the classnames provided |
|
308 | + * in $classnames |
|
309 | + * |
|
310 | + * @param object $object |
|
311 | + * @param array $classnames |
|
312 | + * @return boolean |
|
313 | + */ |
|
314 | + public function isSubclassOfOne($object, $classnames) |
|
315 | + { |
|
316 | + foreach ($classnames as $classname) { |
|
317 | + if (is_a($object, $classname)) { |
|
318 | + return true; |
|
319 | + } |
|
320 | + } |
|
321 | + return false; |
|
322 | + } |
|
323 | + |
|
324 | + |
|
325 | + /** |
|
326 | + * Returns the list of model field classes that that the API basically ignores |
|
327 | + * |
|
328 | + * @return array |
|
329 | + */ |
|
330 | + public function fieldsIgnored() |
|
331 | + { |
|
332 | + return apply_filters( |
|
333 | + 'FHEE__Controller_Model_Read_fields_ignored', |
|
334 | + array() |
|
335 | + ); |
|
336 | + } |
|
337 | + |
|
338 | + |
|
339 | + /** |
|
340 | + * If this field one that should be ignored by the API? |
|
341 | + * |
|
342 | + * @param EE_Model_Field_Base |
|
343 | + * @return boolean |
|
344 | + */ |
|
345 | + public function fieldIsIgnored($field_obj) |
|
346 | + { |
|
347 | + return $this->isSubclassOfOne($field_obj, $this->fieldsIgnored()); |
|
348 | + } |
|
349 | + |
|
350 | + |
|
351 | + /** |
|
352 | + * Returns the list of model field classes that have a "raw" and non-raw formats. |
|
353 | + * Normally the "raw" versions are only accessible to those who can edit them. |
|
354 | + * |
|
355 | + * @return array an array of EE_Model_Field_Base child classnames |
|
356 | + */ |
|
357 | + public function fieldsThatHaveRenderedFormat() |
|
358 | + { |
|
359 | + return apply_filters( |
|
360 | + 'FHEE__Controller_Model_Read__fields_raw', |
|
361 | + array('EE_Post_Content_Field', 'EE_Full_HTML_Field') |
|
362 | + ); |
|
363 | + } |
|
364 | + |
|
365 | + |
|
366 | + /** |
|
367 | + * If this field one that has a raw format |
|
368 | + * |
|
369 | + * @param EE_Model_Field_Base |
|
370 | + * @return boolean |
|
371 | + */ |
|
372 | + public function fieldHasRenderedFormat($field_obj) |
|
373 | + { |
|
374 | + return $this->isSubclassOfOne($field_obj, $this->fieldsThatHaveRenderedFormat()); |
|
375 | + } |
|
376 | + |
|
377 | + |
|
378 | + /** |
|
379 | + * Returns the list of model field classes that have a "_pretty" and non-pretty versions. |
|
380 | + * The pretty version of the field is NOT query-able or editable, but requires no extra permissions |
|
381 | + * to view |
|
382 | + * |
|
383 | + * @return array an array of EE_Model_Field_Base child classnames |
|
384 | + */ |
|
385 | + public function fieldsThatHavePrettyFormat() |
|
386 | + { |
|
387 | + return apply_filters( |
|
388 | + 'FHEE__Controller_Model_Read__fields_pretty', |
|
389 | + array('EE_Enum_Integer_Field', 'EE_Enum_Text_Field', 'EE_Money_Field') |
|
390 | + ); |
|
391 | + } |
|
392 | + |
|
393 | + |
|
394 | + /** |
|
395 | + * If this field one that has a pretty equivalent |
|
396 | + * |
|
397 | + * @param EE_Model_Field_Base |
|
398 | + * @return boolean |
|
399 | + */ |
|
400 | + public function fieldHasPrettyFormat($field_obj) |
|
401 | + { |
|
402 | + return $this->isSubclassOfOne($field_obj, $this->fieldsThatHavePrettyFormat()); |
|
403 | + } |
|
404 | + |
|
405 | + |
|
406 | + /** |
|
407 | + * Returns an array describing what extra API resource properties have been added through the versions |
|
408 | + * |
|
409 | + * @return array @see $this->_extra_resource_properties_for_models |
|
410 | + */ |
|
411 | + public function resourceChanges() |
|
412 | + { |
|
413 | + return $this->resource_changes; |
|
414 | + } |
|
415 | + |
|
416 | + |
|
417 | + /** |
|
418 | + * Returns an array where keys are extra resource properties in this version of the API, |
|
419 | + * and values are key-value pairs describing the new properties. @see Model_Version::_resource_changes |
|
420 | + * |
|
421 | + * @param \EEM_Base $model |
|
422 | + * @return array |
|
423 | + */ |
|
424 | + public function extraResourcePropertiesForModel($model) |
|
425 | + { |
|
426 | + $extra_properties = array(); |
|
427 | + foreach ($this->resourceChangesBetweenRequestedVersionAndCurrent() as $version => $model_classnames) { |
|
428 | + foreach ($model_classnames as $model_classname => $properties_added_in_this_version) { |
|
429 | + if (is_subclass_of($model, $model_classname)) { |
|
430 | + $extra_properties = array_merge($extra_properties, $properties_added_in_this_version); |
|
431 | + } |
|
432 | + } |
|
433 | + } |
|
434 | + return $extra_properties; |
|
435 | + } |
|
436 | + |
|
437 | + |
|
438 | + /** |
|
439 | + * Gets all the related models for the specified model. It's good to use this |
|
440 | + * in case this model didn't exist for this version or something |
|
441 | + * |
|
442 | + * @param \EEM_Base $model |
|
443 | + * @return \EE_Model_Relation_Base[] |
|
444 | + */ |
|
445 | + public function relationSettings(\EEM_Base $model) |
|
446 | + { |
|
447 | + $relations = array(); |
|
448 | + foreach ($model->relation_settings() as $relation_name => $relation_obj) { |
|
449 | + if ($this->isModelNameInThisVersion($relation_name)) { |
|
450 | + $relations[ $relation_name ] = $relation_obj; |
|
451 | + } |
|
452 | + } |
|
453 | + // filter the results, but use the old filter name |
|
454 | + return apply_filters( |
|
455 | + 'FHEE__Read__create_entity_from_wpdb_result__related_models_to_include', |
|
456 | + $relations, |
|
457 | + $model |
|
458 | + ); |
|
459 | + } |
|
460 | 460 | } |
@@ -196,11 +196,11 @@ discard block |
||
196 | 196 | ! empty($messenger) |
197 | 197 | && $Message_Resource_Manager->is_message_type_active_for_messenger($messenger, $this->name) |
198 | 198 | ) { |
199 | - $settings_to_use = $active_messengers[ $messenger ]['settings'][ $messenger . '-message_types' ]; |
|
199 | + $settings_to_use = $active_messengers[$messenger]['settings'][$messenger.'-message_types']; |
|
200 | 200 | } |
201 | 201 | |
202 | - $this->_existing_admin_settings = isset($settings_to_use[ $this->name ]['settings']) |
|
203 | - ? $settings_to_use[ $this->name ]['settings'] |
|
202 | + $this->_existing_admin_settings = isset($settings_to_use[$this->name]['settings']) |
|
203 | + ? $settings_to_use[$this->name]['settings'] |
|
204 | 204 | : null; |
205 | 205 | } |
206 | 206 | |
@@ -240,7 +240,7 @@ discard block |
||
240 | 240 | public function get_valid_shortcodes() |
241 | 241 | { |
242 | 242 | $valid_shortcodes = apply_filters( |
243 | - 'FHEE__' . get_class($this) . '__get_valid_shortcodes', |
|
243 | + 'FHEE__'.get_class($this).'__get_valid_shortcodes', |
|
244 | 244 | $this->_valid_shortcodes, |
245 | 245 | $this |
246 | 246 | ); |
@@ -283,19 +283,19 @@ discard block |
||
283 | 283 | protected function _get_admin_page_content($page, $action, $extra, $actives) |
284 | 284 | { |
285 | 285 | // we can also further refine the context by action (if present). |
286 | - if (!empty($action)) { |
|
287 | - $page = $page . '_' . $action; |
|
286 | + if ( ! empty($action)) { |
|
287 | + $page = $page.'_'.$action; |
|
288 | 288 | } |
289 | 289 | |
290 | - if (!isset($this->admin_registered_pages[ $page ])) { |
|
290 | + if ( ! isset($this->admin_registered_pages[$page])) { |
|
291 | 291 | // todo: a place to throw an exception? |
292 | 292 | // We need to indicate there is no registered page so this function is not being called correctly. |
293 | 293 | return false; |
294 | 294 | } |
295 | 295 | // k made it here so let's call the method |
296 | 296 | $content = call_user_func_array( |
297 | - array( $this, '_get_admin_content_' . $page ), |
|
298 | - array( $actives, $extra ) |
|
297 | + array($this, '_get_admin_content_'.$page), |
|
298 | + array($actives, $extra) |
|
299 | 299 | ); |
300 | 300 | if ($content === false) { |
301 | 301 | // todo this needs to be an exception once we've got exceptions in place. |
@@ -13,44 +13,44 @@ discard block |
||
13 | 13 | */ |
14 | 14 | abstract class EE_Messages_Base extends EE_Base |
15 | 15 | { |
16 | - /** DETAILS PROPERTIES **/ |
|
17 | - /** |
|
18 | - * The following are used to hold details on the type for reference (i.e. on admin screens) |
|
19 | - * and also used by the EE_message_type object to figure out where to get template data. |
|
20 | - */ |
|
21 | - public $name; |
|
22 | - public $description; |
|
23 | - protected $_messages_item_type; // messenger OR message_type? |
|
24 | - |
|
25 | - |
|
26 | - /** |
|
27 | - * This is an array describing the ui facing labels |
|
28 | - * that will be used whenever the messenger is referenced in the ui |
|
29 | - * |
|
30 | - * array( |
|
31 | - * 'singular' => esc_html__('something'), |
|
32 | - * 'plural' => esc_html__('somethings') |
|
33 | - * ) |
|
34 | - * |
|
35 | - * @var array |
|
36 | - */ |
|
37 | - public $label; |
|
38 | - |
|
39 | - |
|
40 | - |
|
41 | - |
|
42 | - /** |
|
43 | - * This property when set will hold the slugs of all EE admin pages that we will need to retrieve fields for |
|
44 | - * (and used to determine which callback method to call from the child class) |
|
45 | - * |
|
46 | - * structure should be |
|
47 | - * array( |
|
48 | - * 'page_action' => true |
|
49 | - * ) |
|
50 | - * |
|
16 | + /** DETAILS PROPERTIES **/ |
|
17 | + /** |
|
18 | + * The following are used to hold details on the type for reference (i.e. on admin screens) |
|
19 | + * and also used by the EE_message_type object to figure out where to get template data. |
|
20 | + */ |
|
21 | + public $name; |
|
22 | + public $description; |
|
23 | + protected $_messages_item_type; // messenger OR message_type? |
|
24 | + |
|
25 | + |
|
26 | + /** |
|
27 | + * This is an array describing the ui facing labels |
|
28 | + * that will be used whenever the messenger is referenced in the ui |
|
29 | + * |
|
30 | + * array( |
|
31 | + * 'singular' => esc_html__('something'), |
|
32 | + * 'plural' => esc_html__('somethings') |
|
33 | + * ) |
|
34 | + * |
|
35 | + * @var array |
|
36 | + */ |
|
37 | + public $label; |
|
38 | + |
|
39 | + |
|
40 | + |
|
41 | + |
|
42 | + /** |
|
43 | + * This property when set will hold the slugs of all EE admin pages that we will need to retrieve fields for |
|
44 | + * (and used to determine which callback method to call from the child class) |
|
45 | + * |
|
46 | + * structure should be |
|
47 | + * array( |
|
48 | + * 'page_action' => true |
|
49 | + * ) |
|
50 | + * |
|
51 | 51 | *@var array |
52 | - */ |
|
53 | - public $admin_registered_pages = array(); |
|
52 | + */ |
|
53 | + public $admin_registered_pages = array(); |
|
54 | 54 | |
55 | 55 | |
56 | 56 | |
@@ -59,265 +59,265 @@ discard block |
||
59 | 59 | |
60 | 60 | |
61 | 61 | |
62 | - /** |
|
63 | - * this property holds any specific fields for holding any settings related to a messenger (if any needed) |
|
64 | - * @var array |
|
65 | - */ |
|
66 | - protected $_admin_settings_fields = array(); |
|
62 | + /** |
|
63 | + * this property holds any specific fields for holding any settings related to a messenger (if any needed) |
|
64 | + * @var array |
|
65 | + */ |
|
66 | + protected $_admin_settings_fields = array(); |
|
67 | 67 | |
68 | 68 | |
69 | 69 | |
70 | 70 | |
71 | 71 | |
72 | - /** |
|
73 | - * this property will hold any existing settings that may have been set in the admin. |
|
74 | - * @var array |
|
75 | - */ |
|
76 | - protected $_existing_admin_settings = array(); |
|
72 | + /** |
|
73 | + * this property will hold any existing settings that may have been set in the admin. |
|
74 | + * @var array |
|
75 | + */ |
|
76 | + protected $_existing_admin_settings = array(); |
|
77 | 77 | |
78 | 78 | |
79 | 79 | |
80 | 80 | |
81 | 81 | |
82 | - /** |
|
83 | - * this property will hold an array of valid shortcodes for this message type and messengers. |
|
84 | - * #For Message Types: |
|
85 | - * This is an array of strings that correspond to defined EE_Shortcode libraries and per context. |
|
86 | - * For example: |
|
87 | - * array( 'admin' => array('transaction', 'event', 'attendee') ) |
|
88 | - * corresponds to 'EE_Transaction_Shortcodes.lib.php, EE_Event_Shortcodes.lib.php, EE_Attendee_Shortcodes.lib.php' |
|
89 | - * for the admin context; |
|
90 | - * |
|
91 | - * |
|
92 | - * #For Messengers: |
|
93 | - * For example: |
|
94 | - * array('subject' => array('transaction', 'event', 'attendee')) |
|
95 | - * corresponds to 'EE_Transaction_Shortcodes.lib.php, EE_Event_Shortcodes.lib.php, EE_Attendee_Shortcodes.lib.php' |
|
96 | - * for the 'subject' field; |
|
97 | - * NOTE: by default, with messengers, if the valid shortcodes for a field is left blank, |
|
98 | - * that field will inherit whatever are set as valid shortcodes by message_type. |
|
99 | - * This is so messenger can set specific valid codes for fields and leave other |
|
100 | - * valid shortcodes up to the message type matched with the messenger. |
|
101 | - * |
|
102 | - * @access protected |
|
103 | - * @var array |
|
104 | - */ |
|
105 | - protected $_valid_shortcodes = array(); |
|
82 | + /** |
|
83 | + * this property will hold an array of valid shortcodes for this message type and messengers. |
|
84 | + * #For Message Types: |
|
85 | + * This is an array of strings that correspond to defined EE_Shortcode libraries and per context. |
|
86 | + * For example: |
|
87 | + * array( 'admin' => array('transaction', 'event', 'attendee') ) |
|
88 | + * corresponds to 'EE_Transaction_Shortcodes.lib.php, EE_Event_Shortcodes.lib.php, EE_Attendee_Shortcodes.lib.php' |
|
89 | + * for the admin context; |
|
90 | + * |
|
91 | + * |
|
92 | + * #For Messengers: |
|
93 | + * For example: |
|
94 | + * array('subject' => array('transaction', 'event', 'attendee')) |
|
95 | + * corresponds to 'EE_Transaction_Shortcodes.lib.php, EE_Event_Shortcodes.lib.php, EE_Attendee_Shortcodes.lib.php' |
|
96 | + * for the 'subject' field; |
|
97 | + * NOTE: by default, with messengers, if the valid shortcodes for a field is left blank, |
|
98 | + * that field will inherit whatever are set as valid shortcodes by message_type. |
|
99 | + * This is so messenger can set specific valid codes for fields and leave other |
|
100 | + * valid shortcodes up to the message type matched with the messenger. |
|
101 | + * |
|
102 | + * @access protected |
|
103 | + * @var array |
|
104 | + */ |
|
105 | + protected $_valid_shortcodes = array(); |
|
106 | 106 | |
107 | 107 | |
108 | 108 | |
109 | 109 | |
110 | 110 | |
111 | - public function __construct() |
|
112 | - { |
|
113 | - $this->_set_admin_settings_fields(); |
|
114 | - $this->_set_valid_shortcodes(); |
|
115 | - $this->_set_admin_pages(); |
|
116 | - } |
|
111 | + public function __construct() |
|
112 | + { |
|
113 | + $this->_set_admin_settings_fields(); |
|
114 | + $this->_set_valid_shortcodes(); |
|
115 | + $this->_set_admin_pages(); |
|
116 | + } |
|
117 | 117 | |
118 | 118 | |
119 | 119 | |
120 | 120 | |
121 | 121 | |
122 | - /** |
|
123 | - * sets the _admin_settings_fields property which needs to be defined by child classes. |
|
124 | - * You will want to set the _admin_settings_fields properties as a multi-dimensional array with the following format |
|
125 | - * array( |
|
126 | - * {field_name - also used for setting index} => array( |
|
127 | - * 'field_type' => {type of field: 'text', 'textarea', 'checkbox'}, |
|
128 | - * 'value_type' => {type of value: 'string', 'int', 'array', 'bool'}, |
|
129 | - * 'required' => {bool, required or not}, |
|
130 | - * 'validation' => {bool, true if we want validation, false if not}, |
|
131 | - * 'format' => {%d, or %s}, |
|
132 | - * 'label' => {label for the field, make sure it's localized}, |
|
133 | - * 'default' => {default value for the setting} |
|
134 | - * ), |
|
135 | - * ); |
|
136 | - * |
|
137 | - * @abstract |
|
138 | - * @access protected |
|
139 | - * @return void |
|
140 | - */ |
|
141 | - abstract protected function _set_admin_settings_fields(); |
|
122 | + /** |
|
123 | + * sets the _admin_settings_fields property which needs to be defined by child classes. |
|
124 | + * You will want to set the _admin_settings_fields properties as a multi-dimensional array with the following format |
|
125 | + * array( |
|
126 | + * {field_name - also used for setting index} => array( |
|
127 | + * 'field_type' => {type of field: 'text', 'textarea', 'checkbox'}, |
|
128 | + * 'value_type' => {type of value: 'string', 'int', 'array', 'bool'}, |
|
129 | + * 'required' => {bool, required or not}, |
|
130 | + * 'validation' => {bool, true if we want validation, false if not}, |
|
131 | + * 'format' => {%d, or %s}, |
|
132 | + * 'label' => {label for the field, make sure it's localized}, |
|
133 | + * 'default' => {default value for the setting} |
|
134 | + * ), |
|
135 | + * ); |
|
136 | + * |
|
137 | + * @abstract |
|
138 | + * @access protected |
|
139 | + * @return void |
|
140 | + */ |
|
141 | + abstract protected function _set_admin_settings_fields(); |
|
142 | 142 | |
143 | 143 | |
144 | 144 | |
145 | 145 | |
146 | 146 | |
147 | - /** |
|
148 | - * sets any properties on whether a message type or messenger interface shows up on a ee administration page. |
|
149 | - * Child classes have to define this method but don't necessarily have to set the flags |
|
150 | - * as they will be set to false by default. |
|
151 | - * |
|
152 | - * Child classes use this method to set the `_admin_registered_page` property. |
|
153 | - * That property is to indicate what EE admin pages we have a corresponding callback for in the child class |
|
154 | - * so Message Type/messenger fields/content is included on that admin page. |
|
155 | - * |
|
156 | - * @abstract |
|
157 | - * @access protected |
|
158 | - * @return void |
|
159 | - */ |
|
160 | - abstract protected function _set_admin_pages(); |
|
147 | + /** |
|
148 | + * sets any properties on whether a message type or messenger interface shows up on a ee administration page. |
|
149 | + * Child classes have to define this method but don't necessarily have to set the flags |
|
150 | + * as they will be set to false by default. |
|
151 | + * |
|
152 | + * Child classes use this method to set the `_admin_registered_page` property. |
|
153 | + * That property is to indicate what EE admin pages we have a corresponding callback for in the child class |
|
154 | + * so Message Type/messenger fields/content is included on that admin page. |
|
155 | + * |
|
156 | + * @abstract |
|
157 | + * @access protected |
|
158 | + * @return void |
|
159 | + */ |
|
160 | + abstract protected function _set_admin_pages(); |
|
161 | 161 | |
162 | 162 | |
163 | 163 | |
164 | 164 | |
165 | 165 | |
166 | - /** |
|
167 | - * Child classes must declare the $_valid_shortcodes property using this method. |
|
168 | - * See comments for $_valid_shortcodes property for details on what it is used for. |
|
169 | - * |
|
170 | - * @access protected |
|
171 | - * @return void |
|
172 | - */ |
|
173 | - abstract protected function _set_valid_shortcodes(); |
|
166 | + /** |
|
167 | + * Child classes must declare the $_valid_shortcodes property using this method. |
|
168 | + * See comments for $_valid_shortcodes property for details on what it is used for. |
|
169 | + * |
|
170 | + * @access protected |
|
171 | + * @return void |
|
172 | + */ |
|
173 | + abstract protected function _set_valid_shortcodes(); |
|
174 | 174 | |
175 | 175 | |
176 | 176 | |
177 | - /** |
|
178 | - * sets the _existing_admin_settings property can be overridden by child classes. |
|
179 | - * We do this so we only do database calls if needed. |
|
180 | - * |
|
181 | - * @access protected |
|
182 | - * @param string $messenger |
|
183 | - */ |
|
184 | - protected function _set_existing_admin_settings($messenger = '') |
|
185 | - { |
|
186 | - /** @var EE_Message_Resource_Manager $Message_Resource_Manager */ |
|
187 | - $Message_Resource_Manager = EE_Registry::instance()->load_lib('Message_Resource_Manager'); |
|
188 | - $active_messengers = $Message_Resource_Manager->get_active_messengers_option(); |
|
189 | - $settings_to_use = $active_messengers; |
|
190 | - |
|
191 | - /** |
|
192 | - * This determines what will be used for the getting the settings. |
|
193 | - */ |
|
194 | - if ( |
|
195 | - ! empty($messenger) |
|
196 | - && $Message_Resource_Manager->is_message_type_active_for_messenger($messenger, $this->name) |
|
197 | - ) { |
|
198 | - $settings_to_use = $active_messengers[ $messenger ]['settings'][ $messenger . '-message_types' ]; |
|
199 | - } |
|
200 | - |
|
201 | - $this->_existing_admin_settings = isset($settings_to_use[ $this->name ]['settings']) |
|
202 | - ? $settings_to_use[ $this->name ]['settings'] |
|
203 | - : null; |
|
204 | - } |
|
205 | - |
|
206 | - |
|
207 | - |
|
208 | - |
|
209 | - |
|
210 | - |
|
211 | - /** |
|
212 | - * get_existing_admin_settings |
|
213 | - * (if needed) sets and returns the _existing_admin_settings property. |
|
214 | - * |
|
215 | - * @access public |
|
216 | - * @param string $messenger |
|
217 | - * @return array settings |
|
218 | - */ |
|
219 | - public function get_existing_admin_settings($messenger = '') |
|
220 | - { |
|
221 | - // if admin_settings property empty lets try setting it. |
|
222 | - if (method_exists($this, '_set_existing_admin_settings') && empty($this->_existing_admin_settings)) { |
|
223 | - $this->_set_existing_admin_settings($messenger); |
|
224 | - } |
|
225 | - return property_exists($this, '_existing_admin_settings') |
|
226 | - ? $this->_existing_admin_settings |
|
227 | - : null; |
|
228 | - } |
|
229 | - |
|
230 | - |
|
231 | - |
|
232 | - |
|
233 | - |
|
234 | - |
|
235 | - /** |
|
236 | - * This returns the array of valid shortcodes for a message type or messenger as set by the child in the $_valid_shortcode property. |
|
237 | - * @return array an array of valid shortcodes. |
|
238 | - */ |
|
239 | - public function get_valid_shortcodes() |
|
240 | - { |
|
241 | - $valid_shortcodes = apply_filters( |
|
242 | - 'FHEE__' . get_class($this) . '__get_valid_shortcodes', |
|
243 | - $this->_valid_shortcodes, |
|
244 | - $this |
|
245 | - ); |
|
246 | - // The below filter applies to ALL messengers and message types so use with care! |
|
247 | - $valid_shortcodes = apply_filters('FHEE__EE_Messages_Base__get_valid_shortcodes', $valid_shortcodes, $this); |
|
248 | - return $valid_shortcodes; |
|
249 | - } |
|
250 | - |
|
251 | - |
|
252 | - |
|
253 | - |
|
254 | - /** |
|
255 | - * getter that returns the protected admin_settings_fields property |
|
256 | - * |
|
257 | - * @access public |
|
258 | - * @return array admin settings fields |
|
259 | - */ |
|
260 | - public function get_admin_settings_fields() |
|
261 | - { |
|
262 | - return $this->_admin_settings_fields; |
|
263 | - } |
|
264 | - |
|
265 | - |
|
266 | - |
|
267 | - |
|
268 | - |
|
269 | - /** |
|
270 | - * this public method accepts a page slug (for an EE_admin page) |
|
271 | - * and will return the response from the child class callback function |
|
272 | - * if that page is registered via the `_admin_registered_page` property set by the child class. |
|
273 | - * |
|
274 | - * @param string $page the slug of the EE admin page |
|
275 | - * @param array $actives an array of active message type (or messenger) objects. |
|
276 | - * @param string $action the page action (to allow for more specific handling - i.e. edit vs. add pages) |
|
277 | - * @param array $extra This is just an extra argument that can be used |
|
278 | - * to pass additional data for setting up page content. |
|
279 | - * @access protected |
|
280 | - * @return string $content for page. |
|
281 | - */ |
|
282 | - protected function _get_admin_page_content($page, $action, $extra, $actives) |
|
283 | - { |
|
284 | - // we can also further refine the context by action (if present). |
|
285 | - if (!empty($action)) { |
|
286 | - $page = $page . '_' . $action; |
|
287 | - } |
|
288 | - |
|
289 | - if (!isset($this->admin_registered_pages[ $page ])) { |
|
290 | - // todo: a place to throw an exception? |
|
291 | - // We need to indicate there is no registered page so this function is not being called correctly. |
|
292 | - return false; |
|
293 | - } |
|
294 | - // k made it here so let's call the method |
|
295 | - $content = call_user_func_array( |
|
296 | - array( $this, '_get_admin_content_' . $page ), |
|
297 | - array( $actives, $extra ) |
|
298 | - ); |
|
299 | - if ($content === false) { |
|
300 | - // todo this needs to be an exception once we've got exceptions in place. |
|
301 | - return false; |
|
302 | - } |
|
303 | - return $content; |
|
304 | - } |
|
305 | - |
|
306 | - |
|
307 | - /** |
|
308 | - * Allows a message type to specifically exclude template fields for the provided messenger. |
|
309 | - * Filtered so this can be programmatically altered as well. |
|
310 | - * @param string $messenger_name name of messenger |
|
311 | - * @return array |
|
312 | - */ |
|
313 | - public function excludedFieldsForMessenger($messenger_name) |
|
314 | - { |
|
315 | - return apply_filters( |
|
316 | - 'FHEE__EE_Messages_Base__excludedFieldForMessenger', |
|
317 | - array(), |
|
318 | - $messenger_name, |
|
319 | - $this->name, |
|
320 | - $this |
|
321 | - ); |
|
322 | - } |
|
177 | + /** |
|
178 | + * sets the _existing_admin_settings property can be overridden by child classes. |
|
179 | + * We do this so we only do database calls if needed. |
|
180 | + * |
|
181 | + * @access protected |
|
182 | + * @param string $messenger |
|
183 | + */ |
|
184 | + protected function _set_existing_admin_settings($messenger = '') |
|
185 | + { |
|
186 | + /** @var EE_Message_Resource_Manager $Message_Resource_Manager */ |
|
187 | + $Message_Resource_Manager = EE_Registry::instance()->load_lib('Message_Resource_Manager'); |
|
188 | + $active_messengers = $Message_Resource_Manager->get_active_messengers_option(); |
|
189 | + $settings_to_use = $active_messengers; |
|
190 | + |
|
191 | + /** |
|
192 | + * This determines what will be used for the getting the settings. |
|
193 | + */ |
|
194 | + if ( |
|
195 | + ! empty($messenger) |
|
196 | + && $Message_Resource_Manager->is_message_type_active_for_messenger($messenger, $this->name) |
|
197 | + ) { |
|
198 | + $settings_to_use = $active_messengers[ $messenger ]['settings'][ $messenger . '-message_types' ]; |
|
199 | + } |
|
200 | + |
|
201 | + $this->_existing_admin_settings = isset($settings_to_use[ $this->name ]['settings']) |
|
202 | + ? $settings_to_use[ $this->name ]['settings'] |
|
203 | + : null; |
|
204 | + } |
|
205 | + |
|
206 | + |
|
207 | + |
|
208 | + |
|
209 | + |
|
210 | + |
|
211 | + /** |
|
212 | + * get_existing_admin_settings |
|
213 | + * (if needed) sets and returns the _existing_admin_settings property. |
|
214 | + * |
|
215 | + * @access public |
|
216 | + * @param string $messenger |
|
217 | + * @return array settings |
|
218 | + */ |
|
219 | + public function get_existing_admin_settings($messenger = '') |
|
220 | + { |
|
221 | + // if admin_settings property empty lets try setting it. |
|
222 | + if (method_exists($this, '_set_existing_admin_settings') && empty($this->_existing_admin_settings)) { |
|
223 | + $this->_set_existing_admin_settings($messenger); |
|
224 | + } |
|
225 | + return property_exists($this, '_existing_admin_settings') |
|
226 | + ? $this->_existing_admin_settings |
|
227 | + : null; |
|
228 | + } |
|
229 | + |
|
230 | + |
|
231 | + |
|
232 | + |
|
233 | + |
|
234 | + |
|
235 | + /** |
|
236 | + * This returns the array of valid shortcodes for a message type or messenger as set by the child in the $_valid_shortcode property. |
|
237 | + * @return array an array of valid shortcodes. |
|
238 | + */ |
|
239 | + public function get_valid_shortcodes() |
|
240 | + { |
|
241 | + $valid_shortcodes = apply_filters( |
|
242 | + 'FHEE__' . get_class($this) . '__get_valid_shortcodes', |
|
243 | + $this->_valid_shortcodes, |
|
244 | + $this |
|
245 | + ); |
|
246 | + // The below filter applies to ALL messengers and message types so use with care! |
|
247 | + $valid_shortcodes = apply_filters('FHEE__EE_Messages_Base__get_valid_shortcodes', $valid_shortcodes, $this); |
|
248 | + return $valid_shortcodes; |
|
249 | + } |
|
250 | + |
|
251 | + |
|
252 | + |
|
253 | + |
|
254 | + /** |
|
255 | + * getter that returns the protected admin_settings_fields property |
|
256 | + * |
|
257 | + * @access public |
|
258 | + * @return array admin settings fields |
|
259 | + */ |
|
260 | + public function get_admin_settings_fields() |
|
261 | + { |
|
262 | + return $this->_admin_settings_fields; |
|
263 | + } |
|
264 | + |
|
265 | + |
|
266 | + |
|
267 | + |
|
268 | + |
|
269 | + /** |
|
270 | + * this public method accepts a page slug (for an EE_admin page) |
|
271 | + * and will return the response from the child class callback function |
|
272 | + * if that page is registered via the `_admin_registered_page` property set by the child class. |
|
273 | + * |
|
274 | + * @param string $page the slug of the EE admin page |
|
275 | + * @param array $actives an array of active message type (or messenger) objects. |
|
276 | + * @param string $action the page action (to allow for more specific handling - i.e. edit vs. add pages) |
|
277 | + * @param array $extra This is just an extra argument that can be used |
|
278 | + * to pass additional data for setting up page content. |
|
279 | + * @access protected |
|
280 | + * @return string $content for page. |
|
281 | + */ |
|
282 | + protected function _get_admin_page_content($page, $action, $extra, $actives) |
|
283 | + { |
|
284 | + // we can also further refine the context by action (if present). |
|
285 | + if (!empty($action)) { |
|
286 | + $page = $page . '_' . $action; |
|
287 | + } |
|
288 | + |
|
289 | + if (!isset($this->admin_registered_pages[ $page ])) { |
|
290 | + // todo: a place to throw an exception? |
|
291 | + // We need to indicate there is no registered page so this function is not being called correctly. |
|
292 | + return false; |
|
293 | + } |
|
294 | + // k made it here so let's call the method |
|
295 | + $content = call_user_func_array( |
|
296 | + array( $this, '_get_admin_content_' . $page ), |
|
297 | + array( $actives, $extra ) |
|
298 | + ); |
|
299 | + if ($content === false) { |
|
300 | + // todo this needs to be an exception once we've got exceptions in place. |
|
301 | + return false; |
|
302 | + } |
|
303 | + return $content; |
|
304 | + } |
|
305 | + |
|
306 | + |
|
307 | + /** |
|
308 | + * Allows a message type to specifically exclude template fields for the provided messenger. |
|
309 | + * Filtered so this can be programmatically altered as well. |
|
310 | + * @param string $messenger_name name of messenger |
|
311 | + * @return array |
|
312 | + */ |
|
313 | + public function excludedFieldsForMessenger($messenger_name) |
|
314 | + { |
|
315 | + return apply_filters( |
|
316 | + 'FHEE__EE_Messages_Base__excludedFieldForMessenger', |
|
317 | + array(), |
|
318 | + $messenger_name, |
|
319 | + $this->name, |
|
320 | + $this |
|
321 | + ); |
|
322 | + } |
|
323 | 323 | } |
@@ -26,7 +26,7 @@ discard block |
||
26 | 26 | public function __construct() |
27 | 27 | { |
28 | 28 | // register tasks (and make sure only registered once). |
29 | - if (! has_action('FHEE__EEH_Activation__get_cron_tasks', array($this, 'register_scheduled_tasks'))) { |
|
29 | + if ( ! has_action('FHEE__EEH_Activation__get_cron_tasks', array($this, 'register_scheduled_tasks'))) { |
|
30 | 30 | add_action('FHEE__EEH_Activation__get_cron_tasks', array($this, 'register_scheduled_tasks'), 10); |
31 | 31 | } |
32 | 32 | |
@@ -77,7 +77,7 @@ discard block |
||
77 | 77 | EE_Registry::instance()->load_helper('DTT_Helper'); |
78 | 78 | $tasks['AHEE__EE_Messages_Scheduler__generation'] = 'ee_message_cron'; |
79 | 79 | $tasks['AHEE__EE_Messages_Scheduler__sending'] = 'ee_message_cron'; |
80 | - $tasks['AHEE__EE_Messages_Scheduler__cleanup'] = array( EEH_DTT_Helper::tomorrow(), 'daily'); |
|
80 | + $tasks['AHEE__EE_Messages_Scheduler__cleanup'] = array(EEH_DTT_Helper::tomorrow(), 'daily'); |
|
81 | 81 | return $tasks; |
82 | 82 | } |
83 | 83 | |
@@ -96,7 +96,7 @@ discard block |
||
96 | 96 | true |
97 | 97 | ) |
98 | 98 | ) { |
99 | - $request_url = add_query_arg( |
|
99 | + $request_url = add_query_arg( |
|
100 | 100 | array_merge( |
101 | 101 | array('ee' => 'msg_cron_trigger'), |
102 | 102 | EE_Messages_Scheduler::get_request_params($task) |
@@ -109,7 +109,7 @@ discard block |
||
109 | 109 | 'sslverify' => false, |
110 | 110 | 'redirection' => 10, |
111 | 111 | ); |
112 | - $response = wp_remote_get($request_url, $request_args); |
|
112 | + $response = wp_remote_get($request_url, $request_args); |
|
113 | 113 | if (is_wp_error($response)) { |
114 | 114 | trigger_error($response->get_error_message()); |
115 | 115 | } |
@@ -129,7 +129,7 @@ discard block |
||
129 | 129 | public static function get_request_params($task) |
130 | 130 | { |
131 | 131 | // transient is used for flood control on msg_cron_trigger requests |
132 | - $transient_key = 'ee_trans_' . uniqid($task); |
|
132 | + $transient_key = 'ee_trans_'.uniqid($task); |
|
133 | 133 | set_transient($transient_key, 1, 5 * MINUTE_IN_SECONDS); |
134 | 134 | return array( |
135 | 135 | 'type' => $task, |
@@ -202,7 +202,7 @@ discard block |
||
202 | 202 | 'AHEE__EE_Messages_Scheduler__sending' => 'ee_message_cron', |
203 | 203 | ); |
204 | 204 | foreach ($message_crons_to_check as $hook_name => $frequency) { |
205 | - if (! wp_next_scheduled($hook_name)) { |
|
205 | + if ( ! wp_next_scheduled($hook_name)) { |
|
206 | 206 | wp_schedule_event(time(), $frequency, $hook_name); |
207 | 207 | } |
208 | 208 | } |
@@ -13,225 +13,225 @@ |
||
13 | 13 | */ |
14 | 14 | class EE_Messages_Scheduler extends EE_Base |
15 | 15 | { |
16 | - /** |
|
17 | - * Number of seconds between batch sends/generates on the cron job. |
|
18 | - * Defaults to 5 minutes in seconds. If you want to change this interval, you can use the native WordPress |
|
19 | - * `cron_schedules` filter and modify the existing custom `ee_message_cron` schedule interval added. |
|
20 | - * |
|
21 | - * @type int |
|
22 | - */ |
|
23 | - const message_cron_schedule = 300; |
|
24 | - |
|
25 | - /** |
|
26 | - * Constructor |
|
27 | - */ |
|
28 | - public function __construct() |
|
29 | - { |
|
30 | - // register tasks (and make sure only registered once). |
|
31 | - if (! has_action('FHEE__EEH_Activation__get_cron_tasks', array($this, 'register_scheduled_tasks'))) { |
|
32 | - add_action('FHEE__EEH_Activation__get_cron_tasks', array($this, 'register_scheduled_tasks'), 10); |
|
33 | - } |
|
34 | - |
|
35 | - // register callbacks for scheduled events (but make sure they are set only once). |
|
36 | - if ( |
|
37 | - ! has_action( |
|
38 | - 'AHEE__EE_Messages_Scheduler__generation', |
|
39 | - array('EE_Messages_Scheduler', 'batch_generation') |
|
40 | - ) |
|
41 | - ) { |
|
42 | - add_action('AHEE__EE_Messages_Scheduler__generation', array('EE_Messages_Scheduler', 'batch_generation')); |
|
43 | - add_action('AHEE__EE_Messages_Scheduler__sending', array('EE_Messages_Scheduler', 'batch_sending')); |
|
44 | - add_action('AHEE__EE_Messages_Scheduler__cleanup', array('EE_Messages_Scheduler', 'cleanup')); |
|
45 | - } |
|
46 | - |
|
47 | - // add custom schedules |
|
48 | - add_filter('cron_schedules', array($this, 'custom_schedules')); |
|
49 | - } |
|
50 | - |
|
51 | - |
|
52 | - /** |
|
53 | - * Add custom schedules for wp_cron |
|
54 | - * |
|
55 | - * @param $schedules |
|
56 | - */ |
|
57 | - public function custom_schedules($schedules) |
|
58 | - { |
|
59 | - $schedules['ee_message_cron'] = array( |
|
60 | - 'interval' => self::message_cron_schedule, |
|
61 | - 'display' => esc_html__( |
|
62 | - 'This is the cron time interval for EE Message schedules (defaults to once every 5 minutes)', |
|
63 | - 'event_espresso' |
|
64 | - ), |
|
65 | - ); |
|
66 | - return $schedules; |
|
67 | - } |
|
68 | - |
|
69 | - |
|
70 | - /** |
|
71 | - * Callback for FHEE__EEH_Activation__get_cron_tasks that is used to retrieve scheduled Cron events to add and |
|
72 | - * remove. |
|
73 | - * |
|
74 | - * @param array $tasks already existing scheduled tasks |
|
75 | - * @return array |
|
76 | - * @throws EE_Error |
|
77 | - * @throws ReflectionException |
|
78 | - */ |
|
79 | - public function register_scheduled_tasks($tasks) |
|
80 | - { |
|
81 | - EE_Registry::instance()->load_helper('DTT_Helper'); |
|
82 | - $tasks['AHEE__EE_Messages_Scheduler__generation'] = 'ee_message_cron'; |
|
83 | - $tasks['AHEE__EE_Messages_Scheduler__sending'] = 'ee_message_cron'; |
|
84 | - $tasks['AHEE__EE_Messages_Scheduler__cleanup'] = array( EEH_DTT_Helper::tomorrow(), 'daily'); |
|
85 | - return $tasks; |
|
86 | - } |
|
87 | - |
|
88 | - |
|
89 | - /** |
|
90 | - * This initiates a non-blocking separate request to execute on a scheduled task. |
|
91 | - * Note: The EED_Messages module has the handlers for these requests. |
|
92 | - * |
|
93 | - * @param string $task The task the request is being generated for. |
|
94 | - */ |
|
95 | - public static function initiate_scheduled_non_blocking_request($task) |
|
96 | - { |
|
97 | - if ( |
|
98 | - apply_filters( |
|
99 | - 'EE_Messages_Scheduler__initiate_scheduled_non_blocking_request__do_separate_request', |
|
100 | - true |
|
101 | - ) |
|
102 | - ) { |
|
103 | - $request_url = add_query_arg( |
|
104 | - array_merge( |
|
105 | - array('ee' => 'msg_cron_trigger'), |
|
106 | - EE_Messages_Scheduler::get_request_params($task) |
|
107 | - ), |
|
108 | - site_url() |
|
109 | - ); |
|
110 | - $request_args = array( |
|
111 | - 'timeout' => 300, |
|
112 | - 'blocking' => (defined('DOING_CRON') && DOING_CRON) |
|
113 | - || (defined('DOING_AJAX') && DOING_AJAX), |
|
114 | - 'sslverify' => false, |
|
115 | - 'redirection' => 10, |
|
116 | - ); |
|
117 | - $response = wp_remote_get($request_url, $request_args); |
|
118 | - if (is_wp_error($response)) { |
|
119 | - trigger_error($response->get_error_message()); |
|
120 | - } |
|
121 | - } else { |
|
122 | - EE_Messages_Scheduler::initiate_immediate_request_on_cron($task); |
|
123 | - } |
|
124 | - } |
|
125 | - |
|
126 | - |
|
127 | - /** |
|
128 | - * This returns |
|
129 | - * the request params used for a scheduled message task request. |
|
130 | - * |
|
131 | - * @param string $task The task the request is for. |
|
132 | - * @return array |
|
133 | - */ |
|
134 | - public static function get_request_params($task) |
|
135 | - { |
|
136 | - // transient is used for flood control on msg_cron_trigger requests |
|
137 | - $transient_key = 'ee_trans_' . uniqid($task); |
|
138 | - set_transient($transient_key, 1, 5 * MINUTE_IN_SECONDS); |
|
139 | - return array( |
|
140 | - 'type' => $task, |
|
141 | - 'key' => $transient_key, |
|
142 | - ); |
|
143 | - } |
|
144 | - |
|
145 | - |
|
146 | - /** |
|
147 | - * This is used to execute an immediate call to the run_cron task performed by EED_Messages |
|
148 | - * |
|
149 | - * @param string $task The task the request is being generated for. |
|
150 | - */ |
|
151 | - public static function initiate_immediate_request_on_cron($task) |
|
152 | - { |
|
153 | - /** @var RequestInterface $request */ |
|
154 | - $request = LoaderFactory::getLoader()->getShared(RequestInterface::class); |
|
155 | - $request_args = EE_Messages_Scheduler::get_request_params($task); |
|
156 | - // set those request args in the request so it gets picked up |
|
157 | - foreach ($request_args as $request_key => $request_value) { |
|
158 | - $request->setRequestParam($request_key, $request_value); |
|
159 | - } |
|
160 | - EED_Messages::instance()->run_cron(); |
|
161 | - } |
|
162 | - |
|
163 | - |
|
164 | - /** |
|
165 | - * Callback for scheduled AHEE__EE_Messages_Scheduler__generation wp cron event |
|
166 | - */ |
|
167 | - public static function batch_generation() |
|
168 | - { |
|
169 | - /** |
|
170 | - * @see filter usage in EE_Messages_Queue::initiate_request_by_priority() |
|
171 | - */ |
|
172 | - if ( |
|
173 | - ! apply_filters('FHEE__EE_Messages_Processor__initiate_request_by_priority__do_immediate_processing', false) |
|
174 | - || ! EE_Registry::instance()->NET_CFG->core->do_messages_on_same_request |
|
175 | - ) { |
|
176 | - EE_Messages_Scheduler::initiate_immediate_request_on_cron('generate'); |
|
177 | - } |
|
178 | - } |
|
179 | - |
|
180 | - |
|
181 | - /** |
|
182 | - * Callback for scheduled AHEE__EE_Messages_Scheduler__sending |
|
183 | - */ |
|
184 | - public static function batch_sending() |
|
185 | - { |
|
186 | - /** |
|
187 | - * @see filter usage in EE_Messages_Queue::initiate_request_by_priority() |
|
188 | - */ |
|
189 | - if ( |
|
190 | - ! apply_filters('FHEE__EE_Messages_Processor__initiate_request_by_priority__do_immediate_processing', false) |
|
191 | - || ! EE_Registry::instance()->NET_CFG->core->do_messages_on_same_request |
|
192 | - ) { |
|
193 | - EE_Messages_Scheduler::initiate_immediate_request_on_cron('send'); |
|
194 | - } |
|
195 | - } |
|
196 | - |
|
197 | - |
|
198 | - /** |
|
199 | - * This is the callback for the `AHEE__EE_Messages_Scheduler__cleanup` scheduled event action. |
|
200 | - * This runs once a day and if cleanup is active (set via messages settings), it will (by default) delete |
|
201 | - * permanently from the database messages that have a MSG_modified date older than 30 days. |
|
202 | - * |
|
203 | - * @throws EE_Error |
|
204 | - * @throws EE_Error |
|
205 | - */ |
|
206 | - public static function cleanup() |
|
207 | - { |
|
208 | - // First, confirm that the generation and sending EE_Messages_Scheduler crons are |
|
209 | - // set and reschedule them if they are not. |
|
210 | - $message_crons_to_check = array( |
|
211 | - 'AHEE__EE_Messages_Scheduler__generation' => 'ee_message_cron', |
|
212 | - 'AHEE__EE_Messages_Scheduler__sending' => 'ee_message_cron', |
|
213 | - ); |
|
214 | - foreach ($message_crons_to_check as $hook_name => $frequency) { |
|
215 | - if (! wp_next_scheduled($hook_name)) { |
|
216 | - wp_schedule_event(time(), $frequency, $hook_name); |
|
217 | - } |
|
218 | - } |
|
219 | - |
|
220 | - // check if user has cleanup turned on or if we're in maintenance mode. If in maintenance mode we'll wait |
|
221 | - // until the next scheduled event. |
|
222 | - if ( |
|
223 | - ! EE_Registry::instance()->CFG->messages->delete_threshold |
|
224 | - || ! EE_Maintenance_Mode::instance()->models_can_query() |
|
225 | - ) { |
|
226 | - return; |
|
227 | - } |
|
228 | - |
|
229 | - /** |
|
230 | - * This filter switch allows other code (such as the EE_Worker_Queue add-on) to replace this with its own handling |
|
231 | - * of deleting messages. |
|
232 | - */ |
|
233 | - if (apply_filters('FHEE__EE_Messages_Scheduler__cleanup__handle_cleanup_on_cron', true)) { |
|
234 | - EEM_Message::instance()->delete_old_messages(EE_Registry::instance()->CFG->messages->delete_threshold); |
|
235 | - } |
|
236 | - } |
|
16 | + /** |
|
17 | + * Number of seconds between batch sends/generates on the cron job. |
|
18 | + * Defaults to 5 minutes in seconds. If you want to change this interval, you can use the native WordPress |
|
19 | + * `cron_schedules` filter and modify the existing custom `ee_message_cron` schedule interval added. |
|
20 | + * |
|
21 | + * @type int |
|
22 | + */ |
|
23 | + const message_cron_schedule = 300; |
|
24 | + |
|
25 | + /** |
|
26 | + * Constructor |
|
27 | + */ |
|
28 | + public function __construct() |
|
29 | + { |
|
30 | + // register tasks (and make sure only registered once). |
|
31 | + if (! has_action('FHEE__EEH_Activation__get_cron_tasks', array($this, 'register_scheduled_tasks'))) { |
|
32 | + add_action('FHEE__EEH_Activation__get_cron_tasks', array($this, 'register_scheduled_tasks'), 10); |
|
33 | + } |
|
34 | + |
|
35 | + // register callbacks for scheduled events (but make sure they are set only once). |
|
36 | + if ( |
|
37 | + ! has_action( |
|
38 | + 'AHEE__EE_Messages_Scheduler__generation', |
|
39 | + array('EE_Messages_Scheduler', 'batch_generation') |
|
40 | + ) |
|
41 | + ) { |
|
42 | + add_action('AHEE__EE_Messages_Scheduler__generation', array('EE_Messages_Scheduler', 'batch_generation')); |
|
43 | + add_action('AHEE__EE_Messages_Scheduler__sending', array('EE_Messages_Scheduler', 'batch_sending')); |
|
44 | + add_action('AHEE__EE_Messages_Scheduler__cleanup', array('EE_Messages_Scheduler', 'cleanup')); |
|
45 | + } |
|
46 | + |
|
47 | + // add custom schedules |
|
48 | + add_filter('cron_schedules', array($this, 'custom_schedules')); |
|
49 | + } |
|
50 | + |
|
51 | + |
|
52 | + /** |
|
53 | + * Add custom schedules for wp_cron |
|
54 | + * |
|
55 | + * @param $schedules |
|
56 | + */ |
|
57 | + public function custom_schedules($schedules) |
|
58 | + { |
|
59 | + $schedules['ee_message_cron'] = array( |
|
60 | + 'interval' => self::message_cron_schedule, |
|
61 | + 'display' => esc_html__( |
|
62 | + 'This is the cron time interval for EE Message schedules (defaults to once every 5 minutes)', |
|
63 | + 'event_espresso' |
|
64 | + ), |
|
65 | + ); |
|
66 | + return $schedules; |
|
67 | + } |
|
68 | + |
|
69 | + |
|
70 | + /** |
|
71 | + * Callback for FHEE__EEH_Activation__get_cron_tasks that is used to retrieve scheduled Cron events to add and |
|
72 | + * remove. |
|
73 | + * |
|
74 | + * @param array $tasks already existing scheduled tasks |
|
75 | + * @return array |
|
76 | + * @throws EE_Error |
|
77 | + * @throws ReflectionException |
|
78 | + */ |
|
79 | + public function register_scheduled_tasks($tasks) |
|
80 | + { |
|
81 | + EE_Registry::instance()->load_helper('DTT_Helper'); |
|
82 | + $tasks['AHEE__EE_Messages_Scheduler__generation'] = 'ee_message_cron'; |
|
83 | + $tasks['AHEE__EE_Messages_Scheduler__sending'] = 'ee_message_cron'; |
|
84 | + $tasks['AHEE__EE_Messages_Scheduler__cleanup'] = array( EEH_DTT_Helper::tomorrow(), 'daily'); |
|
85 | + return $tasks; |
|
86 | + } |
|
87 | + |
|
88 | + |
|
89 | + /** |
|
90 | + * This initiates a non-blocking separate request to execute on a scheduled task. |
|
91 | + * Note: The EED_Messages module has the handlers for these requests. |
|
92 | + * |
|
93 | + * @param string $task The task the request is being generated for. |
|
94 | + */ |
|
95 | + public static function initiate_scheduled_non_blocking_request($task) |
|
96 | + { |
|
97 | + if ( |
|
98 | + apply_filters( |
|
99 | + 'EE_Messages_Scheduler__initiate_scheduled_non_blocking_request__do_separate_request', |
|
100 | + true |
|
101 | + ) |
|
102 | + ) { |
|
103 | + $request_url = add_query_arg( |
|
104 | + array_merge( |
|
105 | + array('ee' => 'msg_cron_trigger'), |
|
106 | + EE_Messages_Scheduler::get_request_params($task) |
|
107 | + ), |
|
108 | + site_url() |
|
109 | + ); |
|
110 | + $request_args = array( |
|
111 | + 'timeout' => 300, |
|
112 | + 'blocking' => (defined('DOING_CRON') && DOING_CRON) |
|
113 | + || (defined('DOING_AJAX') && DOING_AJAX), |
|
114 | + 'sslverify' => false, |
|
115 | + 'redirection' => 10, |
|
116 | + ); |
|
117 | + $response = wp_remote_get($request_url, $request_args); |
|
118 | + if (is_wp_error($response)) { |
|
119 | + trigger_error($response->get_error_message()); |
|
120 | + } |
|
121 | + } else { |
|
122 | + EE_Messages_Scheduler::initiate_immediate_request_on_cron($task); |
|
123 | + } |
|
124 | + } |
|
125 | + |
|
126 | + |
|
127 | + /** |
|
128 | + * This returns |
|
129 | + * the request params used for a scheduled message task request. |
|
130 | + * |
|
131 | + * @param string $task The task the request is for. |
|
132 | + * @return array |
|
133 | + */ |
|
134 | + public static function get_request_params($task) |
|
135 | + { |
|
136 | + // transient is used for flood control on msg_cron_trigger requests |
|
137 | + $transient_key = 'ee_trans_' . uniqid($task); |
|
138 | + set_transient($transient_key, 1, 5 * MINUTE_IN_SECONDS); |
|
139 | + return array( |
|
140 | + 'type' => $task, |
|
141 | + 'key' => $transient_key, |
|
142 | + ); |
|
143 | + } |
|
144 | + |
|
145 | + |
|
146 | + /** |
|
147 | + * This is used to execute an immediate call to the run_cron task performed by EED_Messages |
|
148 | + * |
|
149 | + * @param string $task The task the request is being generated for. |
|
150 | + */ |
|
151 | + public static function initiate_immediate_request_on_cron($task) |
|
152 | + { |
|
153 | + /** @var RequestInterface $request */ |
|
154 | + $request = LoaderFactory::getLoader()->getShared(RequestInterface::class); |
|
155 | + $request_args = EE_Messages_Scheduler::get_request_params($task); |
|
156 | + // set those request args in the request so it gets picked up |
|
157 | + foreach ($request_args as $request_key => $request_value) { |
|
158 | + $request->setRequestParam($request_key, $request_value); |
|
159 | + } |
|
160 | + EED_Messages::instance()->run_cron(); |
|
161 | + } |
|
162 | + |
|
163 | + |
|
164 | + /** |
|
165 | + * Callback for scheduled AHEE__EE_Messages_Scheduler__generation wp cron event |
|
166 | + */ |
|
167 | + public static function batch_generation() |
|
168 | + { |
|
169 | + /** |
|
170 | + * @see filter usage in EE_Messages_Queue::initiate_request_by_priority() |
|
171 | + */ |
|
172 | + if ( |
|
173 | + ! apply_filters('FHEE__EE_Messages_Processor__initiate_request_by_priority__do_immediate_processing', false) |
|
174 | + || ! EE_Registry::instance()->NET_CFG->core->do_messages_on_same_request |
|
175 | + ) { |
|
176 | + EE_Messages_Scheduler::initiate_immediate_request_on_cron('generate'); |
|
177 | + } |
|
178 | + } |
|
179 | + |
|
180 | + |
|
181 | + /** |
|
182 | + * Callback for scheduled AHEE__EE_Messages_Scheduler__sending |
|
183 | + */ |
|
184 | + public static function batch_sending() |
|
185 | + { |
|
186 | + /** |
|
187 | + * @see filter usage in EE_Messages_Queue::initiate_request_by_priority() |
|
188 | + */ |
|
189 | + if ( |
|
190 | + ! apply_filters('FHEE__EE_Messages_Processor__initiate_request_by_priority__do_immediate_processing', false) |
|
191 | + || ! EE_Registry::instance()->NET_CFG->core->do_messages_on_same_request |
|
192 | + ) { |
|
193 | + EE_Messages_Scheduler::initiate_immediate_request_on_cron('send'); |
|
194 | + } |
|
195 | + } |
|
196 | + |
|
197 | + |
|
198 | + /** |
|
199 | + * This is the callback for the `AHEE__EE_Messages_Scheduler__cleanup` scheduled event action. |
|
200 | + * This runs once a day and if cleanup is active (set via messages settings), it will (by default) delete |
|
201 | + * permanently from the database messages that have a MSG_modified date older than 30 days. |
|
202 | + * |
|
203 | + * @throws EE_Error |
|
204 | + * @throws EE_Error |
|
205 | + */ |
|
206 | + public static function cleanup() |
|
207 | + { |
|
208 | + // First, confirm that the generation and sending EE_Messages_Scheduler crons are |
|
209 | + // set and reschedule them if they are not. |
|
210 | + $message_crons_to_check = array( |
|
211 | + 'AHEE__EE_Messages_Scheduler__generation' => 'ee_message_cron', |
|
212 | + 'AHEE__EE_Messages_Scheduler__sending' => 'ee_message_cron', |
|
213 | + ); |
|
214 | + foreach ($message_crons_to_check as $hook_name => $frequency) { |
|
215 | + if (! wp_next_scheduled($hook_name)) { |
|
216 | + wp_schedule_event(time(), $frequency, $hook_name); |
|
217 | + } |
|
218 | + } |
|
219 | + |
|
220 | + // check if user has cleanup turned on or if we're in maintenance mode. If in maintenance mode we'll wait |
|
221 | + // until the next scheduled event. |
|
222 | + if ( |
|
223 | + ! EE_Registry::instance()->CFG->messages->delete_threshold |
|
224 | + || ! EE_Maintenance_Mode::instance()->models_can_query() |
|
225 | + ) { |
|
226 | + return; |
|
227 | + } |
|
228 | + |
|
229 | + /** |
|
230 | + * This filter switch allows other code (such as the EE_Worker_Queue add-on) to replace this with its own handling |
|
231 | + * of deleting messages. |
|
232 | + */ |
|
233 | + if (apply_filters('FHEE__EE_Messages_Scheduler__cleanup__handle_cleanup_on_cron', true)) { |
|
234 | + EEM_Message::instance()->delete_old_messages(EE_Registry::instance()->CFG->messages->delete_threshold); |
|
235 | + } |
|
236 | + } |
|
237 | 237 | } |
@@ -332,7 +332,7 @@ discard block |
||
332 | 332 | $answers = $questions = $attendees = $line_items = $registrations = array(); |
333 | 333 | $total_ticket_count = 0; |
334 | 334 | |
335 | - if (! empty($this->reg_objs)) { |
|
335 | + if ( ! empty($this->reg_objs)) { |
|
336 | 336 | $event_attendee_count = array(); |
337 | 337 | /** @var EE_Registration $reg */ |
338 | 338 | foreach ($this->reg_objs as $reg) { |
@@ -344,7 +344,7 @@ discard block |
||
344 | 344 | |
345 | 345 | $evt_id = $reg->event_ID(); |
346 | 346 | /** @type EE_Ticket $ticket */ |
347 | - $ticket = $reg->get_first_related('Ticket'); |
|
347 | + $ticket = $reg->get_first_related('Ticket'); |
|
348 | 348 | $attendee = $reg->attendee(); |
349 | 349 | $event = $reg->event(); |
350 | 350 | // if none of the following entities are available, then we can't setup other data reliably, |
@@ -358,67 +358,67 @@ discard block |
||
358 | 358 | } |
359 | 359 | $relateddatetime = $ticket->datetimes(); |
360 | 360 | $total_ticket_count++; |
361 | - $tickets[ $ticket->ID() ]['ticket'] = $ticket; |
|
362 | - $tickets[ $ticket->ID() ]['count'] = is_array($tickets[ $ticket->ID() ]) |
|
363 | - && isset($tickets[ $ticket->ID() ]['count']) |
|
364 | - ? $tickets[ $ticket->ID() ]['count'] + 1 |
|
361 | + $tickets[$ticket->ID()]['ticket'] = $ticket; |
|
362 | + $tickets[$ticket->ID()]['count'] = is_array($tickets[$ticket->ID()]) |
|
363 | + && isset($tickets[$ticket->ID()]['count']) |
|
364 | + ? $tickets[$ticket->ID()]['count'] + 1 |
|
365 | 365 | : 1; |
366 | - $tickets[ $ticket->ID() ]['att_objs'][ $attendee->ID() ] = $attendee; |
|
367 | - $tickets[ $ticket->ID() ]['dtt_objs'] = $relateddatetime; |
|
368 | - $tickets[ $ticket->ID() ]['reg_objs'][ $reg->ID() ] = $reg; |
|
369 | - $tickets[ $ticket->ID() ]['EE_Event'] = $event; |
|
370 | - $evtcache[ $evt_id ] = $event; |
|
371 | - $eventsetup[ $evt_id ]['reg_objs'][ $reg->ID() ] = $reg; |
|
372 | - $eventsetup[ $evt_id ]['tkt_objs'][ $ticket->ID() ] = $ticket; |
|
373 | - $eventsetup[ $evt_id ]['att_objs'][ $attendee->ID() ] = $attendee; |
|
374 | - $event_attendee_count[ $evt_id ] = isset($event_attendee_count[ $evt_id ]) |
|
375 | - ? $event_attendee_count[ $evt_id ] + 1 |
|
366 | + $tickets[$ticket->ID()]['att_objs'][$attendee->ID()] = $attendee; |
|
367 | + $tickets[$ticket->ID()]['dtt_objs'] = $relateddatetime; |
|
368 | + $tickets[$ticket->ID()]['reg_objs'][$reg->ID()] = $reg; |
|
369 | + $tickets[$ticket->ID()]['EE_Event'] = $event; |
|
370 | + $evtcache[$evt_id] = $event; |
|
371 | + $eventsetup[$evt_id]['reg_objs'][$reg->ID()] = $reg; |
|
372 | + $eventsetup[$evt_id]['tkt_objs'][$ticket->ID()] = $ticket; |
|
373 | + $eventsetup[$evt_id]['att_objs'][$attendee->ID()] = $attendee; |
|
374 | + $event_attendee_count[$evt_id] = isset($event_attendee_count[$evt_id]) |
|
375 | + ? $event_attendee_count[$evt_id] + 1 |
|
376 | 376 | : 0; |
377 | - $attendees[ $reg->attendee_ID() ]['line_ref'][] = $evt_id; |
|
378 | - $attendees[ $reg->attendee_ID() ]['att_obj'] = $attendee; |
|
379 | - $attendees[ $reg->attendee_ID() ]['reg_objs'][ $reg->ID() ] = $reg; |
|
377 | + $attendees[$reg->attendee_ID()]['line_ref'][] = $evt_id; |
|
378 | + $attendees[$reg->attendee_ID()]['att_obj'] = $attendee; |
|
379 | + $attendees[$reg->attendee_ID()]['reg_objs'][$reg->ID()] = $reg; |
|
380 | 380 | // $attendees[ $reg->attendee_ID() ]['registration_id'] = $reg->ID(); |
381 | - $attendees[ $reg->attendee_ID() ]['attendee_email'] = $attendee->email(); |
|
382 | - $attendees[ $reg->attendee_ID() ]['tkt_objs'][ $ticket->ID() ] = $ticket; |
|
383 | - $attendees[ $reg->attendee_ID() ]['evt_objs'][ $evt_id ] = $event; |
|
381 | + $attendees[$reg->attendee_ID()]['attendee_email'] = $attendee->email(); |
|
382 | + $attendees[$reg->attendee_ID()]['tkt_objs'][$ticket->ID()] = $ticket; |
|
383 | + $attendees[$reg->attendee_ID()]['evt_objs'][$evt_id] = $event; |
|
384 | 384 | |
385 | 385 | // registrations |
386 | - $registrations[ $reg->ID() ]['tkt_obj'] = $ticket; |
|
387 | - $registrations[ $reg->ID() ]['evt_obj'] = $event; |
|
388 | - $registrations[ $reg->ID() ]['reg_obj'] = $reg; |
|
389 | - $registrations[ $reg->ID() ]['att_obj'] = $attendee; |
|
386 | + $registrations[$reg->ID()]['tkt_obj'] = $ticket; |
|
387 | + $registrations[$reg->ID()]['evt_obj'] = $event; |
|
388 | + $registrations[$reg->ID()]['reg_obj'] = $reg; |
|
389 | + $registrations[$reg->ID()]['att_obj'] = $attendee; |
|
390 | 390 | |
391 | 391 | // set up answer objects |
392 | 392 | $rel_ans = $reg->get_many_related('Answer'); |
393 | 393 | foreach ($rel_ans as $ansid => $answer) { |
394 | - if (! isset($questions[ $ansid ])) { |
|
395 | - $questions[ $ansid ] = $answer->get_first_related('Question'); |
|
394 | + if ( ! isset($questions[$ansid])) { |
|
395 | + $questions[$ansid] = $answer->get_first_related('Question'); |
|
396 | 396 | } |
397 | - $answers[ $ansid ] = $answer; |
|
398 | - $registrations[ $reg->ID() ]['ans_objs'][ $ansid ] = $answer; |
|
397 | + $answers[$ansid] = $answer; |
|
398 | + $registrations[$reg->ID()]['ans_objs'][$ansid] = $answer; |
|
399 | 399 | } |
400 | 400 | /** |
401 | 401 | * @var int $dtt_id |
402 | 402 | * @var EE_Datetime $datetime |
403 | 403 | */ |
404 | 404 | foreach ($relateddatetime as $dtt_id => $datetime) { |
405 | - $eventsetup[ $evt_id ]['dtt_objs'][ $dtt_id ] = $datetime; |
|
406 | - $registrations[ $reg->ID() ]['dtt_objs'][ $dtt_id ] = $datetime; |
|
405 | + $eventsetup[$evt_id]['dtt_objs'][$dtt_id] = $datetime; |
|
406 | + $registrations[$reg->ID()]['dtt_objs'][$dtt_id] = $datetime; |
|
407 | 407 | |
408 | - if (isset($datetimes[ $dtt_id ])) { |
|
408 | + if (isset($datetimes[$dtt_id])) { |
|
409 | 409 | continue; // already have this info in the datetimes array. |
410 | 410 | } |
411 | 411 | |
412 | - $datetimes[ $dtt_id ]['tkt_objs'][] = $ticket; |
|
413 | - $datetimes[ $dtt_id ]['datetime'] = $datetime; |
|
414 | - $datetimes[ $dtt_id ]['evt_objs'][ $evt_id ] = $event; |
|
415 | - $datetimes[ $dtt_id ]['reg_objs'][ $reg->ID() ] = $reg; |
|
412 | + $datetimes[$dtt_id]['tkt_objs'][] = $ticket; |
|
413 | + $datetimes[$dtt_id]['datetime'] = $datetime; |
|
414 | + $datetimes[$dtt_id]['evt_objs'][$evt_id] = $event; |
|
415 | + $datetimes[$dtt_id]['reg_objs'][$reg->ID()] = $reg; |
|
416 | 416 | } |
417 | 417 | } |
418 | 418 | |
419 | 419 | // let's loop through the unique event=>reg items and setup data on them |
420 | 420 | |
421 | - if (! empty($eventsetup)) { |
|
421 | + if ( ! empty($eventsetup)) { |
|
422 | 422 | foreach ($eventsetup as $evt_id => $items) { |
423 | 423 | $ticket_line_items_for_event = array(); |
424 | 424 | if ($this->txn instanceof EE_Transaction) { |
@@ -432,11 +432,11 @@ discard block |
||
432 | 432 | ) |
433 | 433 | ); |
434 | 434 | } |
435 | - $events[ $evt_id ] = array( |
|
435 | + $events[$evt_id] = array( |
|
436 | 436 | 'ID' => $evt_id, |
437 | - 'event' => $evtcache[ $evt_id ], |
|
438 | - 'name' => $evtcache[ $evt_id ] instanceof EE_Event ? $evtcache[ $evt_id ]->name() : '', |
|
439 | - 'total_attendees' => $event_attendee_count[ $evt_id ], |
|
437 | + 'event' => $evtcache[$evt_id], |
|
438 | + 'name' => $evtcache[$evt_id] instanceof EE_Event ? $evtcache[$evt_id]->name() : '', |
|
439 | + 'total_attendees' => $event_attendee_count[$evt_id], |
|
440 | 440 | 'reg_objs' => $items['reg_objs'], |
441 | 441 | 'tkt_objs' => $items['tkt_objs'], |
442 | 442 | 'att_objs' => $items['att_objs'], |
@@ -447,11 +447,11 @@ discard block |
||
447 | 447 | // make sure the tickets have the line items setup for them. |
448 | 448 | foreach ($ticket_line_items_for_event as $line_id => $line_item) { |
449 | 449 | // only add the ticket line items if we already have this ticket in the $tickets array. |
450 | - if ($line_item instanceof EE_Line_Item && isset($tickets[ $line_item->ticket()->ID() ])) { |
|
451 | - $tickets[ $line_item->ticket()->ID() ]['line_item'] = $line_item; |
|
452 | - $tickets[ $line_item->ticket()->ID() ]['sub_line_items'] = $line_item->children(); |
|
453 | - $line_items[ $line_item->ID() ]['children'] = $line_item->children(); |
|
454 | - $line_items[ $line_item->ID() ]['EE_Ticket'] = $line_item->ticket(); |
|
450 | + if ($line_item instanceof EE_Line_Item && isset($tickets[$line_item->ticket()->ID()])) { |
|
451 | + $tickets[$line_item->ticket()->ID()]['line_item'] = $line_item; |
|
452 | + $tickets[$line_item->ticket()->ID()]['sub_line_items'] = $line_item->children(); |
|
453 | + $line_items[$line_item->ID()]['children'] = $line_item->children(); |
|
454 | + $line_items[$line_item->ID()]['EE_Ticket'] = $line_item->ticket(); |
|
455 | 455 | } |
456 | 456 | } |
457 | 457 | } |
@@ -16,522 +16,522 @@ |
||
16 | 16 | */ |
17 | 17 | abstract class EE_Messages_incoming_data |
18 | 18 | { |
19 | - /** |
|
20 | - * user id for logged in user when data collected |
|
21 | - * |
|
22 | - * @var string $user_id |
|
23 | - */ |
|
24 | - public $user_id; |
|
25 | - |
|
26 | - /** |
|
27 | - * IP Address of browser used |
|
28 | - * |
|
29 | - * @var string $ip_address |
|
30 | - */ |
|
31 | - public $ip_address; |
|
32 | - |
|
33 | - /** |
|
34 | - * browser |
|
35 | - * |
|
36 | - * @var string $user_agent |
|
37 | - */ |
|
38 | - public $user_agent; |
|
39 | - |
|
40 | - /** |
|
41 | - * Unix timestamp |
|
42 | - * |
|
43 | - * @var string $init_access |
|
44 | - */ |
|
45 | - public $init_access; |
|
46 | - |
|
47 | - /** |
|
48 | - * Unix timestamp |
|
49 | - * |
|
50 | - * @var string $last_access |
|
51 | - */ |
|
52 | - public $last_access; |
|
53 | - |
|
54 | - /** |
|
55 | - * The registrations details from the cart |
|
56 | - * |
|
57 | - * @var array $reg_info |
|
58 | - */ |
|
59 | - public $reg_info; |
|
60 | - |
|
61 | - /** |
|
62 | - * Some data handlers can set what reg status all the registrations are filtered by. |
|
63 | - * The status should match a EEM_Registration status constant. |
|
64 | - * |
|
65 | - * @var string $filtered_reg_status |
|
66 | - */ |
|
67 | - public $filtered_reg_status; |
|
68 | - |
|
69 | - /** |
|
70 | - * will hold an array of events assembled from $reg_info |
|
71 | - * |
|
72 | - * @var EE_Event[] $events |
|
73 | - */ |
|
74 | - public $events; |
|
75 | - |
|
76 | - /** |
|
77 | - * holds an array of datetimes assembled from the incoming data. |
|
78 | - * |
|
79 | - * @var EE_Datetime[] $datetimes |
|
80 | - */ |
|
81 | - public $datetimes; |
|
82 | - |
|
83 | - /** |
|
84 | - * holds an array of tickets assembled from the incoming data. |
|
85 | - * |
|
86 | - * @var EE_Ticket[] $tickets |
|
87 | - */ |
|
88 | - public $tickets; |
|
89 | - |
|
90 | - /** |
|
91 | - * holds an array with a key of parent line item and values are an array of children of that line item. |
|
92 | - * |
|
93 | - * @since 4.5.0 |
|
94 | - * @var EE_Line_Item[] $line_items_with_children |
|
95 | - */ |
|
96 | - public $line_items_with_children; |
|
97 | - |
|
98 | - /** |
|
99 | - * will hold an array of attendees assembled from the $reg_info |
|
100 | - * |
|
101 | - * @var EE_Attendee[] $attendees |
|
102 | - */ |
|
103 | - public $attendees; |
|
104 | - |
|
105 | - /** |
|
106 | - * will hold an array of cached registration objects and info assembled from reg_info |
|
107 | - * |
|
108 | - * @var array $registrations |
|
109 | - */ |
|
110 | - public $registrations; |
|
111 | - |
|
112 | - /** |
|
113 | - * will hold an array of answers assembled from the $reg_info |
|
114 | - * |
|
115 | - * @var EE_Answer[] $answers |
|
116 | - */ |
|
117 | - public $answers; |
|
118 | - |
|
119 | - /** |
|
120 | - * will hold an array of questions assembled from the $reg_info (indexed by Answer ID); |
|
121 | - * |
|
122 | - * @var EE_Question[] $questions |
|
123 | - */ |
|
124 | - public $questions; |
|
125 | - |
|
126 | - /** |
|
127 | - * Will hold billing data assembled from $billing_info (if present) |
|
128 | - * |
|
129 | - * @var mixed (array|null) $billing |
|
130 | - */ |
|
131 | - public $billing; |
|
132 | - |
|
133 | - /** |
|
134 | - * The total amount of tax for the transaction |
|
135 | - * |
|
136 | - * @var float $taxes |
|
137 | - */ |
|
138 | - public $taxes; |
|
139 | - |
|
140 | - /** |
|
141 | - * Holds the line items related to taxes |
|
142 | - * |
|
143 | - * @since 4.5.0 |
|
144 | - * @var EE_Line_Item[] $tax_line_items |
|
145 | - */ |
|
146 | - public $tax_line_items; |
|
147 | - |
|
148 | - /** |
|
149 | - * Hold the line items which aren't taxes and don't relate |
|
150 | - * to tickets. So: promotions and miscellaneous charges |
|
151 | - * |
|
152 | - * @since 4.5 |
|
153 | - * @var EE_Line_Item[] $additional_line_items |
|
154 | - */ |
|
155 | - public $additional_line_items; |
|
156 | - |
|
157 | - /** |
|
158 | - * Holds the grand total EE_Line_Item |
|
159 | - * |
|
160 | - * @var EE_Line_Item $grand_total_line_item |
|
161 | - */ |
|
162 | - public $grand_total_line_item; |
|
163 | - |
|
164 | - /** |
|
165 | - * holds the grand total price object |
|
166 | - * currently not used. |
|
167 | - * |
|
168 | - * @var null $grand_total_price_object |
|
169 | - */ |
|
170 | - public $grand_total_price_object; |
|
171 | - |
|
172 | - /** |
|
173 | - * total number of tickets |
|
174 | - * |
|
175 | - * @var int $total_ticket_count |
|
176 | - */ |
|
177 | - public $total_ticket_count; |
|
178 | - |
|
179 | - /** |
|
180 | - * Will hold the final transaction object (EE_Transaction) |
|
181 | - * |
|
182 | - * @var EE_Transaction $txn |
|
183 | - */ |
|
184 | - public $txn; |
|
185 | - |
|
186 | - /** |
|
187 | - * Holds the payments related to a transaction |
|
188 | - * |
|
189 | - * @since 4.5.0 |
|
190 | - * @var EE_Payment[] $payments |
|
191 | - */ |
|
192 | - public $payments; |
|
193 | - |
|
194 | - /** |
|
195 | - * Holds the first related payment related for a transaction |
|
196 | - * |
|
197 | - * @since 4.5.0 |
|
198 | - * @var EE_Payment $payment |
|
199 | - */ |
|
200 | - public $payment; |
|
201 | - |
|
202 | - /** |
|
203 | - * Will hold the label for the txn status |
|
204 | - * |
|
205 | - * @var string $txn_status |
|
206 | - */ |
|
207 | - public $txn_status; |
|
208 | - |
|
209 | - /** |
|
210 | - * Will hold the final registration object (EE_Registration) |
|
211 | - * |
|
212 | - * @var EE_Registration[] $reg_objs |
|
213 | - */ |
|
214 | - public $reg_objs; |
|
215 | - |
|
216 | - /** |
|
217 | - * Will hold an array of primary attendee data (if present) |
|
218 | - * |
|
219 | - * @var array $primary_attendee_data |
|
220 | - */ |
|
221 | - public $primary_attendee_data; |
|
222 | - |
|
223 | - /** |
|
224 | - * This is just an internal object used for passing around the incoming data. |
|
225 | - * |
|
226 | - * @var mixed $_data |
|
227 | - */ |
|
228 | - protected $_data; |
|
229 | - |
|
230 | - /** |
|
231 | - * This is just an internal object used for passing around the incoming data. |
|
232 | - * |
|
233 | - * @var mixed $incoming_data |
|
234 | - */ |
|
235 | - public $incoming_data; |
|
236 | - |
|
237 | - /** |
|
238 | - * hold objects that might be created |
|
239 | - * |
|
240 | - * @type EE_Registration $reg_obj |
|
241 | - */ |
|
242 | - public $reg_obj; |
|
243 | - |
|
244 | - |
|
245 | - /** |
|
246 | - * constructor |
|
247 | - * |
|
248 | - * @param mixed $data incoming data object|array. Suggested that child classes use type hinting for expected |
|
249 | - * data object. But here parent will be generic because we don't know what's coming in. |
|
250 | - */ |
|
251 | - public function __construct($data) |
|
252 | - { |
|
253 | - $this->_data = $data; |
|
254 | - $this->_setup_data(); |
|
255 | - } |
|
256 | - |
|
257 | - |
|
258 | - /** |
|
259 | - * Every child class has to setup the data object ! |
|
260 | - * |
|
261 | - * @return void |
|
262 | - */ |
|
263 | - abstract protected function _setup_data(); |
|
264 | - |
|
265 | - |
|
266 | - /** |
|
267 | - * Returns database safe representation of the data later used to when instantiating this object. |
|
268 | - * |
|
269 | - * @param mixed $data The incoming data to be prepped. |
|
270 | - * @return mixed The prepped data for db |
|
271 | - */ |
|
272 | - public static function convert_data_for_persistent_storage($data) |
|
273 | - { |
|
274 | - return $data; |
|
275 | - } |
|
276 | - |
|
277 | - |
|
278 | - /** |
|
279 | - * Data that has been stored in persistent storage that was prepped by _convert_data_for_persistent_storage |
|
280 | - * can be sent into this method and converted back into the format used for instantiating with this data handler. |
|
281 | - * |
|
282 | - * @param $data |
|
283 | - * @return mixed |
|
284 | - */ |
|
285 | - public static function convert_data_from_persistent_storage($data) |
|
286 | - { |
|
287 | - return $data; |
|
288 | - } |
|
289 | - |
|
290 | - |
|
291 | - /** |
|
292 | - * only purpose is to return the data |
|
293 | - * |
|
294 | - * @access public |
|
295 | - * @return mixed the formatted data object! |
|
296 | - */ |
|
297 | - public function data() |
|
298 | - { |
|
299 | - return $this->_data; |
|
300 | - } |
|
301 | - |
|
302 | - |
|
303 | - /** |
|
304 | - * This helper method can be used by any incoming data handlers to setup the data correctly. All that is required |
|
305 | - * is that $this->reg_objs be set. |
|
306 | - * |
|
307 | - * @throws EE_Error |
|
308 | - * @throws InvalidDataTypeException |
|
309 | - * @throws InvalidInterfaceException |
|
310 | - * @throws InvalidArgumentException |
|
311 | - * @throws EntityNotFoundException |
|
312 | - */ |
|
313 | - protected function _assemble_data() |
|
314 | - { |
|
315 | - // verify that reg_objs is set |
|
316 | - if ( |
|
317 | - ! is_array($this->reg_objs) |
|
318 | - && ! reset($this->reg_objs) instanceof EE_Registration |
|
319 | - ) { |
|
320 | - throw new EE_Error( |
|
321 | - esc_html__( |
|
322 | - 'In order to assemble the data correctly, the "reg_objs" property must be an array of EE_Registration objects', |
|
323 | - 'event_espresso' |
|
324 | - ) |
|
325 | - ); |
|
326 | - } |
|
327 | - |
|
328 | - // get all attendee and events associated with the registrations in this transaction |
|
329 | - $events = $event_setup = $evtcache = $tickets = $datetimes = array(); |
|
330 | - $answers = $questions = $attendees = $line_items = $registrations = array(); |
|
331 | - $total_ticket_count = 0; |
|
332 | - |
|
333 | - if (! empty($this->reg_objs)) { |
|
334 | - $event_attendee_count = array(); |
|
335 | - /** @var EE_Registration $reg */ |
|
336 | - foreach ($this->reg_objs as $reg) { |
|
337 | - if ( |
|
338 | - $this->_skip_registration_for_processing($reg) |
|
339 | - ) { |
|
340 | - continue; |
|
341 | - } |
|
342 | - |
|
343 | - $evt_id = $reg->event_ID(); |
|
344 | - /** @type EE_Ticket $ticket */ |
|
345 | - $ticket = $reg->get_first_related('Ticket'); |
|
346 | - $attendee = $reg->attendee(); |
|
347 | - $event = $reg->event(); |
|
348 | - // if none of the following entities are available, then we can't setup other data reliably, |
|
349 | - // so let's just skip. |
|
350 | - if ( |
|
351 | - ! $ticket instanceof EE_Ticket |
|
352 | - || ! $attendee instanceof EE_Attendee |
|
353 | - || ! $event instanceof EE_Event |
|
354 | - ) { |
|
355 | - continue; |
|
356 | - } |
|
357 | - $relateddatetime = $ticket->datetimes(); |
|
358 | - $total_ticket_count++; |
|
359 | - $tickets[ $ticket->ID() ]['ticket'] = $ticket; |
|
360 | - $tickets[ $ticket->ID() ]['count'] = is_array($tickets[ $ticket->ID() ]) |
|
361 | - && isset($tickets[ $ticket->ID() ]['count']) |
|
362 | - ? $tickets[ $ticket->ID() ]['count'] + 1 |
|
363 | - : 1; |
|
364 | - $tickets[ $ticket->ID() ]['att_objs'][ $attendee->ID() ] = $attendee; |
|
365 | - $tickets[ $ticket->ID() ]['dtt_objs'] = $relateddatetime; |
|
366 | - $tickets[ $ticket->ID() ]['reg_objs'][ $reg->ID() ] = $reg; |
|
367 | - $tickets[ $ticket->ID() ]['EE_Event'] = $event; |
|
368 | - $evtcache[ $evt_id ] = $event; |
|
369 | - $eventsetup[ $evt_id ]['reg_objs'][ $reg->ID() ] = $reg; |
|
370 | - $eventsetup[ $evt_id ]['tkt_objs'][ $ticket->ID() ] = $ticket; |
|
371 | - $eventsetup[ $evt_id ]['att_objs'][ $attendee->ID() ] = $attendee; |
|
372 | - $event_attendee_count[ $evt_id ] = isset($event_attendee_count[ $evt_id ]) |
|
373 | - ? $event_attendee_count[ $evt_id ] + 1 |
|
374 | - : 0; |
|
375 | - $attendees[ $reg->attendee_ID() ]['line_ref'][] = $evt_id; |
|
376 | - $attendees[ $reg->attendee_ID() ]['att_obj'] = $attendee; |
|
377 | - $attendees[ $reg->attendee_ID() ]['reg_objs'][ $reg->ID() ] = $reg; |
|
378 | - // $attendees[ $reg->attendee_ID() ]['registration_id'] = $reg->ID(); |
|
379 | - $attendees[ $reg->attendee_ID() ]['attendee_email'] = $attendee->email(); |
|
380 | - $attendees[ $reg->attendee_ID() ]['tkt_objs'][ $ticket->ID() ] = $ticket; |
|
381 | - $attendees[ $reg->attendee_ID() ]['evt_objs'][ $evt_id ] = $event; |
|
382 | - |
|
383 | - // registrations |
|
384 | - $registrations[ $reg->ID() ]['tkt_obj'] = $ticket; |
|
385 | - $registrations[ $reg->ID() ]['evt_obj'] = $event; |
|
386 | - $registrations[ $reg->ID() ]['reg_obj'] = $reg; |
|
387 | - $registrations[ $reg->ID() ]['att_obj'] = $attendee; |
|
388 | - |
|
389 | - // set up answer objects |
|
390 | - $rel_ans = $reg->get_many_related('Answer'); |
|
391 | - foreach ($rel_ans as $ansid => $answer) { |
|
392 | - if (! isset($questions[ $ansid ])) { |
|
393 | - $questions[ $ansid ] = $answer->get_first_related('Question'); |
|
394 | - } |
|
395 | - $answers[ $ansid ] = $answer; |
|
396 | - $registrations[ $reg->ID() ]['ans_objs'][ $ansid ] = $answer; |
|
397 | - } |
|
398 | - /** |
|
399 | - * @var int $dtt_id |
|
400 | - * @var EE_Datetime $datetime |
|
401 | - */ |
|
402 | - foreach ($relateddatetime as $dtt_id => $datetime) { |
|
403 | - $eventsetup[ $evt_id ]['dtt_objs'][ $dtt_id ] = $datetime; |
|
404 | - $registrations[ $reg->ID() ]['dtt_objs'][ $dtt_id ] = $datetime; |
|
405 | - |
|
406 | - if (isset($datetimes[ $dtt_id ])) { |
|
407 | - continue; // already have this info in the datetimes array. |
|
408 | - } |
|
409 | - |
|
410 | - $datetimes[ $dtt_id ]['tkt_objs'][] = $ticket; |
|
411 | - $datetimes[ $dtt_id ]['datetime'] = $datetime; |
|
412 | - $datetimes[ $dtt_id ]['evt_objs'][ $evt_id ] = $event; |
|
413 | - $datetimes[ $dtt_id ]['reg_objs'][ $reg->ID() ] = $reg; |
|
414 | - } |
|
415 | - } |
|
416 | - |
|
417 | - // let's loop through the unique event=>reg items and setup data on them |
|
418 | - |
|
419 | - if (! empty($eventsetup)) { |
|
420 | - foreach ($eventsetup as $evt_id => $items) { |
|
421 | - $ticket_line_items_for_event = array(); |
|
422 | - if ($this->txn instanceof EE_Transaction) { |
|
423 | - $ticket_line_items_for_event = EEM_Line_Item::instance()->get_all( |
|
424 | - array( |
|
425 | - array( |
|
426 | - 'Ticket.Datetime.EVT_ID' => $evt_id, |
|
427 | - 'TXN_ID' => $this->txn->ID(), |
|
428 | - ), |
|
429 | - 'default_where_conditions' => 'none', |
|
430 | - ) |
|
431 | - ); |
|
432 | - } |
|
433 | - $events[ $evt_id ] = array( |
|
434 | - 'ID' => $evt_id, |
|
435 | - 'event' => $evtcache[ $evt_id ], |
|
436 | - 'name' => $evtcache[ $evt_id ] instanceof EE_Event ? $evtcache[ $evt_id ]->name() : '', |
|
437 | - 'total_attendees' => $event_attendee_count[ $evt_id ], |
|
438 | - 'reg_objs' => $items['reg_objs'], |
|
439 | - 'tkt_objs' => $items['tkt_objs'], |
|
440 | - 'att_objs' => $items['att_objs'], |
|
441 | - 'dtt_objs' => isset($items['dtt_objs']) ? $items['dtt_objs'] : array(), |
|
442 | - 'line_items' => $ticket_line_items_for_event, |
|
443 | - ); |
|
444 | - |
|
445 | - // make sure the tickets have the line items setup for them. |
|
446 | - foreach ($ticket_line_items_for_event as $line_id => $line_item) { |
|
447 | - // only add the ticket line items if we already have this ticket in the $tickets array. |
|
448 | - if ($line_item instanceof EE_Line_Item && isset($tickets[ $line_item->ticket()->ID() ])) { |
|
449 | - $tickets[ $line_item->ticket()->ID() ]['line_item'] = $line_item; |
|
450 | - $tickets[ $line_item->ticket()->ID() ]['sub_line_items'] = $line_item->children(); |
|
451 | - $line_items[ $line_item->ID() ]['children'] = $line_item->children(); |
|
452 | - $line_items[ $line_item->ID() ]['EE_Ticket'] = $line_item->ticket(); |
|
453 | - } |
|
454 | - } |
|
455 | - } |
|
456 | - } |
|
457 | - |
|
458 | - $this->grand_total_line_item = $this->txn instanceof EE_Transaction |
|
459 | - ? $this->txn->total_line_item() |
|
460 | - : null; |
|
461 | - } |
|
462 | - |
|
463 | - // lets set the attendees and events properties |
|
464 | - $this->attendees = $attendees; |
|
465 | - $this->events = $events; |
|
466 | - $this->tickets = $tickets; |
|
467 | - $this->line_items_with_children = $line_items; |
|
468 | - $this->datetimes = $datetimes; |
|
469 | - $this->questions = $questions; |
|
470 | - $this->answers = $answers; |
|
471 | - $this->total_ticket_count = $total_ticket_count; |
|
472 | - $this->registrations = $registrations; |
|
473 | - |
|
474 | - if ($this->txn instanceof EE_Transaction) { |
|
475 | - $this->tax_line_items = $this->txn->tax_items(); |
|
476 | - $this->additional_line_items = $this->txn->non_ticket_line_items(); |
|
477 | - $this->payments = $this->txn->payments(); |
|
478 | - |
|
479 | - // setup primary registration if we have a single transaction object to work with |
|
480 | - |
|
481 | - // let's get just the primary_attendee_data! First we get the primary registration object. |
|
482 | - $primary_reg = $this->txn->primary_registration(); |
|
483 | - // verify |
|
484 | - if ($primary_reg instanceof EE_Registration) { |
|
485 | - // get attendee object |
|
486 | - if ($primary_reg->attendee() instanceof EE_Attendee) { |
|
487 | - // now we can setup the primary_attendee_data array |
|
488 | - $this->primary_attendee_data = array( |
|
489 | - 'registration_id' => $primary_reg->ID(), |
|
490 | - 'att_obj' => $primary_reg->attendee(), |
|
491 | - 'reg_obj' => $primary_reg, |
|
492 | - 'primary_att_obj' => $primary_reg->attendee(), |
|
493 | - 'primary_reg_obj' => $primary_reg, |
|
494 | - ); |
|
495 | - } else { |
|
496 | - EE_Error::add_error( |
|
497 | - esc_html__( |
|
498 | - 'Incoming data does not have a valid Attendee object for the primary registrant.', |
|
499 | - 'event_espresso' |
|
500 | - ), |
|
501 | - __FILE__, |
|
502 | - __FUNCTION__, |
|
503 | - __LINE__ |
|
504 | - ); |
|
505 | - } |
|
506 | - } else { |
|
507 | - EE_Error::add_error( |
|
508 | - esc_html__( |
|
509 | - 'Incoming data does not have a valid Registration object for the primary registrant.', |
|
510 | - 'event_espresso' |
|
511 | - ), |
|
512 | - __FILE__, |
|
513 | - __FUNCTION__, |
|
514 | - __LINE__ |
|
515 | - ); |
|
516 | - } |
|
517 | - } |
|
518 | - } |
|
519 | - |
|
520 | - /** |
|
521 | - * This simply considers whether the given registration should be processed or not based on comparison with the |
|
522 | - * filtered_reg_status property. |
|
523 | - * |
|
524 | - * @param EE_Registration $registration |
|
525 | - * @return bool returning true means we DO want to skip processing. returning false means we DON'T want to skip |
|
526 | - * processing |
|
527 | - */ |
|
528 | - protected function _skip_registration_for_processing(EE_Registration $registration) |
|
529 | - { |
|
530 | - if (empty($this->filtered_reg_status)) { |
|
531 | - return false; |
|
532 | - } |
|
533 | - |
|
534 | - // if we made it here then we just compare the filtered_reg_status with the registration status and return that |
|
535 | - return $this->filtered_reg_status !== $registration->status_ID(); |
|
536 | - } |
|
19 | + /** |
|
20 | + * user id for logged in user when data collected |
|
21 | + * |
|
22 | + * @var string $user_id |
|
23 | + */ |
|
24 | + public $user_id; |
|
25 | + |
|
26 | + /** |
|
27 | + * IP Address of browser used |
|
28 | + * |
|
29 | + * @var string $ip_address |
|
30 | + */ |
|
31 | + public $ip_address; |
|
32 | + |
|
33 | + /** |
|
34 | + * browser |
|
35 | + * |
|
36 | + * @var string $user_agent |
|
37 | + */ |
|
38 | + public $user_agent; |
|
39 | + |
|
40 | + /** |
|
41 | + * Unix timestamp |
|
42 | + * |
|
43 | + * @var string $init_access |
|
44 | + */ |
|
45 | + public $init_access; |
|
46 | + |
|
47 | + /** |
|
48 | + * Unix timestamp |
|
49 | + * |
|
50 | + * @var string $last_access |
|
51 | + */ |
|
52 | + public $last_access; |
|
53 | + |
|
54 | + /** |
|
55 | + * The registrations details from the cart |
|
56 | + * |
|
57 | + * @var array $reg_info |
|
58 | + */ |
|
59 | + public $reg_info; |
|
60 | + |
|
61 | + /** |
|
62 | + * Some data handlers can set what reg status all the registrations are filtered by. |
|
63 | + * The status should match a EEM_Registration status constant. |
|
64 | + * |
|
65 | + * @var string $filtered_reg_status |
|
66 | + */ |
|
67 | + public $filtered_reg_status; |
|
68 | + |
|
69 | + /** |
|
70 | + * will hold an array of events assembled from $reg_info |
|
71 | + * |
|
72 | + * @var EE_Event[] $events |
|
73 | + */ |
|
74 | + public $events; |
|
75 | + |
|
76 | + /** |
|
77 | + * holds an array of datetimes assembled from the incoming data. |
|
78 | + * |
|
79 | + * @var EE_Datetime[] $datetimes |
|
80 | + */ |
|
81 | + public $datetimes; |
|
82 | + |
|
83 | + /** |
|
84 | + * holds an array of tickets assembled from the incoming data. |
|
85 | + * |
|
86 | + * @var EE_Ticket[] $tickets |
|
87 | + */ |
|
88 | + public $tickets; |
|
89 | + |
|
90 | + /** |
|
91 | + * holds an array with a key of parent line item and values are an array of children of that line item. |
|
92 | + * |
|
93 | + * @since 4.5.0 |
|
94 | + * @var EE_Line_Item[] $line_items_with_children |
|
95 | + */ |
|
96 | + public $line_items_with_children; |
|
97 | + |
|
98 | + /** |
|
99 | + * will hold an array of attendees assembled from the $reg_info |
|
100 | + * |
|
101 | + * @var EE_Attendee[] $attendees |
|
102 | + */ |
|
103 | + public $attendees; |
|
104 | + |
|
105 | + /** |
|
106 | + * will hold an array of cached registration objects and info assembled from reg_info |
|
107 | + * |
|
108 | + * @var array $registrations |
|
109 | + */ |
|
110 | + public $registrations; |
|
111 | + |
|
112 | + /** |
|
113 | + * will hold an array of answers assembled from the $reg_info |
|
114 | + * |
|
115 | + * @var EE_Answer[] $answers |
|
116 | + */ |
|
117 | + public $answers; |
|
118 | + |
|
119 | + /** |
|
120 | + * will hold an array of questions assembled from the $reg_info (indexed by Answer ID); |
|
121 | + * |
|
122 | + * @var EE_Question[] $questions |
|
123 | + */ |
|
124 | + public $questions; |
|
125 | + |
|
126 | + /** |
|
127 | + * Will hold billing data assembled from $billing_info (if present) |
|
128 | + * |
|
129 | + * @var mixed (array|null) $billing |
|
130 | + */ |
|
131 | + public $billing; |
|
132 | + |
|
133 | + /** |
|
134 | + * The total amount of tax for the transaction |
|
135 | + * |
|
136 | + * @var float $taxes |
|
137 | + */ |
|
138 | + public $taxes; |
|
139 | + |
|
140 | + /** |
|
141 | + * Holds the line items related to taxes |
|
142 | + * |
|
143 | + * @since 4.5.0 |
|
144 | + * @var EE_Line_Item[] $tax_line_items |
|
145 | + */ |
|
146 | + public $tax_line_items; |
|
147 | + |
|
148 | + /** |
|
149 | + * Hold the line items which aren't taxes and don't relate |
|
150 | + * to tickets. So: promotions and miscellaneous charges |
|
151 | + * |
|
152 | + * @since 4.5 |
|
153 | + * @var EE_Line_Item[] $additional_line_items |
|
154 | + */ |
|
155 | + public $additional_line_items; |
|
156 | + |
|
157 | + /** |
|
158 | + * Holds the grand total EE_Line_Item |
|
159 | + * |
|
160 | + * @var EE_Line_Item $grand_total_line_item |
|
161 | + */ |
|
162 | + public $grand_total_line_item; |
|
163 | + |
|
164 | + /** |
|
165 | + * holds the grand total price object |
|
166 | + * currently not used. |
|
167 | + * |
|
168 | + * @var null $grand_total_price_object |
|
169 | + */ |
|
170 | + public $grand_total_price_object; |
|
171 | + |
|
172 | + /** |
|
173 | + * total number of tickets |
|
174 | + * |
|
175 | + * @var int $total_ticket_count |
|
176 | + */ |
|
177 | + public $total_ticket_count; |
|
178 | + |
|
179 | + /** |
|
180 | + * Will hold the final transaction object (EE_Transaction) |
|
181 | + * |
|
182 | + * @var EE_Transaction $txn |
|
183 | + */ |
|
184 | + public $txn; |
|
185 | + |
|
186 | + /** |
|
187 | + * Holds the payments related to a transaction |
|
188 | + * |
|
189 | + * @since 4.5.0 |
|
190 | + * @var EE_Payment[] $payments |
|
191 | + */ |
|
192 | + public $payments; |
|
193 | + |
|
194 | + /** |
|
195 | + * Holds the first related payment related for a transaction |
|
196 | + * |
|
197 | + * @since 4.5.0 |
|
198 | + * @var EE_Payment $payment |
|
199 | + */ |
|
200 | + public $payment; |
|
201 | + |
|
202 | + /** |
|
203 | + * Will hold the label for the txn status |
|
204 | + * |
|
205 | + * @var string $txn_status |
|
206 | + */ |
|
207 | + public $txn_status; |
|
208 | + |
|
209 | + /** |
|
210 | + * Will hold the final registration object (EE_Registration) |
|
211 | + * |
|
212 | + * @var EE_Registration[] $reg_objs |
|
213 | + */ |
|
214 | + public $reg_objs; |
|
215 | + |
|
216 | + /** |
|
217 | + * Will hold an array of primary attendee data (if present) |
|
218 | + * |
|
219 | + * @var array $primary_attendee_data |
|
220 | + */ |
|
221 | + public $primary_attendee_data; |
|
222 | + |
|
223 | + /** |
|
224 | + * This is just an internal object used for passing around the incoming data. |
|
225 | + * |
|
226 | + * @var mixed $_data |
|
227 | + */ |
|
228 | + protected $_data; |
|
229 | + |
|
230 | + /** |
|
231 | + * This is just an internal object used for passing around the incoming data. |
|
232 | + * |
|
233 | + * @var mixed $incoming_data |
|
234 | + */ |
|
235 | + public $incoming_data; |
|
236 | + |
|
237 | + /** |
|
238 | + * hold objects that might be created |
|
239 | + * |
|
240 | + * @type EE_Registration $reg_obj |
|
241 | + */ |
|
242 | + public $reg_obj; |
|
243 | + |
|
244 | + |
|
245 | + /** |
|
246 | + * constructor |
|
247 | + * |
|
248 | + * @param mixed $data incoming data object|array. Suggested that child classes use type hinting for expected |
|
249 | + * data object. But here parent will be generic because we don't know what's coming in. |
|
250 | + */ |
|
251 | + public function __construct($data) |
|
252 | + { |
|
253 | + $this->_data = $data; |
|
254 | + $this->_setup_data(); |
|
255 | + } |
|
256 | + |
|
257 | + |
|
258 | + /** |
|
259 | + * Every child class has to setup the data object ! |
|
260 | + * |
|
261 | + * @return void |
|
262 | + */ |
|
263 | + abstract protected function _setup_data(); |
|
264 | + |
|
265 | + |
|
266 | + /** |
|
267 | + * Returns database safe representation of the data later used to when instantiating this object. |
|
268 | + * |
|
269 | + * @param mixed $data The incoming data to be prepped. |
|
270 | + * @return mixed The prepped data for db |
|
271 | + */ |
|
272 | + public static function convert_data_for_persistent_storage($data) |
|
273 | + { |
|
274 | + return $data; |
|
275 | + } |
|
276 | + |
|
277 | + |
|
278 | + /** |
|
279 | + * Data that has been stored in persistent storage that was prepped by _convert_data_for_persistent_storage |
|
280 | + * can be sent into this method and converted back into the format used for instantiating with this data handler. |
|
281 | + * |
|
282 | + * @param $data |
|
283 | + * @return mixed |
|
284 | + */ |
|
285 | + public static function convert_data_from_persistent_storage($data) |
|
286 | + { |
|
287 | + return $data; |
|
288 | + } |
|
289 | + |
|
290 | + |
|
291 | + /** |
|
292 | + * only purpose is to return the data |
|
293 | + * |
|
294 | + * @access public |
|
295 | + * @return mixed the formatted data object! |
|
296 | + */ |
|
297 | + public function data() |
|
298 | + { |
|
299 | + return $this->_data; |
|
300 | + } |
|
301 | + |
|
302 | + |
|
303 | + /** |
|
304 | + * This helper method can be used by any incoming data handlers to setup the data correctly. All that is required |
|
305 | + * is that $this->reg_objs be set. |
|
306 | + * |
|
307 | + * @throws EE_Error |
|
308 | + * @throws InvalidDataTypeException |
|
309 | + * @throws InvalidInterfaceException |
|
310 | + * @throws InvalidArgumentException |
|
311 | + * @throws EntityNotFoundException |
|
312 | + */ |
|
313 | + protected function _assemble_data() |
|
314 | + { |
|
315 | + // verify that reg_objs is set |
|
316 | + if ( |
|
317 | + ! is_array($this->reg_objs) |
|
318 | + && ! reset($this->reg_objs) instanceof EE_Registration |
|
319 | + ) { |
|
320 | + throw new EE_Error( |
|
321 | + esc_html__( |
|
322 | + 'In order to assemble the data correctly, the "reg_objs" property must be an array of EE_Registration objects', |
|
323 | + 'event_espresso' |
|
324 | + ) |
|
325 | + ); |
|
326 | + } |
|
327 | + |
|
328 | + // get all attendee and events associated with the registrations in this transaction |
|
329 | + $events = $event_setup = $evtcache = $tickets = $datetimes = array(); |
|
330 | + $answers = $questions = $attendees = $line_items = $registrations = array(); |
|
331 | + $total_ticket_count = 0; |
|
332 | + |
|
333 | + if (! empty($this->reg_objs)) { |
|
334 | + $event_attendee_count = array(); |
|
335 | + /** @var EE_Registration $reg */ |
|
336 | + foreach ($this->reg_objs as $reg) { |
|
337 | + if ( |
|
338 | + $this->_skip_registration_for_processing($reg) |
|
339 | + ) { |
|
340 | + continue; |
|
341 | + } |
|
342 | + |
|
343 | + $evt_id = $reg->event_ID(); |
|
344 | + /** @type EE_Ticket $ticket */ |
|
345 | + $ticket = $reg->get_first_related('Ticket'); |
|
346 | + $attendee = $reg->attendee(); |
|
347 | + $event = $reg->event(); |
|
348 | + // if none of the following entities are available, then we can't setup other data reliably, |
|
349 | + // so let's just skip. |
|
350 | + if ( |
|
351 | + ! $ticket instanceof EE_Ticket |
|
352 | + || ! $attendee instanceof EE_Attendee |
|
353 | + || ! $event instanceof EE_Event |
|
354 | + ) { |
|
355 | + continue; |
|
356 | + } |
|
357 | + $relateddatetime = $ticket->datetimes(); |
|
358 | + $total_ticket_count++; |
|
359 | + $tickets[ $ticket->ID() ]['ticket'] = $ticket; |
|
360 | + $tickets[ $ticket->ID() ]['count'] = is_array($tickets[ $ticket->ID() ]) |
|
361 | + && isset($tickets[ $ticket->ID() ]['count']) |
|
362 | + ? $tickets[ $ticket->ID() ]['count'] + 1 |
|
363 | + : 1; |
|
364 | + $tickets[ $ticket->ID() ]['att_objs'][ $attendee->ID() ] = $attendee; |
|
365 | + $tickets[ $ticket->ID() ]['dtt_objs'] = $relateddatetime; |
|
366 | + $tickets[ $ticket->ID() ]['reg_objs'][ $reg->ID() ] = $reg; |
|
367 | + $tickets[ $ticket->ID() ]['EE_Event'] = $event; |
|
368 | + $evtcache[ $evt_id ] = $event; |
|
369 | + $eventsetup[ $evt_id ]['reg_objs'][ $reg->ID() ] = $reg; |
|
370 | + $eventsetup[ $evt_id ]['tkt_objs'][ $ticket->ID() ] = $ticket; |
|
371 | + $eventsetup[ $evt_id ]['att_objs'][ $attendee->ID() ] = $attendee; |
|
372 | + $event_attendee_count[ $evt_id ] = isset($event_attendee_count[ $evt_id ]) |
|
373 | + ? $event_attendee_count[ $evt_id ] + 1 |
|
374 | + : 0; |
|
375 | + $attendees[ $reg->attendee_ID() ]['line_ref'][] = $evt_id; |
|
376 | + $attendees[ $reg->attendee_ID() ]['att_obj'] = $attendee; |
|
377 | + $attendees[ $reg->attendee_ID() ]['reg_objs'][ $reg->ID() ] = $reg; |
|
378 | + // $attendees[ $reg->attendee_ID() ]['registration_id'] = $reg->ID(); |
|
379 | + $attendees[ $reg->attendee_ID() ]['attendee_email'] = $attendee->email(); |
|
380 | + $attendees[ $reg->attendee_ID() ]['tkt_objs'][ $ticket->ID() ] = $ticket; |
|
381 | + $attendees[ $reg->attendee_ID() ]['evt_objs'][ $evt_id ] = $event; |
|
382 | + |
|
383 | + // registrations |
|
384 | + $registrations[ $reg->ID() ]['tkt_obj'] = $ticket; |
|
385 | + $registrations[ $reg->ID() ]['evt_obj'] = $event; |
|
386 | + $registrations[ $reg->ID() ]['reg_obj'] = $reg; |
|
387 | + $registrations[ $reg->ID() ]['att_obj'] = $attendee; |
|
388 | + |
|
389 | + // set up answer objects |
|
390 | + $rel_ans = $reg->get_many_related('Answer'); |
|
391 | + foreach ($rel_ans as $ansid => $answer) { |
|
392 | + if (! isset($questions[ $ansid ])) { |
|
393 | + $questions[ $ansid ] = $answer->get_first_related('Question'); |
|
394 | + } |
|
395 | + $answers[ $ansid ] = $answer; |
|
396 | + $registrations[ $reg->ID() ]['ans_objs'][ $ansid ] = $answer; |
|
397 | + } |
|
398 | + /** |
|
399 | + * @var int $dtt_id |
|
400 | + * @var EE_Datetime $datetime |
|
401 | + */ |
|
402 | + foreach ($relateddatetime as $dtt_id => $datetime) { |
|
403 | + $eventsetup[ $evt_id ]['dtt_objs'][ $dtt_id ] = $datetime; |
|
404 | + $registrations[ $reg->ID() ]['dtt_objs'][ $dtt_id ] = $datetime; |
|
405 | + |
|
406 | + if (isset($datetimes[ $dtt_id ])) { |
|
407 | + continue; // already have this info in the datetimes array. |
|
408 | + } |
|
409 | + |
|
410 | + $datetimes[ $dtt_id ]['tkt_objs'][] = $ticket; |
|
411 | + $datetimes[ $dtt_id ]['datetime'] = $datetime; |
|
412 | + $datetimes[ $dtt_id ]['evt_objs'][ $evt_id ] = $event; |
|
413 | + $datetimes[ $dtt_id ]['reg_objs'][ $reg->ID() ] = $reg; |
|
414 | + } |
|
415 | + } |
|
416 | + |
|
417 | + // let's loop through the unique event=>reg items and setup data on them |
|
418 | + |
|
419 | + if (! empty($eventsetup)) { |
|
420 | + foreach ($eventsetup as $evt_id => $items) { |
|
421 | + $ticket_line_items_for_event = array(); |
|
422 | + if ($this->txn instanceof EE_Transaction) { |
|
423 | + $ticket_line_items_for_event = EEM_Line_Item::instance()->get_all( |
|
424 | + array( |
|
425 | + array( |
|
426 | + 'Ticket.Datetime.EVT_ID' => $evt_id, |
|
427 | + 'TXN_ID' => $this->txn->ID(), |
|
428 | + ), |
|
429 | + 'default_where_conditions' => 'none', |
|
430 | + ) |
|
431 | + ); |
|
432 | + } |
|
433 | + $events[ $evt_id ] = array( |
|
434 | + 'ID' => $evt_id, |
|
435 | + 'event' => $evtcache[ $evt_id ], |
|
436 | + 'name' => $evtcache[ $evt_id ] instanceof EE_Event ? $evtcache[ $evt_id ]->name() : '', |
|
437 | + 'total_attendees' => $event_attendee_count[ $evt_id ], |
|
438 | + 'reg_objs' => $items['reg_objs'], |
|
439 | + 'tkt_objs' => $items['tkt_objs'], |
|
440 | + 'att_objs' => $items['att_objs'], |
|
441 | + 'dtt_objs' => isset($items['dtt_objs']) ? $items['dtt_objs'] : array(), |
|
442 | + 'line_items' => $ticket_line_items_for_event, |
|
443 | + ); |
|
444 | + |
|
445 | + // make sure the tickets have the line items setup for them. |
|
446 | + foreach ($ticket_line_items_for_event as $line_id => $line_item) { |
|
447 | + // only add the ticket line items if we already have this ticket in the $tickets array. |
|
448 | + if ($line_item instanceof EE_Line_Item && isset($tickets[ $line_item->ticket()->ID() ])) { |
|
449 | + $tickets[ $line_item->ticket()->ID() ]['line_item'] = $line_item; |
|
450 | + $tickets[ $line_item->ticket()->ID() ]['sub_line_items'] = $line_item->children(); |
|
451 | + $line_items[ $line_item->ID() ]['children'] = $line_item->children(); |
|
452 | + $line_items[ $line_item->ID() ]['EE_Ticket'] = $line_item->ticket(); |
|
453 | + } |
|
454 | + } |
|
455 | + } |
|
456 | + } |
|
457 | + |
|
458 | + $this->grand_total_line_item = $this->txn instanceof EE_Transaction |
|
459 | + ? $this->txn->total_line_item() |
|
460 | + : null; |
|
461 | + } |
|
462 | + |
|
463 | + // lets set the attendees and events properties |
|
464 | + $this->attendees = $attendees; |
|
465 | + $this->events = $events; |
|
466 | + $this->tickets = $tickets; |
|
467 | + $this->line_items_with_children = $line_items; |
|
468 | + $this->datetimes = $datetimes; |
|
469 | + $this->questions = $questions; |
|
470 | + $this->answers = $answers; |
|
471 | + $this->total_ticket_count = $total_ticket_count; |
|
472 | + $this->registrations = $registrations; |
|
473 | + |
|
474 | + if ($this->txn instanceof EE_Transaction) { |
|
475 | + $this->tax_line_items = $this->txn->tax_items(); |
|
476 | + $this->additional_line_items = $this->txn->non_ticket_line_items(); |
|
477 | + $this->payments = $this->txn->payments(); |
|
478 | + |
|
479 | + // setup primary registration if we have a single transaction object to work with |
|
480 | + |
|
481 | + // let's get just the primary_attendee_data! First we get the primary registration object. |
|
482 | + $primary_reg = $this->txn->primary_registration(); |
|
483 | + // verify |
|
484 | + if ($primary_reg instanceof EE_Registration) { |
|
485 | + // get attendee object |
|
486 | + if ($primary_reg->attendee() instanceof EE_Attendee) { |
|
487 | + // now we can setup the primary_attendee_data array |
|
488 | + $this->primary_attendee_data = array( |
|
489 | + 'registration_id' => $primary_reg->ID(), |
|
490 | + 'att_obj' => $primary_reg->attendee(), |
|
491 | + 'reg_obj' => $primary_reg, |
|
492 | + 'primary_att_obj' => $primary_reg->attendee(), |
|
493 | + 'primary_reg_obj' => $primary_reg, |
|
494 | + ); |
|
495 | + } else { |
|
496 | + EE_Error::add_error( |
|
497 | + esc_html__( |
|
498 | + 'Incoming data does not have a valid Attendee object for the primary registrant.', |
|
499 | + 'event_espresso' |
|
500 | + ), |
|
501 | + __FILE__, |
|
502 | + __FUNCTION__, |
|
503 | + __LINE__ |
|
504 | + ); |
|
505 | + } |
|
506 | + } else { |
|
507 | + EE_Error::add_error( |
|
508 | + esc_html__( |
|
509 | + 'Incoming data does not have a valid Registration object for the primary registrant.', |
|
510 | + 'event_espresso' |
|
511 | + ), |
|
512 | + __FILE__, |
|
513 | + __FUNCTION__, |
|
514 | + __LINE__ |
|
515 | + ); |
|
516 | + } |
|
517 | + } |
|
518 | + } |
|
519 | + |
|
520 | + /** |
|
521 | + * This simply considers whether the given registration should be processed or not based on comparison with the |
|
522 | + * filtered_reg_status property. |
|
523 | + * |
|
524 | + * @param EE_Registration $registration |
|
525 | + * @return bool returning true means we DO want to skip processing. returning false means we DON'T want to skip |
|
526 | + * processing |
|
527 | + */ |
|
528 | + protected function _skip_registration_for_processing(EE_Registration $registration) |
|
529 | + { |
|
530 | + if (empty($this->filtered_reg_status)) { |
|
531 | + return false; |
|
532 | + } |
|
533 | + |
|
534 | + // if we made it here then we just compare the filtered_reg_status with the registration status and return that |
|
535 | + return $this->filtered_reg_status !== $registration->status_ID(); |
|
536 | + } |
|
537 | 537 | } |
@@ -116,17 +116,17 @@ discard block |
||
116 | 116 | ? $this->_extra_data['data'] |
117 | 117 | : $this->_recipient; |
118 | 118 | |
119 | - if (! $this->_recipient instanceof EE_Messages_Addressee) { |
|
119 | + if ( ! $this->_recipient instanceof EE_Messages_Addressee) { |
|
120 | 120 | return ''; |
121 | 121 | } |
122 | 122 | |
123 | 123 | $attendee = $this->_recipient->att_obj; |
124 | - if (! $attendee instanceof EE_Attendee) { |
|
124 | + if ( ! $attendee instanceof EE_Attendee) { |
|
125 | 125 | return ''; |
126 | 126 | } |
127 | 127 | |
128 | - $this->_registrations_for_recipient = isset($this->_recipient->attendees[ $attendee->ID() ]['reg_objs']) |
|
129 | - ? $this->_recipient->attendees[ $attendee->ID() ]['reg_objs'] |
|
128 | + $this->_registrations_for_recipient = isset($this->_recipient->attendees[$attendee->ID()]['reg_objs']) |
|
129 | + ? $this->_recipient->attendees[$attendee->ID()]['reg_objs'] |
|
130 | 130 | : array(); |
131 | 131 | |
132 | 132 | switch ($shortcode) { |
@@ -143,21 +143,21 @@ discard block |
||
143 | 143 | break; |
144 | 144 | |
145 | 145 | case '[RECIPIENT_REGISTRATION_ID]': |
146 | - if (! $this->_recipient->reg_obj instanceof EE_Registration) { |
|
146 | + if ( ! $this->_recipient->reg_obj instanceof EE_Registration) { |
|
147 | 147 | return ''; |
148 | 148 | } |
149 | 149 | return $this->_get_reg_id(); |
150 | 150 | break; |
151 | 151 | |
152 | 152 | case '[RECIPIENT_REGISTRATION_CODE]': |
153 | - if (! $this->_recipient->reg_obj instanceof EE_Registration) { |
|
153 | + if ( ! $this->_recipient->reg_obj instanceof EE_Registration) { |
|
154 | 154 | return ''; |
155 | 155 | } |
156 | 156 | return $this->_get_reg_code(); |
157 | 157 | break; |
158 | 158 | |
159 | 159 | case '[RECIPIENT_EDIT_REGISTRATION_LINK]': |
160 | - if (! $this->_recipient->reg_obj instanceof EE_Registration) { |
|
160 | + if ( ! $this->_recipient->reg_obj instanceof EE_Registration) { |
|
161 | 161 | return ''; |
162 | 162 | } |
163 | 163 | return $this->_recipient->reg_obj->edit_attendee_information_url(); |
@@ -213,9 +213,9 @@ discard block |
||
213 | 213 | if ( |
214 | 214 | $question instanceof EE_Question |
215 | 215 | && trim($question->display_text()) === trim($shortcode) |
216 | - && isset($this->_recipient->registrations[ $this->_recipient->reg_obj->ID() ]['ans_objs'][ $ansid ]) |
|
216 | + && isset($this->_recipient->registrations[$this->_recipient->reg_obj->ID()]['ans_objs'][$ansid]) |
|
217 | 217 | ) { |
218 | - $recipient_ansid = $this->_recipient->registrations[ $this->_recipient->reg_obj->ID() ]['ans_objs'][ $ansid ]; |
|
218 | + $recipient_ansid = $this->_recipient->registrations[$this->_recipient->reg_obj->ID()]['ans_objs'][$ansid]; |
|
219 | 219 | |
220 | 220 | // what we show for the answer depends on the question type! |
221 | 221 | switch ($question->get('QST_type')) { |
@@ -18,355 +18,355 @@ |
||
18 | 18 | */ |
19 | 19 | class EE_Recipient_Details_Shortcodes extends EE_Shortcodes |
20 | 20 | { |
21 | - protected $_recipient; |
|
22 | - |
|
23 | - protected $_registrations_for_recipient; |
|
24 | - |
|
25 | - |
|
26 | - protected function _init_props() |
|
27 | - { |
|
28 | - $this->label = esc_html__('Recipient Details Shortcodes', 'event_espresso'); |
|
29 | - $this->description = esc_html__('All shortcodes specific to recipient registration data', 'event_espresso'); |
|
30 | - $this->_shortcodes = array( |
|
31 | - '[RECIPIENT_FNAME]' => esc_html__( |
|
32 | - 'Parses to the first name of the recipient for the message.', |
|
33 | - 'event_espresso' |
|
34 | - ), |
|
35 | - '[RECIPIENT_LNAME]' => esc_html__( |
|
36 | - 'Parses to the last name of the recipient for the message.', |
|
37 | - 'event_espresso' |
|
38 | - ), |
|
39 | - '[RECIPIENT_EMAIL]' => esc_html__( |
|
40 | - 'Parses to the email address of the recipient for the message.', |
|
41 | - 'event_espresso' |
|
42 | - ), |
|
43 | - '[RECIPIENT_REGISTRATION_ID]' => esc_html__( |
|
44 | - 'Parses to the registration ID of the recipient for the message.', |
|
45 | - 'event_espresso' |
|
46 | - ), |
|
47 | - '[RECIPIENT_REGISTRATION_CODE]' => esc_html__( |
|
48 | - 'Parses to the registration code of the recipient for the message.', |
|
49 | - 'event_espresso' |
|
50 | - ), |
|
51 | - '[RECIPIENT_EDIT_REGISTRATION_LINK]' => esc_html__( |
|
52 | - 'Parses to a link for frontend editing of the registration for the recipient.', |
|
53 | - 'event_espresso' |
|
54 | - ), |
|
55 | - '[RECIPIENT_PHONE_NUMBER]' => esc_html__( |
|
56 | - 'The Phone Number for the recipient of the message.', |
|
57 | - 'event_espresso' |
|
58 | - ), |
|
59 | - '[RECIPIENT_ADDRESS]' => esc_html__( |
|
60 | - 'The Address for the recipient of the message.', |
|
61 | - 'event_espresso' |
|
62 | - ), |
|
63 | - '[RECIPIENT_ADDRESS2]' => esc_html__( |
|
64 | - 'Whatever was in the address 2 field for the recipient of the message.', |
|
65 | - 'event_espresso' |
|
66 | - ), |
|
67 | - '[RECIPIENT_CITY]' => esc_html__( |
|
68 | - 'The city for the recipient of the message.', |
|
69 | - 'event_espresso' |
|
70 | - ), |
|
71 | - '[RECIPIENT_ZIP_PC]' => esc_html__( |
|
72 | - 'The ZIP (or Postal) Code for the recipient of the message.', |
|
73 | - 'event_espresso' |
|
74 | - ), |
|
75 | - '[RECIPIENT_ADDRESS_STATE]' => esc_html__( |
|
76 | - 'The state/province for the recipient of the message.', |
|
77 | - 'event_espresso' |
|
78 | - ), |
|
79 | - '[RECIPIENT_COUNTRY]' => esc_html__( |
|
80 | - 'The country for the recipient of the message.', |
|
81 | - 'event_espresso' |
|
82 | - ), |
|
83 | - '[RECIPIENT_ANSWER_*]' => esc_html__( |
|
84 | - 'This is a special dynamic shortcode. After the "*", add the exact text of an existing question, and if there is an answer for that question for this recipient, then it will be output in place of this shortcode.', |
|
85 | - 'event_espresso' |
|
86 | - ), |
|
87 | - '[RECIPIENT_TOTAL_AMOUNT_PAID]' => esc_html__( |
|
88 | - 'If a single registration related to the recipient is available, that is used to retrieve the total amount that has been paid for this recipient. Otherwise the value of 0 is printed.', |
|
89 | - 'event_espresso' |
|
90 | - ), |
|
91 | - ); |
|
92 | - } |
|
93 | - |
|
94 | - |
|
95 | - /** |
|
96 | - * @access protected |
|
97 | - * @param string $shortcode the shortcode to be parsed. |
|
98 | - * @return string parsed shortcode |
|
99 | - */ |
|
100 | - protected function _parser($shortcode) |
|
101 | - { |
|
102 | - |
|
103 | - // make sure we end up with a copy of the EE_Messages_Addressee object |
|
104 | - $this->_recipient = $this->_data instanceof EE_Messages_Addressee ? $this->_data : null; |
|
105 | - $this->_recipient = ! $this->_recipient instanceof EE_Messages_Addressee |
|
106 | - && is_array($this->_data) |
|
107 | - && isset($this->_data['data']) |
|
108 | - && $this->_data['data'] instanceof EE_Messages_Addressee |
|
109 | - ? $this->_data['data'] |
|
110 | - : |
|
111 | - $this->_recipient; |
|
112 | - $this->_recipient = ! $this->_recipient instanceof EE_Messages_Addressee |
|
113 | - && ! empty($this->_extra_data['data']) |
|
114 | - && $this->_extra_data['data'] instanceof EE_Messages_Addressee |
|
115 | - ? $this->_extra_data['data'] |
|
116 | - : $this->_recipient; |
|
117 | - |
|
118 | - if (! $this->_recipient instanceof EE_Messages_Addressee) { |
|
119 | - return ''; |
|
120 | - } |
|
121 | - |
|
122 | - $attendee = $this->_recipient->att_obj; |
|
123 | - if (! $attendee instanceof EE_Attendee) { |
|
124 | - return ''; |
|
125 | - } |
|
126 | - |
|
127 | - $this->_registrations_for_recipient = isset($this->_recipient->attendees[ $attendee->ID() ]['reg_objs']) |
|
128 | - ? $this->_recipient->attendees[ $attendee->ID() ]['reg_objs'] |
|
129 | - : array(); |
|
130 | - |
|
131 | - switch ($shortcode) { |
|
132 | - case '[RECIPIENT_FNAME]': |
|
133 | - return $attendee->fname(); |
|
134 | - break; |
|
135 | - |
|
136 | - case '[RECIPIENT_LNAME]': |
|
137 | - return $attendee->lname(); |
|
138 | - break; |
|
139 | - |
|
140 | - case '[RECIPIENT_EMAIL]': |
|
141 | - return $attendee->email(); |
|
142 | - break; |
|
143 | - |
|
144 | - case '[RECIPIENT_REGISTRATION_ID]': |
|
145 | - if (! $this->_recipient->reg_obj instanceof EE_Registration) { |
|
146 | - return ''; |
|
147 | - } |
|
148 | - return $this->_get_reg_id(); |
|
149 | - break; |
|
150 | - |
|
151 | - case '[RECIPIENT_REGISTRATION_CODE]': |
|
152 | - if (! $this->_recipient->reg_obj instanceof EE_Registration) { |
|
153 | - return ''; |
|
154 | - } |
|
155 | - return $this->_get_reg_code(); |
|
156 | - break; |
|
157 | - |
|
158 | - case '[RECIPIENT_EDIT_REGISTRATION_LINK]': |
|
159 | - if (! $this->_recipient->reg_obj instanceof EE_Registration) { |
|
160 | - return ''; |
|
161 | - } |
|
162 | - return $this->_recipient->reg_obj->edit_attendee_information_url(); |
|
163 | - break; |
|
164 | - |
|
165 | - case '[RECIPIENT_PHONE_NUMBER]': |
|
166 | - return $attendee->phone(); |
|
167 | - break; |
|
168 | - |
|
169 | - case '[RECIPIENT_ADDRESS]': |
|
170 | - return $attendee->address(); |
|
171 | - break; |
|
172 | - |
|
173 | - case '[RECIPIENT_ADDRESS2]': |
|
174 | - return $attendee->address2(); |
|
175 | - break; |
|
176 | - |
|
177 | - case '[RECIPIENT_CITY]': |
|
178 | - return $attendee->city(); |
|
179 | - break; |
|
180 | - |
|
181 | - case '[RECIPIENT_ZIP_PC]': |
|
182 | - return $attendee->zip(); |
|
183 | - break; |
|
184 | - |
|
185 | - case '[RECIPIENT_ADDRESS_STATE]': |
|
186 | - $state_obj = $attendee->state_obj(); |
|
187 | - return $state_obj instanceof EE_State ? $state_obj->name() : ''; |
|
188 | - break; |
|
189 | - |
|
190 | - case '[RECIPIENT_COUNTRY]': |
|
191 | - $country_obj = $attendee->country_obj(); |
|
192 | - return $country_obj instanceof EE_Country ? $country_obj->name() : ''; |
|
193 | - break; |
|
194 | - case '[RECIPIENT_TOTAL_AMOUNT_PAID]': |
|
195 | - return $this->_recipient->reg_obj instanceof EE_Registration |
|
196 | - ? $this->_recipient->reg_obj->pretty_paid() |
|
197 | - : 0; |
|
198 | - break; |
|
199 | - } |
|
200 | - |
|
201 | - if (strpos($shortcode, '[RECIPIENT_ANSWER_*') !== false) { |
|
202 | - $shortcode = str_replace('[RECIPIENT_ANSWER_*', '', $shortcode); |
|
203 | - $shortcode = trim(str_replace(']', '', $shortcode)); |
|
204 | - |
|
205 | - |
|
206 | - // now let's figure out what question has this text |
|
207 | - if (empty($this->_recipient->questions) || ! $this->_recipient->reg_obj instanceof EE_Registration) { |
|
208 | - return ''; |
|
209 | - } |
|
210 | - |
|
211 | - foreach ($this->_recipient->questions as $ansid => $question) { |
|
212 | - if ( |
|
213 | - $question instanceof EE_Question |
|
214 | - && trim($question->display_text()) === trim($shortcode) |
|
215 | - && isset($this->_recipient->registrations[ $this->_recipient->reg_obj->ID() ]['ans_objs'][ $ansid ]) |
|
216 | - ) { |
|
217 | - $recipient_ansid = $this->_recipient->registrations[ $this->_recipient->reg_obj->ID() ]['ans_objs'][ $ansid ]; |
|
218 | - |
|
219 | - // what we show for the answer depends on the question type! |
|
220 | - switch ($question->get('QST_type')) { |
|
221 | - case EEM_Question::QST_type_state: |
|
222 | - $state = EEM_State::instance()->get_one_by_ID($recipient_ansid->get('ANS_value')); |
|
223 | - $answer = $state instanceof EE_State ? $state->name() : ''; |
|
224 | - break; |
|
225 | - |
|
226 | - case EEM_Question::QST_type_country: |
|
227 | - $country = EEM_Country::instance()->get_one_by_ID($recipient_ansid->get('ANS_value')); |
|
228 | - $answer = $country instanceof EE_Country ? $country->name() : ''; |
|
229 | - break; |
|
230 | - |
|
231 | - default: |
|
232 | - $answer = $recipient_ansid->get_pretty('ANS_value', 'no_wpautop'); |
|
233 | - break; |
|
234 | - } |
|
235 | - |
|
236 | - return $answer; |
|
237 | - break; |
|
238 | - } |
|
239 | - } |
|
240 | - } |
|
241 | - |
|
242 | - return ''; |
|
243 | - } |
|
244 | - |
|
245 | - |
|
246 | - /** |
|
247 | - * Returns the EE_Messages_Addressee object for the recipient. |
|
248 | - * |
|
249 | - * @since 4.5.0 |
|
250 | - * |
|
251 | - * @return EE_Messages_Addressee |
|
252 | - */ |
|
253 | - public function get_recipient() |
|
254 | - { |
|
255 | - return $this->_recipient; |
|
256 | - } |
|
257 | - |
|
258 | - |
|
259 | - /** |
|
260 | - * returns the reg code for the recipient depending on the context and whether the recipient has multiple |
|
261 | - * registrations or not. |
|
262 | - * |
|
263 | - * @return string |
|
264 | - */ |
|
265 | - protected function _get_reg_code() |
|
266 | - { |
|
267 | - |
|
268 | - // if only one related registration for the recipient then just return that reg code. |
|
269 | - if (count($this->_registrations_for_recipient) <= 1) { |
|
270 | - return $this->_recipient->reg_obj->reg_code(); |
|
271 | - } |
|
272 | - |
|
273 | - // k more than one registration so let's see if we can get specific to context |
|
274 | - // are we parsing event_list? |
|
275 | - if ($this->_data instanceof EE_Event) { |
|
276 | - $reg_code = array(); |
|
277 | - // loop through registrations for recipient and see if there is a match for this event |
|
278 | - foreach ($this->_registrations_for_recipient as $reg) { |
|
279 | - if ($reg instanceof EE_Registration && $reg->event_ID() == $this->_data->ID()) { |
|
280 | - $reg_code[] = $reg->reg_code(); |
|
281 | - } |
|
282 | - } |
|
283 | - return implode(', ', $reg_code); |
|
284 | - } |
|
285 | - |
|
286 | - // are we parsing ticket list? |
|
287 | - if ($this->_data instanceof EE_Ticket) { |
|
288 | - $reg_code = array(); |
|
289 | - // loop through each registration for recipient and see if there is a match for this ticket |
|
290 | - foreach ($this->_registrations_for_recipient as $reg) { |
|
291 | - if ($reg instanceof EE_Registration && $reg->ticket_ID() == $this->_data->ID()) { |
|
292 | - $reg_code[] = $reg->reg_code(); |
|
293 | - } |
|
294 | - } |
|
295 | - return implode(', ', $reg_code); |
|
296 | - } |
|
297 | - |
|
298 | - // do we have a specific reg_obj? Let's use it |
|
299 | - if ($this->_data instanceof EE_Messages_Addressee && $this->_data->reg_obj instanceof EE_Registration) { |
|
300 | - return $this->_data->reg_obj->reg_code(); |
|
301 | - } |
|
302 | - |
|
303 | - // do we have a specific reg_obj? Let's use it |
|
304 | - if ($this->_data instanceof EE_Messages_Addressee && $this->_data->reg_obj instanceof EE_Registration) { |
|
305 | - return $this->_data->reg_obj->reg_code(); |
|
306 | - } |
|
307 | - |
|
308 | - // not able to determine the single reg code so let's return a comma delimited list of reg codes. |
|
309 | - $reg_code = array(); |
|
310 | - foreach ($this->_registrations_for_recipient as $reg) { |
|
311 | - if ($reg instanceof EE_Registration) { |
|
312 | - $reg_code[] = $reg->reg_code(); |
|
313 | - } |
|
314 | - } |
|
315 | - return implode(', ', $reg_code); |
|
316 | - } |
|
317 | - |
|
318 | - |
|
319 | - /** |
|
320 | - * returns the reg ID for the recipient depending on the context and whether the recipient has multiple |
|
321 | - * registrations or not. |
|
322 | - * |
|
323 | - * @return int|string |
|
324 | - */ |
|
325 | - protected function _get_reg_id() |
|
326 | - { |
|
327 | - |
|
328 | - // if only one related registration for the recipient then just return that reg code. |
|
329 | - if (count($this->_registrations_for_recipient) <= 1) { |
|
330 | - return $this->_recipient->reg_obj->ID(); |
|
331 | - } |
|
332 | - |
|
333 | - // k more than one registration so let's see if we can get specific to context |
|
334 | - // are we parsing event_list? |
|
335 | - if ($this->_data instanceof EE_Event) { |
|
336 | - $registration_ids = array(); |
|
337 | - // loop through registrations for recipient and see if there is a match for this event |
|
338 | - foreach ($this->_registrations_for_recipient as $reg) { |
|
339 | - if ($reg instanceof EE_Registration && $reg->event_ID() == $this->_data->ID()) { |
|
340 | - $registration_ids[] = $reg->ID(); |
|
341 | - } |
|
342 | - } |
|
343 | - return implode(', ', $registration_ids); |
|
344 | - } |
|
345 | - |
|
346 | - // are we parsing ticket list? |
|
347 | - if ($this->_data instanceof EE_Ticket) { |
|
348 | - $registration_ids = array(); |
|
349 | - // loop through each registration for recipient and see if there is a match for this ticket |
|
350 | - foreach ($this->_registrations_for_recipient as $reg) { |
|
351 | - if ($reg instanceof EE_Registration && $reg->ticket_ID() == $this->_data->ID()) { |
|
352 | - $registration_ids = $reg->ID(); |
|
353 | - } |
|
354 | - } |
|
355 | - return implode(', ', $registration_ids); |
|
356 | - } |
|
357 | - |
|
358 | - // do we have a specific reg_obj? Let's use it |
|
359 | - if ($this->_data instanceof EE_Messages_Addressee && $this->_data->reg_obj instanceof EE_Registration) { |
|
360 | - return $this->_data->reg_obj->ID(); |
|
361 | - } |
|
362 | - |
|
363 | - // not able to determine the single reg code so let's return a comma delimited list of reg codes. |
|
364 | - $registration_ids = array(); |
|
365 | - foreach ($this->_registrations_for_recipient as $reg) { |
|
366 | - if ($reg instanceof EE_Registration) { |
|
367 | - $registration_ids[] = $reg->ID(); |
|
368 | - } |
|
369 | - } |
|
370 | - return implode(', ', $registration_ids); |
|
371 | - } |
|
21 | + protected $_recipient; |
|
22 | + |
|
23 | + protected $_registrations_for_recipient; |
|
24 | + |
|
25 | + |
|
26 | + protected function _init_props() |
|
27 | + { |
|
28 | + $this->label = esc_html__('Recipient Details Shortcodes', 'event_espresso'); |
|
29 | + $this->description = esc_html__('All shortcodes specific to recipient registration data', 'event_espresso'); |
|
30 | + $this->_shortcodes = array( |
|
31 | + '[RECIPIENT_FNAME]' => esc_html__( |
|
32 | + 'Parses to the first name of the recipient for the message.', |
|
33 | + 'event_espresso' |
|
34 | + ), |
|
35 | + '[RECIPIENT_LNAME]' => esc_html__( |
|
36 | + 'Parses to the last name of the recipient for the message.', |
|
37 | + 'event_espresso' |
|
38 | + ), |
|
39 | + '[RECIPIENT_EMAIL]' => esc_html__( |
|
40 | + 'Parses to the email address of the recipient for the message.', |
|
41 | + 'event_espresso' |
|
42 | + ), |
|
43 | + '[RECIPIENT_REGISTRATION_ID]' => esc_html__( |
|
44 | + 'Parses to the registration ID of the recipient for the message.', |
|
45 | + 'event_espresso' |
|
46 | + ), |
|
47 | + '[RECIPIENT_REGISTRATION_CODE]' => esc_html__( |
|
48 | + 'Parses to the registration code of the recipient for the message.', |
|
49 | + 'event_espresso' |
|
50 | + ), |
|
51 | + '[RECIPIENT_EDIT_REGISTRATION_LINK]' => esc_html__( |
|
52 | + 'Parses to a link for frontend editing of the registration for the recipient.', |
|
53 | + 'event_espresso' |
|
54 | + ), |
|
55 | + '[RECIPIENT_PHONE_NUMBER]' => esc_html__( |
|
56 | + 'The Phone Number for the recipient of the message.', |
|
57 | + 'event_espresso' |
|
58 | + ), |
|
59 | + '[RECIPIENT_ADDRESS]' => esc_html__( |
|
60 | + 'The Address for the recipient of the message.', |
|
61 | + 'event_espresso' |
|
62 | + ), |
|
63 | + '[RECIPIENT_ADDRESS2]' => esc_html__( |
|
64 | + 'Whatever was in the address 2 field for the recipient of the message.', |
|
65 | + 'event_espresso' |
|
66 | + ), |
|
67 | + '[RECIPIENT_CITY]' => esc_html__( |
|
68 | + 'The city for the recipient of the message.', |
|
69 | + 'event_espresso' |
|
70 | + ), |
|
71 | + '[RECIPIENT_ZIP_PC]' => esc_html__( |
|
72 | + 'The ZIP (or Postal) Code for the recipient of the message.', |
|
73 | + 'event_espresso' |
|
74 | + ), |
|
75 | + '[RECIPIENT_ADDRESS_STATE]' => esc_html__( |
|
76 | + 'The state/province for the recipient of the message.', |
|
77 | + 'event_espresso' |
|
78 | + ), |
|
79 | + '[RECIPIENT_COUNTRY]' => esc_html__( |
|
80 | + 'The country for the recipient of the message.', |
|
81 | + 'event_espresso' |
|
82 | + ), |
|
83 | + '[RECIPIENT_ANSWER_*]' => esc_html__( |
|
84 | + 'This is a special dynamic shortcode. After the "*", add the exact text of an existing question, and if there is an answer for that question for this recipient, then it will be output in place of this shortcode.', |
|
85 | + 'event_espresso' |
|
86 | + ), |
|
87 | + '[RECIPIENT_TOTAL_AMOUNT_PAID]' => esc_html__( |
|
88 | + 'If a single registration related to the recipient is available, that is used to retrieve the total amount that has been paid for this recipient. Otherwise the value of 0 is printed.', |
|
89 | + 'event_espresso' |
|
90 | + ), |
|
91 | + ); |
|
92 | + } |
|
93 | + |
|
94 | + |
|
95 | + /** |
|
96 | + * @access protected |
|
97 | + * @param string $shortcode the shortcode to be parsed. |
|
98 | + * @return string parsed shortcode |
|
99 | + */ |
|
100 | + protected function _parser($shortcode) |
|
101 | + { |
|
102 | + |
|
103 | + // make sure we end up with a copy of the EE_Messages_Addressee object |
|
104 | + $this->_recipient = $this->_data instanceof EE_Messages_Addressee ? $this->_data : null; |
|
105 | + $this->_recipient = ! $this->_recipient instanceof EE_Messages_Addressee |
|
106 | + && is_array($this->_data) |
|
107 | + && isset($this->_data['data']) |
|
108 | + && $this->_data['data'] instanceof EE_Messages_Addressee |
|
109 | + ? $this->_data['data'] |
|
110 | + : |
|
111 | + $this->_recipient; |
|
112 | + $this->_recipient = ! $this->_recipient instanceof EE_Messages_Addressee |
|
113 | + && ! empty($this->_extra_data['data']) |
|
114 | + && $this->_extra_data['data'] instanceof EE_Messages_Addressee |
|
115 | + ? $this->_extra_data['data'] |
|
116 | + : $this->_recipient; |
|
117 | + |
|
118 | + if (! $this->_recipient instanceof EE_Messages_Addressee) { |
|
119 | + return ''; |
|
120 | + } |
|
121 | + |
|
122 | + $attendee = $this->_recipient->att_obj; |
|
123 | + if (! $attendee instanceof EE_Attendee) { |
|
124 | + return ''; |
|
125 | + } |
|
126 | + |
|
127 | + $this->_registrations_for_recipient = isset($this->_recipient->attendees[ $attendee->ID() ]['reg_objs']) |
|
128 | + ? $this->_recipient->attendees[ $attendee->ID() ]['reg_objs'] |
|
129 | + : array(); |
|
130 | + |
|
131 | + switch ($shortcode) { |
|
132 | + case '[RECIPIENT_FNAME]': |
|
133 | + return $attendee->fname(); |
|
134 | + break; |
|
135 | + |
|
136 | + case '[RECIPIENT_LNAME]': |
|
137 | + return $attendee->lname(); |
|
138 | + break; |
|
139 | + |
|
140 | + case '[RECIPIENT_EMAIL]': |
|
141 | + return $attendee->email(); |
|
142 | + break; |
|
143 | + |
|
144 | + case '[RECIPIENT_REGISTRATION_ID]': |
|
145 | + if (! $this->_recipient->reg_obj instanceof EE_Registration) { |
|
146 | + return ''; |
|
147 | + } |
|
148 | + return $this->_get_reg_id(); |
|
149 | + break; |
|
150 | + |
|
151 | + case '[RECIPIENT_REGISTRATION_CODE]': |
|
152 | + if (! $this->_recipient->reg_obj instanceof EE_Registration) { |
|
153 | + return ''; |
|
154 | + } |
|
155 | + return $this->_get_reg_code(); |
|
156 | + break; |
|
157 | + |
|
158 | + case '[RECIPIENT_EDIT_REGISTRATION_LINK]': |
|
159 | + if (! $this->_recipient->reg_obj instanceof EE_Registration) { |
|
160 | + return ''; |
|
161 | + } |
|
162 | + return $this->_recipient->reg_obj->edit_attendee_information_url(); |
|
163 | + break; |
|
164 | + |
|
165 | + case '[RECIPIENT_PHONE_NUMBER]': |
|
166 | + return $attendee->phone(); |
|
167 | + break; |
|
168 | + |
|
169 | + case '[RECIPIENT_ADDRESS]': |
|
170 | + return $attendee->address(); |
|
171 | + break; |
|
172 | + |
|
173 | + case '[RECIPIENT_ADDRESS2]': |
|
174 | + return $attendee->address2(); |
|
175 | + break; |
|
176 | + |
|
177 | + case '[RECIPIENT_CITY]': |
|
178 | + return $attendee->city(); |
|
179 | + break; |
|
180 | + |
|
181 | + case '[RECIPIENT_ZIP_PC]': |
|
182 | + return $attendee->zip(); |
|
183 | + break; |
|
184 | + |
|
185 | + case '[RECIPIENT_ADDRESS_STATE]': |
|
186 | + $state_obj = $attendee->state_obj(); |
|
187 | + return $state_obj instanceof EE_State ? $state_obj->name() : ''; |
|
188 | + break; |
|
189 | + |
|
190 | + case '[RECIPIENT_COUNTRY]': |
|
191 | + $country_obj = $attendee->country_obj(); |
|
192 | + return $country_obj instanceof EE_Country ? $country_obj->name() : ''; |
|
193 | + break; |
|
194 | + case '[RECIPIENT_TOTAL_AMOUNT_PAID]': |
|
195 | + return $this->_recipient->reg_obj instanceof EE_Registration |
|
196 | + ? $this->_recipient->reg_obj->pretty_paid() |
|
197 | + : 0; |
|
198 | + break; |
|
199 | + } |
|
200 | + |
|
201 | + if (strpos($shortcode, '[RECIPIENT_ANSWER_*') !== false) { |
|
202 | + $shortcode = str_replace('[RECIPIENT_ANSWER_*', '', $shortcode); |
|
203 | + $shortcode = trim(str_replace(']', '', $shortcode)); |
|
204 | + |
|
205 | + |
|
206 | + // now let's figure out what question has this text |
|
207 | + if (empty($this->_recipient->questions) || ! $this->_recipient->reg_obj instanceof EE_Registration) { |
|
208 | + return ''; |
|
209 | + } |
|
210 | + |
|
211 | + foreach ($this->_recipient->questions as $ansid => $question) { |
|
212 | + if ( |
|
213 | + $question instanceof EE_Question |
|
214 | + && trim($question->display_text()) === trim($shortcode) |
|
215 | + && isset($this->_recipient->registrations[ $this->_recipient->reg_obj->ID() ]['ans_objs'][ $ansid ]) |
|
216 | + ) { |
|
217 | + $recipient_ansid = $this->_recipient->registrations[ $this->_recipient->reg_obj->ID() ]['ans_objs'][ $ansid ]; |
|
218 | + |
|
219 | + // what we show for the answer depends on the question type! |
|
220 | + switch ($question->get('QST_type')) { |
|
221 | + case EEM_Question::QST_type_state: |
|
222 | + $state = EEM_State::instance()->get_one_by_ID($recipient_ansid->get('ANS_value')); |
|
223 | + $answer = $state instanceof EE_State ? $state->name() : ''; |
|
224 | + break; |
|
225 | + |
|
226 | + case EEM_Question::QST_type_country: |
|
227 | + $country = EEM_Country::instance()->get_one_by_ID($recipient_ansid->get('ANS_value')); |
|
228 | + $answer = $country instanceof EE_Country ? $country->name() : ''; |
|
229 | + break; |
|
230 | + |
|
231 | + default: |
|
232 | + $answer = $recipient_ansid->get_pretty('ANS_value', 'no_wpautop'); |
|
233 | + break; |
|
234 | + } |
|
235 | + |
|
236 | + return $answer; |
|
237 | + break; |
|
238 | + } |
|
239 | + } |
|
240 | + } |
|
241 | + |
|
242 | + return ''; |
|
243 | + } |
|
244 | + |
|
245 | + |
|
246 | + /** |
|
247 | + * Returns the EE_Messages_Addressee object for the recipient. |
|
248 | + * |
|
249 | + * @since 4.5.0 |
|
250 | + * |
|
251 | + * @return EE_Messages_Addressee |
|
252 | + */ |
|
253 | + public function get_recipient() |
|
254 | + { |
|
255 | + return $this->_recipient; |
|
256 | + } |
|
257 | + |
|
258 | + |
|
259 | + /** |
|
260 | + * returns the reg code for the recipient depending on the context and whether the recipient has multiple |
|
261 | + * registrations or not. |
|
262 | + * |
|
263 | + * @return string |
|
264 | + */ |
|
265 | + protected function _get_reg_code() |
|
266 | + { |
|
267 | + |
|
268 | + // if only one related registration for the recipient then just return that reg code. |
|
269 | + if (count($this->_registrations_for_recipient) <= 1) { |
|
270 | + return $this->_recipient->reg_obj->reg_code(); |
|
271 | + } |
|
272 | + |
|
273 | + // k more than one registration so let's see if we can get specific to context |
|
274 | + // are we parsing event_list? |
|
275 | + if ($this->_data instanceof EE_Event) { |
|
276 | + $reg_code = array(); |
|
277 | + // loop through registrations for recipient and see if there is a match for this event |
|
278 | + foreach ($this->_registrations_for_recipient as $reg) { |
|
279 | + if ($reg instanceof EE_Registration && $reg->event_ID() == $this->_data->ID()) { |
|
280 | + $reg_code[] = $reg->reg_code(); |
|
281 | + } |
|
282 | + } |
|
283 | + return implode(', ', $reg_code); |
|
284 | + } |
|
285 | + |
|
286 | + // are we parsing ticket list? |
|
287 | + if ($this->_data instanceof EE_Ticket) { |
|
288 | + $reg_code = array(); |
|
289 | + // loop through each registration for recipient and see if there is a match for this ticket |
|
290 | + foreach ($this->_registrations_for_recipient as $reg) { |
|
291 | + if ($reg instanceof EE_Registration && $reg->ticket_ID() == $this->_data->ID()) { |
|
292 | + $reg_code[] = $reg->reg_code(); |
|
293 | + } |
|
294 | + } |
|
295 | + return implode(', ', $reg_code); |
|
296 | + } |
|
297 | + |
|
298 | + // do we have a specific reg_obj? Let's use it |
|
299 | + if ($this->_data instanceof EE_Messages_Addressee && $this->_data->reg_obj instanceof EE_Registration) { |
|
300 | + return $this->_data->reg_obj->reg_code(); |
|
301 | + } |
|
302 | + |
|
303 | + // do we have a specific reg_obj? Let's use it |
|
304 | + if ($this->_data instanceof EE_Messages_Addressee && $this->_data->reg_obj instanceof EE_Registration) { |
|
305 | + return $this->_data->reg_obj->reg_code(); |
|
306 | + } |
|
307 | + |
|
308 | + // not able to determine the single reg code so let's return a comma delimited list of reg codes. |
|
309 | + $reg_code = array(); |
|
310 | + foreach ($this->_registrations_for_recipient as $reg) { |
|
311 | + if ($reg instanceof EE_Registration) { |
|
312 | + $reg_code[] = $reg->reg_code(); |
|
313 | + } |
|
314 | + } |
|
315 | + return implode(', ', $reg_code); |
|
316 | + } |
|
317 | + |
|
318 | + |
|
319 | + /** |
|
320 | + * returns the reg ID for the recipient depending on the context and whether the recipient has multiple |
|
321 | + * registrations or not. |
|
322 | + * |
|
323 | + * @return int|string |
|
324 | + */ |
|
325 | + protected function _get_reg_id() |
|
326 | + { |
|
327 | + |
|
328 | + // if only one related registration for the recipient then just return that reg code. |
|
329 | + if (count($this->_registrations_for_recipient) <= 1) { |
|
330 | + return $this->_recipient->reg_obj->ID(); |
|
331 | + } |
|
332 | + |
|
333 | + // k more than one registration so let's see if we can get specific to context |
|
334 | + // are we parsing event_list? |
|
335 | + if ($this->_data instanceof EE_Event) { |
|
336 | + $registration_ids = array(); |
|
337 | + // loop through registrations for recipient and see if there is a match for this event |
|
338 | + foreach ($this->_registrations_for_recipient as $reg) { |
|
339 | + if ($reg instanceof EE_Registration && $reg->event_ID() == $this->_data->ID()) { |
|
340 | + $registration_ids[] = $reg->ID(); |
|
341 | + } |
|
342 | + } |
|
343 | + return implode(', ', $registration_ids); |
|
344 | + } |
|
345 | + |
|
346 | + // are we parsing ticket list? |
|
347 | + if ($this->_data instanceof EE_Ticket) { |
|
348 | + $registration_ids = array(); |
|
349 | + // loop through each registration for recipient and see if there is a match for this ticket |
|
350 | + foreach ($this->_registrations_for_recipient as $reg) { |
|
351 | + if ($reg instanceof EE_Registration && $reg->ticket_ID() == $this->_data->ID()) { |
|
352 | + $registration_ids = $reg->ID(); |
|
353 | + } |
|
354 | + } |
|
355 | + return implode(', ', $registration_ids); |
|
356 | + } |
|
357 | + |
|
358 | + // do we have a specific reg_obj? Let's use it |
|
359 | + if ($this->_data instanceof EE_Messages_Addressee && $this->_data->reg_obj instanceof EE_Registration) { |
|
360 | + return $this->_data->reg_obj->ID(); |
|
361 | + } |
|
362 | + |
|
363 | + // not able to determine the single reg code so let's return a comma delimited list of reg codes. |
|
364 | + $registration_ids = array(); |
|
365 | + foreach ($this->_registrations_for_recipient as $reg) { |
|
366 | + if ($reg instanceof EE_Registration) { |
|
367 | + $registration_ids[] = $reg->ID(); |
|
368 | + } |
|
369 | + } |
|
370 | + return implode(', ', $registration_ids); |
|
371 | + } |
|
372 | 372 | } |
@@ -134,7 +134,7 @@ discard block |
||
134 | 134 | |
135 | 135 | |
136 | 136 | // If there is no event objecdt by now then get out. |
137 | - if (! $this->_event instanceof EE_Event) { |
|
137 | + if ( ! $this->_event instanceof EE_Event) { |
|
138 | 138 | return ''; |
139 | 139 | } |
140 | 140 | |
@@ -187,11 +187,11 @@ discard block |
||
187 | 187 | $image = $this->_event->feature_image_url(array(600, 300)); |
188 | 188 | // @todo: eventually we should make this an attribute shortcode so that em can send along what size they want returned. |
189 | 189 | return ! empty($image) |
190 | - ? '<img src="' . $image . '" alt="' |
|
190 | + ? '<img src="'.$image.'" alt="' |
|
191 | 191 | . sprintf( |
192 | 192 | esc_attr__('%s Feature Image', 'event_espresso'), |
193 | 193 | $this->_event->get('EVT_name') |
194 | - ) . '" />' |
|
194 | + ).'" />' |
|
195 | 195 | : ''; |
196 | 196 | break; |
197 | 197 | |
@@ -253,7 +253,7 @@ discard block |
||
253 | 253 | // Check if a do_shortcode attribute was set to true and if so run $event_meta through that function. |
254 | 254 | if ( |
255 | 255 | apply_filters('FHEE__EventEspresso_core_libraries_shortcodes_EE_Event_Shortcodes___parser__event_meta_do_shortcode', false) |
256 | - || !empty($attrs['do_shortcode']) && filter_var($attrs['do_shortcode'], FILTER_VALIDATE_BOOLEAN) |
|
256 | + || ! empty($attrs['do_shortcode']) && filter_var($attrs['do_shortcode'], FILTER_VALIDATE_BOOLEAN) |
|
257 | 257 | ) { |
258 | 258 | return do_shortcode($event_meta); |
259 | 259 | } |
@@ -271,11 +271,11 @@ discard block |
||
271 | 271 | |
272 | 272 | if (strpos($shortcode, '[EVENT_IMAGE_*') !== false) { |
273 | 273 | $attrs = $this->_get_shortcode_attrs($shortcode); |
274 | - $width = empty($attrs['width']) ? '' : ' width="' . $attrs['width'] . '"'; |
|
275 | - $height = empty($attrs['height']) ? '' : ' height="' . $attrs['height'] . '"'; |
|
274 | + $width = empty($attrs['width']) ? '' : ' width="'.$attrs['width'].'"'; |
|
275 | + $height = empty($attrs['height']) ? '' : ' height="'.$attrs['height'].'"'; |
|
276 | 276 | |
277 | 277 | // Size may be set to a string such as 'tumbnail' or "width, height" eg - '200,200' |
278 | - if (! empty($attrs['size'])) { |
|
278 | + if ( ! empty($attrs['size'])) { |
|
279 | 279 | $size = explode(',', $attrs['size']); |
280 | 280 | if (count($size) === 1) { |
281 | 281 | $size = $size[0]; |
@@ -287,11 +287,11 @@ discard block |
||
287 | 287 | $image = $this->_event->feature_image_url($size); |
288 | 288 | |
289 | 289 | return ! empty($image) |
290 | - ? '<img src="' . $image . '" alt="' |
|
290 | + ? '<img src="'.$image.'" alt="' |
|
291 | 291 | . sprintf( |
292 | 292 | esc_attr__('%s Feature Image', 'event_espresso'), |
293 | 293 | $this->_event->get('EVT_name') |
294 | - ) . '"' . $width . $height . '/>' |
|
294 | + ).'"'.$width.$height.'/>' |
|
295 | 295 | : ''; |
296 | 296 | } |
297 | 297 | |
@@ -310,6 +310,6 @@ discard block |
||
310 | 310 | { |
311 | 311 | $url = get_permalink($event->ID()); |
312 | 312 | |
313 | - return $full_link ? '<a href="' . $url . '">' . $event->get('EVT_name') . '</a>' : $url; |
|
313 | + return $full_link ? '<a href="'.$url.'">'.$event->get('EVT_name').'</a>' : $url; |
|
314 | 314 | } |
315 | 315 | } |
@@ -17,297 +17,297 @@ |
||
17 | 17 | */ |
18 | 18 | class EE_Event_Shortcodes extends EE_Shortcodes |
19 | 19 | { |
20 | - /** |
|
21 | - * Will hold the EE_Event if available |
|
22 | - * |
|
23 | - * @var EE_Event |
|
24 | - */ |
|
25 | - protected $_event; |
|
26 | - |
|
27 | - |
|
28 | - public function __construct() |
|
29 | - { |
|
30 | - parent::__construct(); |
|
31 | - } |
|
32 | - |
|
33 | - |
|
34 | - protected function _init_props() |
|
35 | - { |
|
36 | - $this->label = esc_html__('Event Shortcodes', 'event_espresso'); |
|
37 | - $this->description = esc_html__('All shortcodes specific to event related data', 'event_espresso'); |
|
38 | - $this->_shortcodes = array( |
|
39 | - '[EVENT_ID]' => esc_html__( |
|
40 | - 'Will be replaced by the event ID of an event', |
|
41 | - 'event_espresso' |
|
42 | - ), |
|
43 | - '[EVENT]' => esc_html__('The name of the event', 'event_espresso'), |
|
44 | - '[EVENT_NAME]' => esc_html__( |
|
45 | - "This also can be used for the name of the event", |
|
46 | - 'event_espresso' |
|
47 | - ), |
|
48 | - '[EVENT_PHONE]' => esc_html__( |
|
49 | - 'The phone number for the event (usually an info number)', |
|
50 | - 'event_espresso' |
|
51 | - ), |
|
52 | - '[EVENT_DESCRIPTION]' => esc_html__('The description of the event', 'event_espresso'), |
|
53 | - '[EVENT_EXCERPT]' => esc_html__( |
|
54 | - 'This gets parsed to the value for the excerpt field in the event or blank if there is no excerpt.', |
|
55 | - 'event_espresso' |
|
56 | - ), |
|
57 | - '[EVENT_LINK]' => esc_html__('A link associated with the event', 'event_espresso'), |
|
58 | - '[EVENT_URL]' => esc_html__( |
|
59 | - 'A link to the event set up on the host site.', |
|
60 | - 'event_espresso' |
|
61 | - ), |
|
62 | - '[VIRTUAL_URL]' => esc_html__( |
|
63 | - 'What was used for the "URL of Event" field in the Venue settings', |
|
64 | - 'event_espresso' |
|
65 | - ), |
|
66 | - '[VIRTUAL_PHONE]' => esc_html__( |
|
67 | - 'An alternate phone number for the event. Typically used as a "call-in" number', |
|
68 | - 'event_espresso' |
|
69 | - ), |
|
70 | - '[EVENT_IMAGE]' => esc_html__( |
|
71 | - 'This will parse to the Feature image for the event.', |
|
72 | - 'event_espresso' |
|
73 | - ), |
|
74 | - '[EVENT_IMAGE_*]' => sprintf( |
|
75 | - esc_html__( |
|
76 | - 'This will parse to the Feature image for the event, %1$ssize%2$s can be set to determine the size of the image loaded by the shortcode. The %1$swidth%2$s and/or %1$sheight%2$s can also be set to determine the width and height of the image when output. By default the shortcode will load the %1$sthumbnail%2$s image size.', |
|
77 | - 'event_espresso' |
|
78 | - ), |
|
79 | - '<code>', |
|
80 | - '</code>' |
|
81 | - ), |
|
82 | - '[EVENT_TOTAL_AVAILABLE_SPACES_*]' => sprintf( |
|
83 | - esc_html__( |
|
84 | - 'This will parse to the total available spaces for an event. Calculating total spaces is approximate because it is dependent on the complexity of limits on your event. There are two methods of calculation (which can be indicated by the %1$smethod%2$s param on the shortcode). %1$scurrent%2$s which will do a more accurate calculation of total available spaces based on current sales, and %1$sfull%2$s which will be the maximum total available spaces that is on the event in optimal conditions. The shortcode will default to current.', |
|
85 | - 'event_espresso' |
|
86 | - ), |
|
87 | - '<code>', |
|
88 | - '</code>' |
|
89 | - ), |
|
90 | - '[EVENT_TOTAL_SPOTS_TAKEN]' => esc_html__( |
|
91 | - 'This shortcode will parse to the output the total approved registrations for this event', |
|
92 | - 'event_espresso' |
|
93 | - ), |
|
94 | - '[EVENT_FACEBOOK_URL]' => esc_html__( |
|
95 | - 'This will return the Facebook URL for the event if you have it set via custom field in your event, otherwise it will use the Facebook URL set in "Your Organization Settings". To set the facebook url in your event, add a custom field with the key as <code>event_facebook</code> and the value as your facebook url.', |
|
96 | - 'event_espresso' |
|
97 | - ), |
|
98 | - '[EVENT_TWITTER_URL]' => esc_html__( |
|
99 | - 'This will return the Twitter URL for the event if you have it set via custom field in your event, otherwise it will use the Twitter URL set in "Your Organization Settings". To set the facebook url in your event, add a custom field with the key as <code>event_twitter</code> and the value as your facebook url', |
|
100 | - 'event_espresso' |
|
101 | - ), |
|
102 | - '[EVENT_META_*]' => sprintf( |
|
103 | - esc_html__( |
|
104 | - 'This is a special dynamic shortcode. After the "*", add the exact name for your custom field, if there is a value set for that custom field within the event then it will be output in place of this shortcode. If you use shortcodes within your custom fields set %1$sdo_shortcode=true%2$s at the end of the shortcode to run the value through the do_shortcode function. ', |
|
105 | - 'event_espresso' |
|
106 | - ), |
|
107 | - '<code>', |
|
108 | - '</code>' |
|
109 | - ), |
|
110 | - '[REGISTRATION_LIST_TABLE_FOR_EVENT_URL]' => esc_html__( |
|
111 | - 'This parses to the url for the registration list table filtered by registrations for this event.', |
|
112 | - 'event_espresso' |
|
113 | - ), |
|
114 | - ); |
|
115 | - } |
|
116 | - |
|
117 | - |
|
118 | - protected function _parser($shortcode) |
|
119 | - { |
|
120 | - |
|
121 | - |
|
122 | - $this->_event = $this->_data instanceof EE_Event ? $this->_data : null; |
|
123 | - |
|
124 | - // if no event, then let's see if there is a reg_obj. If there IS, then we'll try and grab the event from the reg_obj instead. |
|
125 | - if (empty($this->_event)) { |
|
126 | - $aee = $this->_data instanceof EE_Messages_Addressee ? $this->_data : null; |
|
127 | - $aee = $this->_extra_data instanceof EE_Messages_Addressee ? $this->_extra_data : $aee; |
|
128 | - |
|
129 | - $this->_event = $aee instanceof EE_Messages_Addressee && $aee->reg_obj instanceof EE_Registration |
|
130 | - ? $aee->reg_obj->event() : null; |
|
131 | - } |
|
132 | - |
|
133 | - |
|
134 | - // If there is no event objecdt by now then get out. |
|
135 | - if (! $this->_event instanceof EE_Event) { |
|
136 | - return ''; |
|
137 | - } |
|
138 | - |
|
139 | - switch ($shortcode) { |
|
140 | - case '[EVENT_ID]': |
|
141 | - return $this->_event->ID(); |
|
142 | - break; |
|
143 | - |
|
144 | - case '[EVENT]': |
|
145 | - case '[EVENT_NAME]': |
|
146 | - return $this->_event->get('EVT_name'); |
|
147 | - break; |
|
148 | - |
|
149 | - case '[EVENT_PHONE]': |
|
150 | - return $this->_event->get('EVT_phone'); |
|
151 | - break; |
|
152 | - |
|
153 | - case '[EVENT_DESCRIPTION]': |
|
154 | - return $this->_event->get('EVT_desc'); |
|
155 | - break; |
|
156 | - |
|
157 | - case '[EVENT_EXCERPT]': |
|
158 | - return $this->_event->get('EVT_short_desc'); |
|
159 | - break; |
|
160 | - |
|
161 | - case '[EVENT_LINK]': |
|
162 | - return $this->_get_event_link($this->_event); |
|
163 | - break; |
|
164 | - |
|
165 | - case '[EVENT_URL]': |
|
166 | - return $this->_get_event_link($this->_event, false); |
|
167 | - break; |
|
168 | - |
|
169 | - case '[VIRTUAL_URL]': |
|
170 | - $venue = $this->_event->get_first_related('Venue'); |
|
171 | - if (empty($venue)) { |
|
172 | - return ''; |
|
173 | - } |
|
174 | - return $venue->get('VNU_virtual_url'); |
|
175 | - |
|
176 | - case '[VIRTUAL_PHONE]': |
|
177 | - $venue = $this->_event->get_first_related('Venue'); |
|
178 | - if (empty($venue)) { |
|
179 | - return ''; |
|
180 | - } |
|
181 | - return $venue->get('VNU_virtual_phone'); |
|
182 | - break; |
|
183 | - |
|
184 | - case '[EVENT_IMAGE]': |
|
185 | - $image = $this->_event->feature_image_url(array(600, 300)); |
|
186 | - // @todo: eventually we should make this an attribute shortcode so that em can send along what size they want returned. |
|
187 | - return ! empty($image) |
|
188 | - ? '<img src="' . $image . '" alt="' |
|
189 | - . sprintf( |
|
190 | - esc_attr__('%s Feature Image', 'event_espresso'), |
|
191 | - $this->_event->get('EVT_name') |
|
192 | - ) . '" />' |
|
193 | - : ''; |
|
194 | - break; |
|
195 | - |
|
196 | - case '[EVENT_FACEBOOK_URL]': |
|
197 | - $facebook_url = $this->_event->get_post_meta('event_facebook', true); |
|
198 | - return empty($facebook_url) ? EE_Registry::instance()->CFG->organization->get_pretty('facebook') |
|
199 | - : $facebook_url; |
|
200 | - break; |
|
201 | - |
|
202 | - case '[EVENT_TWITTER_URL]': |
|
203 | - $twitter_url = $this->_event->get_post_meta('event_twitter', true); |
|
204 | - return empty($twitter_url) ? EE_Registry::instance()->CFG->organization->get_pretty('twitter') |
|
205 | - : $twitter_url; |
|
206 | - break; |
|
207 | - |
|
208 | - case '[EVENT_AUTHOR_EMAIL]': |
|
209 | - $author_id = $this->_event->get('EVT_wp_user'); |
|
210 | - $user_data = get_userdata((int) $author_id); |
|
211 | - return $user_data->user_email; |
|
212 | - break; |
|
213 | - |
|
214 | - case '[EVENT_TOTAL_SPOTS_TAKEN]': |
|
215 | - return EEM_Registration::instance()->count( |
|
216 | - array(array('EVT_ID' => $this->_event->ID(), 'STS_ID' => EEM_Registration::status_id_approved)), |
|
217 | - 'REG_ID', |
|
218 | - true |
|
219 | - ); |
|
220 | - break; |
|
221 | - |
|
222 | - case '[REGISTRATION_LIST_TABLE_FOR_EVENT_URL]': |
|
223 | - return EEH_URL::add_query_args_and_nonce( |
|
224 | - array( |
|
225 | - 'event_id' => $this->_event->ID(), |
|
226 | - 'page' => 'espresso_registrations', |
|
227 | - 'action' => 'default', |
|
228 | - ), |
|
229 | - admin_url('admin.php'), |
|
230 | - true |
|
231 | - ); |
|
232 | - break; |
|
233 | - } |
|
234 | - |
|
235 | - if (strpos($shortcode, '[EVENT_META_*') !== false) { |
|
236 | - // Strip the shortcode itself from $shortcode leaving any attributes set. |
|
237 | - // Removing the * is correct here as _* is used to indiciate a dynamic shortcode. |
|
238 | - $shortcode = str_replace('[EVENT_META_*', '', $shortcode); |
|
239 | - $shortcode = trim(str_replace(']', '', $shortcode)); |
|
240 | - // Get any attributes set on this shortcode. |
|
241 | - $attrs = $this->_get_shortcode_attrs($shortcode); |
|
242 | - // The meta_key set on the shortcode should always be the first value in the array. |
|
243 | - $meta_key = $attrs[0]; |
|
244 | - // Pull the meta value from the event post. |
|
245 | - $event_meta = $this->_event->get_post_meta($meta_key, true); |
|
246 | - // If we have no event_meta, just return an empty string. |
|
247 | - if (empty($event_meta)) { |
|
248 | - return ''; |
|
249 | - } |
|
250 | - // Add a filter to allow all instances of EVENT_META_* to run through do_shortcode, default to false. |
|
251 | - // Check if a do_shortcode attribute was set to true and if so run $event_meta through that function. |
|
252 | - if ( |
|
253 | - apply_filters('FHEE__EventEspresso_core_libraries_shortcodes_EE_Event_Shortcodes___parser__event_meta_do_shortcode', false) |
|
254 | - || !empty($attrs['do_shortcode']) && filter_var($attrs['do_shortcode'], FILTER_VALIDATE_BOOLEAN) |
|
255 | - ) { |
|
256 | - return do_shortcode($event_meta); |
|
257 | - } |
|
258 | - // Still here? We just need to return the event_meta value as is. |
|
259 | - return $event_meta; |
|
260 | - } |
|
261 | - |
|
262 | - if (strpos($shortcode, '[EVENT_TOTAL_AVAILABLE_SPACES_*') !== false) { |
|
263 | - $attrs = $this->_get_shortcode_attrs($shortcode); |
|
264 | - $method = empty($attrs['method']) ? 'current' : $attrs['method']; |
|
265 | - $method = $method === 'current'; |
|
266 | - $available = $this->_event->total_available_spaces($method); |
|
267 | - return $available === EE_INF ? '∞' : $available; |
|
268 | - } |
|
269 | - |
|
270 | - if (strpos($shortcode, '[EVENT_IMAGE_*') !== false) { |
|
271 | - $attrs = $this->_get_shortcode_attrs($shortcode); |
|
272 | - $width = empty($attrs['width']) ? '' : ' width="' . $attrs['width'] . '"'; |
|
273 | - $height = empty($attrs['height']) ? '' : ' height="' . $attrs['height'] . '"'; |
|
274 | - |
|
275 | - // Size may be set to a string such as 'tumbnail' or "width, height" eg - '200,200' |
|
276 | - if (! empty($attrs['size'])) { |
|
277 | - $size = explode(',', $attrs['size']); |
|
278 | - if (count($size) === 1) { |
|
279 | - $size = $size[0]; |
|
280 | - } |
|
281 | - } else { |
|
282 | - $size = 'thumbnail'; |
|
283 | - } |
|
284 | - |
|
285 | - $image = $this->_event->feature_image_url($size); |
|
286 | - |
|
287 | - return ! empty($image) |
|
288 | - ? '<img src="' . $image . '" alt="' |
|
289 | - . sprintf( |
|
290 | - esc_attr__('%s Feature Image', 'event_espresso'), |
|
291 | - $this->_event->get('EVT_name') |
|
292 | - ) . '"' . $width . $height . '/>' |
|
293 | - : ''; |
|
294 | - } |
|
295 | - |
|
296 | - return ''; |
|
297 | - } |
|
298 | - |
|
299 | - |
|
300 | - /** |
|
301 | - * returns the link to the event |
|
302 | - * |
|
303 | - * @param boolean $full_link if TRUE (default) we return the html for the name of the event linked to the event. |
|
304 | - * Otherwise we just return the url of the event. |
|
305 | - * @return string |
|
306 | - */ |
|
307 | - private function _get_event_link($event, $full_link = true) |
|
308 | - { |
|
309 | - $url = get_permalink($event->ID()); |
|
310 | - |
|
311 | - return $full_link ? '<a href="' . $url . '">' . $event->get('EVT_name') . '</a>' : $url; |
|
312 | - } |
|
20 | + /** |
|
21 | + * Will hold the EE_Event if available |
|
22 | + * |
|
23 | + * @var EE_Event |
|
24 | + */ |
|
25 | + protected $_event; |
|
26 | + |
|
27 | + |
|
28 | + public function __construct() |
|
29 | + { |
|
30 | + parent::__construct(); |
|
31 | + } |
|
32 | + |
|
33 | + |
|
34 | + protected function _init_props() |
|
35 | + { |
|
36 | + $this->label = esc_html__('Event Shortcodes', 'event_espresso'); |
|
37 | + $this->description = esc_html__('All shortcodes specific to event related data', 'event_espresso'); |
|
38 | + $this->_shortcodes = array( |
|
39 | + '[EVENT_ID]' => esc_html__( |
|
40 | + 'Will be replaced by the event ID of an event', |
|
41 | + 'event_espresso' |
|
42 | + ), |
|
43 | + '[EVENT]' => esc_html__('The name of the event', 'event_espresso'), |
|
44 | + '[EVENT_NAME]' => esc_html__( |
|
45 | + "This also can be used for the name of the event", |
|
46 | + 'event_espresso' |
|
47 | + ), |
|
48 | + '[EVENT_PHONE]' => esc_html__( |
|
49 | + 'The phone number for the event (usually an info number)', |
|
50 | + 'event_espresso' |
|
51 | + ), |
|
52 | + '[EVENT_DESCRIPTION]' => esc_html__('The description of the event', 'event_espresso'), |
|
53 | + '[EVENT_EXCERPT]' => esc_html__( |
|
54 | + 'This gets parsed to the value for the excerpt field in the event or blank if there is no excerpt.', |
|
55 | + 'event_espresso' |
|
56 | + ), |
|
57 | + '[EVENT_LINK]' => esc_html__('A link associated with the event', 'event_espresso'), |
|
58 | + '[EVENT_URL]' => esc_html__( |
|
59 | + 'A link to the event set up on the host site.', |
|
60 | + 'event_espresso' |
|
61 | + ), |
|
62 | + '[VIRTUAL_URL]' => esc_html__( |
|
63 | + 'What was used for the "URL of Event" field in the Venue settings', |
|
64 | + 'event_espresso' |
|
65 | + ), |
|
66 | + '[VIRTUAL_PHONE]' => esc_html__( |
|
67 | + 'An alternate phone number for the event. Typically used as a "call-in" number', |
|
68 | + 'event_espresso' |
|
69 | + ), |
|
70 | + '[EVENT_IMAGE]' => esc_html__( |
|
71 | + 'This will parse to the Feature image for the event.', |
|
72 | + 'event_espresso' |
|
73 | + ), |
|
74 | + '[EVENT_IMAGE_*]' => sprintf( |
|
75 | + esc_html__( |
|
76 | + 'This will parse to the Feature image for the event, %1$ssize%2$s can be set to determine the size of the image loaded by the shortcode. The %1$swidth%2$s and/or %1$sheight%2$s can also be set to determine the width and height of the image when output. By default the shortcode will load the %1$sthumbnail%2$s image size.', |
|
77 | + 'event_espresso' |
|
78 | + ), |
|
79 | + '<code>', |
|
80 | + '</code>' |
|
81 | + ), |
|
82 | + '[EVENT_TOTAL_AVAILABLE_SPACES_*]' => sprintf( |
|
83 | + esc_html__( |
|
84 | + 'This will parse to the total available spaces for an event. Calculating total spaces is approximate because it is dependent on the complexity of limits on your event. There are two methods of calculation (which can be indicated by the %1$smethod%2$s param on the shortcode). %1$scurrent%2$s which will do a more accurate calculation of total available spaces based on current sales, and %1$sfull%2$s which will be the maximum total available spaces that is on the event in optimal conditions. The shortcode will default to current.', |
|
85 | + 'event_espresso' |
|
86 | + ), |
|
87 | + '<code>', |
|
88 | + '</code>' |
|
89 | + ), |
|
90 | + '[EVENT_TOTAL_SPOTS_TAKEN]' => esc_html__( |
|
91 | + 'This shortcode will parse to the output the total approved registrations for this event', |
|
92 | + 'event_espresso' |
|
93 | + ), |
|
94 | + '[EVENT_FACEBOOK_URL]' => esc_html__( |
|
95 | + 'This will return the Facebook URL for the event if you have it set via custom field in your event, otherwise it will use the Facebook URL set in "Your Organization Settings". To set the facebook url in your event, add a custom field with the key as <code>event_facebook</code> and the value as your facebook url.', |
|
96 | + 'event_espresso' |
|
97 | + ), |
|
98 | + '[EVENT_TWITTER_URL]' => esc_html__( |
|
99 | + 'This will return the Twitter URL for the event if you have it set via custom field in your event, otherwise it will use the Twitter URL set in "Your Organization Settings". To set the facebook url in your event, add a custom field with the key as <code>event_twitter</code> and the value as your facebook url', |
|
100 | + 'event_espresso' |
|
101 | + ), |
|
102 | + '[EVENT_META_*]' => sprintf( |
|
103 | + esc_html__( |
|
104 | + 'This is a special dynamic shortcode. After the "*", add the exact name for your custom field, if there is a value set for that custom field within the event then it will be output in place of this shortcode. If you use shortcodes within your custom fields set %1$sdo_shortcode=true%2$s at the end of the shortcode to run the value through the do_shortcode function. ', |
|
105 | + 'event_espresso' |
|
106 | + ), |
|
107 | + '<code>', |
|
108 | + '</code>' |
|
109 | + ), |
|
110 | + '[REGISTRATION_LIST_TABLE_FOR_EVENT_URL]' => esc_html__( |
|
111 | + 'This parses to the url for the registration list table filtered by registrations for this event.', |
|
112 | + 'event_espresso' |
|
113 | + ), |
|
114 | + ); |
|
115 | + } |
|
116 | + |
|
117 | + |
|
118 | + protected function _parser($shortcode) |
|
119 | + { |
|
120 | + |
|
121 | + |
|
122 | + $this->_event = $this->_data instanceof EE_Event ? $this->_data : null; |
|
123 | + |
|
124 | + // if no event, then let's see if there is a reg_obj. If there IS, then we'll try and grab the event from the reg_obj instead. |
|
125 | + if (empty($this->_event)) { |
|
126 | + $aee = $this->_data instanceof EE_Messages_Addressee ? $this->_data : null; |
|
127 | + $aee = $this->_extra_data instanceof EE_Messages_Addressee ? $this->_extra_data : $aee; |
|
128 | + |
|
129 | + $this->_event = $aee instanceof EE_Messages_Addressee && $aee->reg_obj instanceof EE_Registration |
|
130 | + ? $aee->reg_obj->event() : null; |
|
131 | + } |
|
132 | + |
|
133 | + |
|
134 | + // If there is no event objecdt by now then get out. |
|
135 | + if (! $this->_event instanceof EE_Event) { |
|
136 | + return ''; |
|
137 | + } |
|
138 | + |
|
139 | + switch ($shortcode) { |
|
140 | + case '[EVENT_ID]': |
|
141 | + return $this->_event->ID(); |
|
142 | + break; |
|
143 | + |
|
144 | + case '[EVENT]': |
|
145 | + case '[EVENT_NAME]': |
|
146 | + return $this->_event->get('EVT_name'); |
|
147 | + break; |
|
148 | + |
|
149 | + case '[EVENT_PHONE]': |
|
150 | + return $this->_event->get('EVT_phone'); |
|
151 | + break; |
|
152 | + |
|
153 | + case '[EVENT_DESCRIPTION]': |
|
154 | + return $this->_event->get('EVT_desc'); |
|
155 | + break; |
|
156 | + |
|
157 | + case '[EVENT_EXCERPT]': |
|
158 | + return $this->_event->get('EVT_short_desc'); |
|
159 | + break; |
|
160 | + |
|
161 | + case '[EVENT_LINK]': |
|
162 | + return $this->_get_event_link($this->_event); |
|
163 | + break; |
|
164 | + |
|
165 | + case '[EVENT_URL]': |
|
166 | + return $this->_get_event_link($this->_event, false); |
|
167 | + break; |
|
168 | + |
|
169 | + case '[VIRTUAL_URL]': |
|
170 | + $venue = $this->_event->get_first_related('Venue'); |
|
171 | + if (empty($venue)) { |
|
172 | + return ''; |
|
173 | + } |
|
174 | + return $venue->get('VNU_virtual_url'); |
|
175 | + |
|
176 | + case '[VIRTUAL_PHONE]': |
|
177 | + $venue = $this->_event->get_first_related('Venue'); |
|
178 | + if (empty($venue)) { |
|
179 | + return ''; |
|
180 | + } |
|
181 | + return $venue->get('VNU_virtual_phone'); |
|
182 | + break; |
|
183 | + |
|
184 | + case '[EVENT_IMAGE]': |
|
185 | + $image = $this->_event->feature_image_url(array(600, 300)); |
|
186 | + // @todo: eventually we should make this an attribute shortcode so that em can send along what size they want returned. |
|
187 | + return ! empty($image) |
|
188 | + ? '<img src="' . $image . '" alt="' |
|
189 | + . sprintf( |
|
190 | + esc_attr__('%s Feature Image', 'event_espresso'), |
|
191 | + $this->_event->get('EVT_name') |
|
192 | + ) . '" />' |
|
193 | + : ''; |
|
194 | + break; |
|
195 | + |
|
196 | + case '[EVENT_FACEBOOK_URL]': |
|
197 | + $facebook_url = $this->_event->get_post_meta('event_facebook', true); |
|
198 | + return empty($facebook_url) ? EE_Registry::instance()->CFG->organization->get_pretty('facebook') |
|
199 | + : $facebook_url; |
|
200 | + break; |
|
201 | + |
|
202 | + case '[EVENT_TWITTER_URL]': |
|
203 | + $twitter_url = $this->_event->get_post_meta('event_twitter', true); |
|
204 | + return empty($twitter_url) ? EE_Registry::instance()->CFG->organization->get_pretty('twitter') |
|
205 | + : $twitter_url; |
|
206 | + break; |
|
207 | + |
|
208 | + case '[EVENT_AUTHOR_EMAIL]': |
|
209 | + $author_id = $this->_event->get('EVT_wp_user'); |
|
210 | + $user_data = get_userdata((int) $author_id); |
|
211 | + return $user_data->user_email; |
|
212 | + break; |
|
213 | + |
|
214 | + case '[EVENT_TOTAL_SPOTS_TAKEN]': |
|
215 | + return EEM_Registration::instance()->count( |
|
216 | + array(array('EVT_ID' => $this->_event->ID(), 'STS_ID' => EEM_Registration::status_id_approved)), |
|
217 | + 'REG_ID', |
|
218 | + true |
|
219 | + ); |
|
220 | + break; |
|
221 | + |
|
222 | + case '[REGISTRATION_LIST_TABLE_FOR_EVENT_URL]': |
|
223 | + return EEH_URL::add_query_args_and_nonce( |
|
224 | + array( |
|
225 | + 'event_id' => $this->_event->ID(), |
|
226 | + 'page' => 'espresso_registrations', |
|
227 | + 'action' => 'default', |
|
228 | + ), |
|
229 | + admin_url('admin.php'), |
|
230 | + true |
|
231 | + ); |
|
232 | + break; |
|
233 | + } |
|
234 | + |
|
235 | + if (strpos($shortcode, '[EVENT_META_*') !== false) { |
|
236 | + // Strip the shortcode itself from $shortcode leaving any attributes set. |
|
237 | + // Removing the * is correct here as _* is used to indiciate a dynamic shortcode. |
|
238 | + $shortcode = str_replace('[EVENT_META_*', '', $shortcode); |
|
239 | + $shortcode = trim(str_replace(']', '', $shortcode)); |
|
240 | + // Get any attributes set on this shortcode. |
|
241 | + $attrs = $this->_get_shortcode_attrs($shortcode); |
|
242 | + // The meta_key set on the shortcode should always be the first value in the array. |
|
243 | + $meta_key = $attrs[0]; |
|
244 | + // Pull the meta value from the event post. |
|
245 | + $event_meta = $this->_event->get_post_meta($meta_key, true); |
|
246 | + // If we have no event_meta, just return an empty string. |
|
247 | + if (empty($event_meta)) { |
|
248 | + return ''; |
|
249 | + } |
|
250 | + // Add a filter to allow all instances of EVENT_META_* to run through do_shortcode, default to false. |
|
251 | + // Check if a do_shortcode attribute was set to true and if so run $event_meta through that function. |
|
252 | + if ( |
|
253 | + apply_filters('FHEE__EventEspresso_core_libraries_shortcodes_EE_Event_Shortcodes___parser__event_meta_do_shortcode', false) |
|
254 | + || !empty($attrs['do_shortcode']) && filter_var($attrs['do_shortcode'], FILTER_VALIDATE_BOOLEAN) |
|
255 | + ) { |
|
256 | + return do_shortcode($event_meta); |
|
257 | + } |
|
258 | + // Still here? We just need to return the event_meta value as is. |
|
259 | + return $event_meta; |
|
260 | + } |
|
261 | + |
|
262 | + if (strpos($shortcode, '[EVENT_TOTAL_AVAILABLE_SPACES_*') !== false) { |
|
263 | + $attrs = $this->_get_shortcode_attrs($shortcode); |
|
264 | + $method = empty($attrs['method']) ? 'current' : $attrs['method']; |
|
265 | + $method = $method === 'current'; |
|
266 | + $available = $this->_event->total_available_spaces($method); |
|
267 | + return $available === EE_INF ? '∞' : $available; |
|
268 | + } |
|
269 | + |
|
270 | + if (strpos($shortcode, '[EVENT_IMAGE_*') !== false) { |
|
271 | + $attrs = $this->_get_shortcode_attrs($shortcode); |
|
272 | + $width = empty($attrs['width']) ? '' : ' width="' . $attrs['width'] . '"'; |
|
273 | + $height = empty($attrs['height']) ? '' : ' height="' . $attrs['height'] . '"'; |
|
274 | + |
|
275 | + // Size may be set to a string such as 'tumbnail' or "width, height" eg - '200,200' |
|
276 | + if (! empty($attrs['size'])) { |
|
277 | + $size = explode(',', $attrs['size']); |
|
278 | + if (count($size) === 1) { |
|
279 | + $size = $size[0]; |
|
280 | + } |
|
281 | + } else { |
|
282 | + $size = 'thumbnail'; |
|
283 | + } |
|
284 | + |
|
285 | + $image = $this->_event->feature_image_url($size); |
|
286 | + |
|
287 | + return ! empty($image) |
|
288 | + ? '<img src="' . $image . '" alt="' |
|
289 | + . sprintf( |
|
290 | + esc_attr__('%s Feature Image', 'event_espresso'), |
|
291 | + $this->_event->get('EVT_name') |
|
292 | + ) . '"' . $width . $height . '/>' |
|
293 | + : ''; |
|
294 | + } |
|
295 | + |
|
296 | + return ''; |
|
297 | + } |
|
298 | + |
|
299 | + |
|
300 | + /** |
|
301 | + * returns the link to the event |
|
302 | + * |
|
303 | + * @param boolean $full_link if TRUE (default) we return the html for the name of the event linked to the event. |
|
304 | + * Otherwise we just return the url of the event. |
|
305 | + * @return string |
|
306 | + */ |
|
307 | + private function _get_event_link($event, $full_link = true) |
|
308 | + { |
|
309 | + $url = get_permalink($event->ID()); |
|
310 | + |
|
311 | + return $full_link ? '<a href="' . $url . '">' . $event->get('EVT_name') . '</a>' : $url; |
|
312 | + } |
|
313 | 313 | } |