1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace EventEspresso\core\libraries\rest_api; |
4
|
|
|
|
5
|
|
|
use EEM_Base; |
6
|
|
|
use EventEspresso\core\exceptions\UnexpectedEntityException; |
7
|
|
|
use EventEspresso\core\libraries\rest_api\calculations\CalculatedModelFieldsFactory; |
8
|
|
|
use EventEspresso\core\libraries\rest_api\controllers\Base; |
9
|
|
|
use EEH_Inflector; |
10
|
|
|
use EventEspresso\core\libraries\rest_api\controllers\Base as BaseController; |
11
|
|
|
|
12
|
|
|
/** |
13
|
|
|
* Class CalculatedModelFields |
14
|
|
|
* Class for defining which model fields can be calculated, and performing those calculations |
15
|
|
|
* as requested |
16
|
|
|
* |
17
|
|
|
* @package Event Espresso |
18
|
|
|
* @subpackage |
19
|
|
|
* @author Mike Nelson |
20
|
|
|
* @since 4.8.35.rc.001 |
21
|
|
|
*/ |
22
|
|
|
class CalculatedModelFields |
23
|
|
|
{ |
24
|
|
|
|
25
|
|
|
/** |
26
|
|
|
* @var array |
27
|
|
|
*/ |
28
|
|
|
protected $mapping; |
29
|
|
|
|
30
|
|
|
/** |
31
|
|
|
* @var array |
32
|
|
|
*/ |
33
|
|
|
protected $mapping_schema; |
34
|
|
|
|
35
|
|
|
/** |
36
|
|
|
* @var CalculatedModelFieldsFactory |
37
|
|
|
*/ |
38
|
|
|
private $factory; |
39
|
|
|
|
40
|
|
|
/** |
41
|
|
|
* CalculatedModelFields constructor. |
42
|
|
|
* @param CalculatedModelFieldsFactory $factory |
43
|
|
|
*/ |
44
|
|
|
public function __construct(CalculatedModelFieldsFactory $factory) |
45
|
|
|
{ |
46
|
|
|
$this->factory = $factory; |
47
|
|
|
} |
48
|
|
|
/** |
49
|
|
|
* @param bool $refresh |
50
|
|
|
* @return array top-level-keys are model names (eg "Event") |
51
|
|
|
* next-level are the calculated field names AND method names on classes |
52
|
|
|
* which perform calculations, values are the fully qualified classnames which do the calculations |
53
|
|
|
* These callbacks should accept as arguments: |
54
|
|
|
* the wpdb row results, |
55
|
|
|
* the WP_Request object, |
56
|
|
|
* the controller object |
57
|
|
|
*/ |
58
|
|
|
public function mapping($refresh = false) |
59
|
|
|
{ |
60
|
|
|
if (! $this->mapping || $refresh) { |
|
|
|
|
61
|
|
|
$this->mapping = $this->generateNewMapping(); |
62
|
|
|
} |
63
|
|
|
return $this->mapping; |
64
|
|
|
} |
65
|
|
|
|
66
|
|
|
|
67
|
|
|
/** |
68
|
|
|
* Generates a new mapping between model calculated fields and their callbacks |
69
|
|
|
* |
70
|
|
|
* @return array |
71
|
|
|
*/ |
72
|
|
|
protected function generateNewMapping() |
73
|
|
|
{ |
74
|
|
|
$mapping = array(); |
75
|
|
|
$models_with_calculated_fields = array( |
76
|
|
|
'Attendee', |
77
|
|
|
'Datetime', |
78
|
|
|
'Event', |
79
|
|
|
'Registration' |
80
|
|
|
); |
81
|
|
|
foreach ($models_with_calculated_fields as $model_name) { |
82
|
|
|
$calculator = $this->factory->createFromModel($model_name); |
83
|
|
|
foreach (array_keys(call_user_func(array($calculator, 'schemaForCalculations'))) as $field_name) { |
84
|
|
|
$mapping[ $model_name ][ $field_name ] = get_class($calculator); |
85
|
|
|
} |
86
|
|
|
} |
87
|
|
|
return apply_filters( |
88
|
|
|
'FHEE__EventEspresso\core\libraries\rest_api\Calculated_Model_Fields__mapping', |
89
|
|
|
$mapping |
90
|
|
|
); |
91
|
|
|
} |
92
|
|
|
|
93
|
|
|
|
94
|
|
|
/** |
95
|
|
|
* Generates the schema for each calculation index in the calculation map. |
96
|
|
|
* |
97
|
|
|
* @return array |
98
|
|
|
* @throws UnexpectedEntityException |
99
|
|
|
*/ |
100
|
|
|
protected function generateNewMappingSchema() |
101
|
|
|
{ |
102
|
|
|
$schema_map = array(); |
103
|
|
|
foreach ($this->mapping() as $map_model => $map_for_model) { |
104
|
|
|
/** |
105
|
|
|
* @var string $calculation_index |
106
|
|
|
* @var string $calculations_class |
107
|
|
|
*/ |
108
|
|
|
foreach ($map_for_model as $calculation_index => $calculations_class) { |
109
|
|
|
$calculator = $this->factory->createFromClassname($calculations_class); |
110
|
|
|
$schema = call_user_func(array($calculator, 'schemaForCalculation'), $calculation_index); |
111
|
|
|
if (! empty($schema)) { |
112
|
|
|
$schema_map[ $map_model ][ $calculation_index ] = $schema; |
113
|
|
|
} |
114
|
|
|
} |
115
|
|
|
} |
116
|
|
|
return $schema_map; |
117
|
|
|
} |
118
|
|
|
|
119
|
|
|
|
120
|
|
|
/** |
121
|
|
|
* Gets the known calculated fields for model |
122
|
|
|
* |
123
|
|
|
* @param EEM_Base $model |
124
|
|
|
* @return array allowable values for this field |
125
|
|
|
*/ |
126
|
|
|
public function retrieveCalculatedFieldsForModel(EEM_Base $model) |
127
|
|
|
{ |
128
|
|
|
$mapping = $this->mapping(); |
129
|
|
|
if (isset($mapping[ $model->get_this_model_name() ])) { |
130
|
|
|
return array_keys($mapping[ $model->get_this_model_name() ]); |
131
|
|
|
} |
132
|
|
|
return array(); |
133
|
|
|
} |
134
|
|
|
|
135
|
|
|
|
136
|
|
|
/** |
137
|
|
|
* Returns the JsonSchema for the calculated fields on the given model. |
138
|
|
|
* @param EEM_Base $model |
139
|
|
|
* @return array |
140
|
|
|
*/ |
141
|
|
|
public function getJsonSchemaForModel(EEM_Base $model) |
142
|
|
|
{ |
143
|
|
|
if (! $this->mapping_schema) { |
|
|
|
|
144
|
|
|
$this->mapping_schema = $this->generateNewMappingSchema(); |
145
|
|
|
} |
146
|
|
|
return array( |
147
|
|
|
'description' => esc_html__( |
148
|
|
|
'Available calculated fields for this model. Fields are only present in the response if explicitly requested', |
149
|
|
|
'event_espresso' |
150
|
|
|
), |
151
|
|
|
'type' => 'object', |
152
|
|
|
'properties' => isset($this->mapping_schema[ $model->get_this_model_name() ]) |
153
|
|
|
? $this->mapping_schema[ $model->get_this_model_name() ] |
154
|
|
|
: array(), |
155
|
|
|
'additionalProperties' => false, |
156
|
|
|
'readonly' => true, |
157
|
|
|
); |
158
|
|
|
} |
159
|
|
|
|
160
|
|
|
|
161
|
|
|
/** |
162
|
|
|
* Retrieves the value for this calculation |
163
|
|
|
* |
164
|
|
|
* @param EEM_Base $model |
165
|
|
|
* @param string $field_name |
166
|
|
|
* @param array $wpdb_row |
167
|
|
|
* @param $rest_request |
168
|
|
|
* @param BaseController $controller |
169
|
|
|
* @return mixed|null |
170
|
|
|
* @throws RestException |
171
|
|
|
* @throws UnexpectedEntityException |
172
|
|
|
*/ |
173
|
|
|
public function retrieveCalculatedFieldValue( |
174
|
|
|
EEM_Base $model, |
175
|
|
|
$field_name, |
176
|
|
|
$wpdb_row, |
177
|
|
|
$rest_request, |
178
|
|
|
Base $controller |
179
|
|
|
) { |
180
|
|
|
$mapping = $this->mapping(); |
181
|
|
|
if (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
|
|
|
__('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
|
|
|
} |
199
|
|
|
|
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.
Consider making the comparison explicit by using
empty(..)
or! empty(...)
instead.