1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/** |
4
|
|
|
* Hook reactor class. |
5
|
|
|
* |
6
|
|
|
* @package wordpoints-hooks-api |
7
|
|
|
* @since 1.0.0 |
8
|
|
|
*/ |
9
|
|
|
|
10
|
|
|
/** |
11
|
|
|
* Bootstrap for performing pre-scripted reactions when an event is fired. |
12
|
|
|
* |
13
|
|
|
* When a hook event fires, it is the job of the reactor to perform the action |
14
|
|
|
* specified for each reaction object. For most reactors this means that they must |
15
|
|
|
* "hit" a "target". For example, it might award points to a particular user. |
16
|
|
|
* |
17
|
|
|
* @since 1.0.0 |
18
|
|
|
* |
19
|
|
|
* @property-read WordPoints_Hook_Reaction_StorageI|null $reactions |
20
|
|
|
* Object for accessing hook reactions for this reactor based on the |
21
|
|
|
* current network mode. If a reactor doesn't support network |
22
|
|
|
* reactions and network mode is on, this property is not available. |
23
|
|
|
* |
24
|
|
|
* @property-read WordPoints_Hook_Reaction_StorageI|null $standard_reactions |
25
|
|
|
* Object for accessing standard hook reactions for this reactor. Not |
26
|
|
|
* available when network mode is on. |
27
|
|
|
* |
28
|
|
|
* @property-read WordPoints_Hook_Reaction_StorageI|null $network_reactions |
29
|
|
|
* Object for accessing network hook reactions for this reactor. May |
30
|
|
|
* not be available for all reactors. |
31
|
|
|
*/ |
32
|
|
|
abstract class WordPoints_Hook_Reactor implements WordPoints_Hook_SettingsI { |
33
|
|
|
|
34
|
|
|
/** |
35
|
|
|
* The unique slug identifying this hook reactor. |
36
|
|
|
* |
37
|
|
|
* @since 1.0.0 |
38
|
|
|
* |
39
|
|
|
* @var string |
40
|
|
|
*/ |
41
|
|
|
protected $slug; |
42
|
|
|
|
43
|
|
|
/** |
44
|
|
|
* The types of args that this reactor can target. |
45
|
|
|
* |
46
|
|
|
* @since 1.0.0 |
47
|
|
|
* |
48
|
|
|
* @var string|string[] |
49
|
|
|
*/ |
50
|
|
|
protected $arg_types; |
51
|
|
|
|
52
|
|
|
/** |
53
|
|
|
* The settings fields used by this reactor. |
54
|
|
|
* |
55
|
|
|
* @since 1.0.0 |
56
|
|
|
* |
57
|
|
|
* @var array |
58
|
|
|
*/ |
59
|
|
|
protected $settings_fields; |
60
|
|
|
|
61
|
|
|
/** |
62
|
|
|
* The storage object for the standard reactions. |
63
|
|
|
* |
64
|
|
|
* @since 1.0.0 |
65
|
|
|
* |
66
|
|
|
* @var WordPoints_Hook_Reaction_StorageI |
67
|
|
|
*/ |
68
|
|
|
protected $standard_reactions; |
69
|
|
|
|
70
|
|
|
/** |
71
|
|
|
* The storage object for the network-wide reactions. |
72
|
|
|
* |
73
|
|
|
* @since 1.0.0 |
74
|
|
|
* |
75
|
|
|
* @var WordPoints_Hook_Reaction_StorageI |
76
|
|
|
*/ |
77
|
|
|
protected $network_reactions; |
78
|
|
|
|
79
|
|
|
/** |
80
|
|
|
* The reaction storage class this reactor uses. |
81
|
|
|
* |
82
|
|
|
* @since 1.0.0 |
83
|
|
|
* |
84
|
|
|
* @var string |
85
|
|
|
*/ |
86
|
|
|
protected $standard_reactions_class = 'WordPoints_Hook_Reaction_Storage_Options'; |
87
|
|
|
|
88
|
|
|
/** |
89
|
|
|
* The network reaction storage class this reactor uses. |
90
|
|
|
* |
91
|
|
|
* @since 1.0.0 |
92
|
|
|
* |
93
|
|
|
* @var string |
94
|
|
|
*/ |
95
|
|
|
protected $network_reactions_class = 'WordPoints_Hook_Reaction_Storage_Options_Network'; |
96
|
|
|
|
97
|
|
|
/** |
98
|
|
|
* @since 1.0.0 |
99
|
|
|
*/ |
100
|
|
|
public function __get( $var ) { |
101
|
|
|
|
102
|
|
|
if ( 'reactions' === $var ) { |
103
|
|
|
$mode = wordpoints_hooks()->get_current_mode(); |
104
|
|
|
$var = "{$mode}_reactions"; |
105
|
|
|
} elseif ( '_reactions' !== substr( $var, -10 ) ) { |
106
|
|
|
return null; |
107
|
|
|
} else { |
108
|
|
|
$mode = substr( $var, 0, -10 /* _reactions */ ); |
109
|
|
|
} |
110
|
|
|
|
111
|
|
|
if ( 'network_reactions' === $var && ! $this->is_network_wide() ) { |
112
|
|
|
return null; |
113
|
|
|
} |
114
|
|
|
|
115
|
|
|
if ( ! isset( $this->$var ) ) { |
116
|
|
|
|
117
|
|
|
if ( isset( $this->{"{$var}_class"} ) ) { |
118
|
|
|
$this->$var = new $this->{"{$var}_class"}( $mode, $this ); |
119
|
|
|
} else { |
120
|
|
|
return null; |
121
|
|
|
} |
122
|
|
|
} |
123
|
|
|
|
124
|
|
|
$store = $this->$var; |
125
|
|
|
|
126
|
|
|
if ( ! $store instanceof WordPoints_Hook_Reaction_StorageI ) { |
127
|
|
|
return null; |
128
|
|
|
} |
129
|
|
|
|
130
|
|
|
// Allowing access to stores out-of-context would lead to strange behavior. |
131
|
|
|
if ( false === $store->get_context_id() ) { |
132
|
|
|
return null; |
133
|
|
|
} |
134
|
|
|
|
135
|
|
|
return $store; |
136
|
|
|
} |
137
|
|
|
|
138
|
|
|
/** |
139
|
|
|
* Get the slug of this reactor. |
140
|
|
|
* |
141
|
|
|
* @since 1.0.0 |
142
|
|
|
* |
143
|
|
|
* @return string The reactor's slug. |
144
|
|
|
*/ |
145
|
|
|
public function get_slug() { |
146
|
|
|
return $this->slug; |
147
|
|
|
} |
148
|
|
|
|
149
|
|
|
/** |
150
|
|
|
* Get a list of the slugs of each type of arg that this reactor supports. |
151
|
|
|
* |
152
|
|
|
* @since 1.0.0 |
153
|
|
|
* |
154
|
|
|
* @return string[] The slugs of the arg types this reactor supports. |
155
|
|
|
*/ |
156
|
|
|
public function get_arg_types() { |
157
|
|
|
return (array) $this->arg_types; |
158
|
|
|
} |
159
|
|
|
|
160
|
|
|
/** |
161
|
|
|
* Get the settings fields used by the reactor. |
162
|
|
|
* |
163
|
|
|
* @since 1.0.0 |
164
|
|
|
* |
165
|
|
|
* @return string[] The meta keys used to store this reactor's settings. |
166
|
|
|
*/ |
167
|
|
|
public function get_settings_fields() { |
168
|
|
|
return $this->settings_fields; |
169
|
|
|
} |
170
|
|
|
|
171
|
|
|
/** |
172
|
|
|
* Check whether this reactor is network-wide. |
173
|
|
|
* |
174
|
|
|
* When a reactor is not network-wide, network reactions are not supported. For |
175
|
|
|
* example, the points reactor is not network-wide when WordPoints isn't network- |
176
|
|
|
* active, because the points types are created per-site. We default all reactors |
177
|
|
|
* to being network wide only when WordPoints is network-active, but some may |
178
|
|
|
* need to override this. |
179
|
|
|
* |
180
|
|
|
* @since 1.0.0 |
181
|
|
|
* |
182
|
|
|
* @return bool Whether this reactor is network-wide. |
183
|
|
|
*/ |
184
|
|
|
public function is_network_wide() { |
185
|
|
|
return is_wordpoints_network_active(); |
186
|
|
|
} |
187
|
|
|
|
188
|
|
|
/** |
189
|
|
|
* Get all reactions to a particular event for this reactor. |
190
|
|
|
* |
191
|
|
|
* On multisite it will return all reactions for the current site, both standard |
192
|
|
|
* ones and any network-wide ones (if this reactor offers a network storage |
193
|
|
|
* class). Or, if network mode is on, it will return only the network-wide ones. |
194
|
|
|
* |
195
|
|
|
* @since 1.0.0 |
196
|
|
|
* |
197
|
|
|
* @param string $event_slug The event slug. |
198
|
|
|
* |
199
|
|
|
* @return WordPoints_Hook_ReactionI[] All of the reaction objects. |
200
|
|
|
*/ |
201
|
|
View Code Duplication |
public function get_all_reactions_to_event( $event_slug ) { |
|
|
|
|
202
|
|
|
|
203
|
|
|
$reactions = array(); |
204
|
|
|
|
205
|
|
|
foreach ( array( 'standard', 'network' ) as $store ) { |
206
|
|
|
|
207
|
|
|
$storage = $this->{"{$store}_reactions"}; |
208
|
|
|
|
209
|
|
|
if ( ! $storage instanceof WordPoints_Hook_Reaction_StorageI ) { |
210
|
|
|
continue; |
211
|
|
|
} |
212
|
|
|
|
213
|
|
|
$reactions = array_merge( |
214
|
|
|
$reactions |
215
|
|
|
, $storage->get_reactions_to_event( $event_slug ) |
216
|
|
|
); |
217
|
|
|
} |
218
|
|
|
|
219
|
|
|
return $reactions; |
220
|
|
|
} |
221
|
|
|
|
222
|
|
|
/** |
223
|
|
|
* Get all reactions for this reactor. |
224
|
|
|
* |
225
|
|
|
* On multisite it will return all reactions for the current site, both standard |
226
|
|
|
* ones and any network-wide ones (if this reactor offers a network storage |
227
|
|
|
* class). Or, if network mode is on, it will return only the network-wide ones. |
228
|
|
|
* |
229
|
|
|
* @since 1.0.0 |
230
|
|
|
* |
231
|
|
|
* @return WordPoints_Hook_ReactionI[] All of the reaction objects. |
232
|
|
|
*/ |
233
|
|
View Code Duplication |
public function get_all_reactions() { |
|
|
|
|
234
|
|
|
|
235
|
|
|
$reactions = array(); |
236
|
|
|
|
237
|
|
|
foreach ( array( 'standard', 'network' ) as $store ) { |
238
|
|
|
|
239
|
|
|
$storage = $this->{"{$store}_reactions"}; |
240
|
|
|
|
241
|
|
|
if ( ! $storage instanceof WordPoints_Hook_Reaction_StorageI ) { |
242
|
|
|
continue; |
243
|
|
|
} |
244
|
|
|
|
245
|
|
|
$reactions = array_merge( $reactions, $storage->get_reactions() ); |
246
|
|
|
} |
247
|
|
|
|
248
|
|
|
return $reactions; |
249
|
|
|
} |
250
|
|
|
|
251
|
|
|
/** |
252
|
|
|
* @since 1.0.0 |
253
|
|
|
*/ |
254
|
|
|
public function validate_settings( |
255
|
|
|
array $settings, |
256
|
|
|
WordPoints_Hook_Reaction_Validator $validator, |
257
|
|
|
WordPoints_Hook_Event_Args $event_args |
258
|
|
|
) { |
259
|
|
|
|
260
|
|
|
if ( |
261
|
|
|
empty( $settings['target'] ) |
262
|
|
|
|| ! is_array( $settings['target'] ) |
263
|
|
|
) { |
264
|
|
|
|
265
|
|
|
$validator->add_error( __( 'Invalid target.', 'wordpoints' ), 'target' ); |
266
|
|
|
|
267
|
|
|
} else { |
268
|
|
|
|
269
|
|
|
$target = $event_args->get_from_hierarchy( $settings['target'] ); |
270
|
|
|
|
271
|
|
|
if ( |
272
|
|
|
! $target instanceof WordPoints_Entity |
273
|
|
|
|| ! in_array( $target->get_slug(), (array) $this->arg_types ) |
274
|
|
|
) { |
275
|
|
|
$validator->add_error( __( 'Invalid target.', 'wordpoints' ), 'target' ); |
276
|
|
|
} |
277
|
|
|
} |
278
|
|
|
|
279
|
|
|
return $settings; |
280
|
|
|
} |
281
|
|
|
|
282
|
|
|
/** |
283
|
|
|
* @since 1.0.0 |
284
|
|
|
*/ |
285
|
|
|
public function update_settings( WordPoints_Hook_ReactionI $reaction, array $settings ) { |
286
|
|
|
$reaction->update_meta( 'target', $settings['target'] ); |
287
|
|
|
} |
288
|
|
|
|
289
|
|
|
/** |
290
|
|
|
* Perform an action when the reactor is hit by an event being fired. |
291
|
|
|
* |
292
|
|
|
* @since 1.0.0 |
293
|
|
|
* |
294
|
|
|
* @param WordPoints_Hook_Event_Args $event_args The event args. |
295
|
|
|
* @param WordPoints_Hook_ReactionI $reaction The reaction. |
296
|
|
|
*/ |
297
|
|
|
abstract public function hit( |
298
|
|
|
WordPoints_Hook_Event_Args $event_args, |
299
|
|
|
WordPoints_Hook_ReactionI $reaction |
300
|
|
|
); |
301
|
|
|
} |
302
|
|
|
|
303
|
|
|
// EOF |
304
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.