1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/** |
4
|
|
|
* . |
5
|
|
|
* |
6
|
|
|
* @package wordpoints-hooks-api |
7
|
|
|
* @since 1. |
8
|
|
|
*/ |
9
|
|
|
|
10
|
|
|
// this is basicaly a router. |
11
|
|
|
class WordPoints_Entity_chang_trigger implements WordPoints_Entity_Change_ListenerI { |
12
|
|
|
|
13
|
|
|
public function created( WordPoints_Entity $entity ) { |
14
|
|
|
// can multiple entities be created at once? not using insert() but via query() |
15
|
|
|
// maybe? and how shoudl we handle that, all at once or one by one? |
16
|
|
|
|
17
|
|
|
/** @var WordPoints_Entity_Change_ListenerI[] $listeners */ |
18
|
|
|
$listeners = wordpoints_apps()->sub_apps->get( 'entity_change_listeners' ); |
19
|
|
|
foreach ( $listeners as $listener ) { |
20
|
|
|
$listener->created( $entity ); |
21
|
|
|
} |
22
|
|
|
} |
23
|
|
|
|
24
|
|
|
|
25
|
|
|
public function updated( WordPoints_Entity $before, WordPoints_Entity $after ) { |
26
|
|
|
|
27
|
|
|
// what if multiple entities are updated at once? do we run each one separatately? |
28
|
|
|
// mayb ethat should be left up to the listenter. |
29
|
|
|
// and likewise wherther we handle the entity modifications attribute by attribute. |
30
|
|
|
} |
31
|
|
|
|
32
|
|
|
|
33
|
|
|
public function deleted( WordPoints_Entity $entity ) { |
34
|
|
|
|
35
|
|
|
// what if we need information about this entitie's relationships, etc., that |
36
|
|
|
// isn't included inthe entity object? |
37
|
|
|
// this is a problem for the hooks api, but not for the possession api. |
38
|
|
|
// but hwat about other potential apis? |
39
|
|
|
// of course, there is no guarantee that the relationships will be deleted |
40
|
|
|
// first, but there is no guarantee that they won't, either. |
41
|
|
|
// but i suppose that our excuse is that any API should be listening to |
42
|
|
|
// entity changes as well if it needs to know about such things. |
43
|
|
|
// but when something is deleted, then such apis will be triggered many times |
44
|
|
|
// right in a row. not ideal, but it isn't as if things are constantly being |
45
|
|
|
// deleted. but if we had a retroactive api, we could just temporarily |
46
|
|
|
// suspend running the listeners and then trigger things after all of the |
47
|
|
|
// queries were done. for a single entity it wouldn't be worth it, but maybe |
48
|
|
|
// for a bunch of entities deleted at once. but that isn't a cross-api think, |
49
|
|
|
// just mainly for the hooks/possession apis. though really is suppose that |
50
|
|
|
// it sis a part of the entity api, in terms of the queries, but we have to |
51
|
|
|
// have some sor of logs in order to be able to use it idempotently. |
52
|
|
|
|
53
|
|
|
// just running before delte wouldn't work either, because the relatinships |
54
|
|
|
// would have alrady been severed then if they are severed before deletion. |
55
|
|
|
} |
56
|
|
|
|
57
|
|
|
} |
58
|
|
|
|
59
|
|
|
// this is basically a reactor |
60
|
|
|
interface WordPoints_Entity_Change_ListenerI { |
61
|
|
|
public function created( WordPoints_Entity $entity ); |
62
|
|
|
public function updated( WordPoints_Entity $before, WordPoints_Entity $after ); |
63
|
|
|
public function deleted( WordPoints_Entity $entity ); |
64
|
|
|
} |
65
|
|
|
|
66
|
|
|
class WordPoints_Entity_Change_Listener_Hooks implements WordPoints_Entity_Change_ListenerI { |
67
|
|
|
|
68
|
|
|
public function created( WordPoints_Entity $entity ) { |
69
|
|
|
|
70
|
|
|
// maybe we would have multuiple events with requirements for a single entity? |
71
|
|
|
// like comment author and post commentn author targets for the same hook. |
72
|
|
|
// but I guess taht is just one event. |
73
|
|
|
// what about user register vs user create on MS? |
74
|
|
|
if ( $this->matches_requirements( $entity ) ) { |
75
|
|
|
$this->fire_event( 'add', $entity ); |
76
|
|
|
} |
77
|
|
|
} |
78
|
|
|
|
79
|
|
|
public function updated( WordPoints_Entity $before, WordPoints_Entity $after ) { |
80
|
|
|
|
81
|
|
|
if ( $this->matches_requirements( $after ) ) { |
82
|
|
|
if ( ! $this->matches_requirements( $before ) ) { |
83
|
|
|
$this->fire_event( 'add', $after ); |
84
|
|
|
} |
85
|
|
|
} else { |
86
|
|
|
if ( $this->matches_requirements( $before ) ) { |
87
|
|
|
$this->fire_event( 'remove', $after ); |
88
|
|
|
} |
89
|
|
|
} |
90
|
|
|
} |
91
|
|
|
|
92
|
|
|
public function deleted( WordPoints_Entity $entity ) { |
93
|
|
|
|
94
|
|
|
if ( $this->matches_requirements( $entity ) ) { |
95
|
|
|
$this->fire_event( 'remove', $entity ); |
96
|
|
|
} |
97
|
|
|
} |
98
|
|
|
|
99
|
|
|
// ideally we would actually check the conditions for each reaction here. |
100
|
|
|
// however, that will likely just have to be a bug/edge-case until the new |
101
|
|
|
// api is introduced. |
102
|
|
|
// ahve we ever considered what happens when an entity has been modified to not |
103
|
|
|
// match the conditions anymore before it is deleted? but that doesn't pose a |
104
|
|
|
// problem in teh hooks api usually, because before we were just reversing based |
105
|
|
|
// on the hook logs. so we didnt' check if the entity matched teh conditions at |
106
|
|
|
// all. |
107
|
|
|
// so the whole issue with relationships being deleted before the hooks api was |
108
|
|
|
// called into play when the entity itself is deleted is moot, because the |
109
|
|
|
// reltionships, etc., aren't even taken into account when toggle-off is called, |
110
|
|
|
// in the points reactor. other reators might, i guess. |
111
|
|
|
protected function matches_requirements( WordPoints_Entity $entity ) { |
112
|
|
|
|
113
|
|
|
/** @var WordPoints_Class_Registry $defaults */ |
114
|
|
|
$defaults = wordpoints_apps()->sub_apps->get( 'entity_possession_defaults' ); |
115
|
|
|
|
116
|
|
|
$defaults = $defaults->get( $entity->get_slug() ); |
117
|
|
|
|
118
|
|
|
if ( ! $defaults ) { |
119
|
|
|
return false; |
120
|
|
|
} |
121
|
|
|
|
122
|
|
|
// use conditions here? |
123
|
|
|
foreach ( $defaults as $child => $value ) { |
124
|
|
|
if ( $entity->get_child( $child ) !== $value ) { |
125
|
|
|
return false; |
126
|
|
|
} |
127
|
|
|
} |
128
|
|
|
|
129
|
|
|
return true; |
130
|
|
|
} |
131
|
|
|
|
132
|
|
|
protected function fire_event( $type, WordPoints_Entity $entity ) { |
133
|
|
|
|
134
|
|
|
$args = new WordPoints_Hook_Event_Args( array() ); |
135
|
|
|
$args->add_entity( $entity ); |
136
|
|
|
|
137
|
|
|
wordpoints_hooks()->fire( |
138
|
|
|
$type . '_entity_' . $entity->get_slug(), |
139
|
|
|
$args, |
140
|
|
|
'toggle_on' |
141
|
|
|
); |
142
|
|
|
} |
143
|
|
|
} |
144
|
|
|
|
145
|
|
|
class WordPoints_Entity_Change_Listener_Points implements WordPoints_Entity_Change_ListenerI { |
146
|
|
|
|
147
|
|
|
public function created( WordPoints_Entity $entity ) { |
148
|
|
|
|
149
|
|
|
$this->process_entityish( |
150
|
|
|
$entity |
151
|
|
|
, $this->get_settings_for_entity( $entity ) |
|
|
|
|
152
|
|
|
); |
153
|
|
|
} |
154
|
|
|
|
155
|
|
|
protected function process_entityish( WordPoints_EntityishI $entity, $settings ) { |
156
|
|
|
|
157
|
|
|
// possibly make this more like extension handling |
158
|
|
|
if ( ! $this->meets_conditions( $entity, $settings['conditions'] ) ) { |
159
|
|
|
return; |
160
|
|
|
} |
161
|
|
|
|
162
|
|
|
// possibly make this more like reactor handling. |
163
|
|
|
$this->award_points( $settings ); |
164
|
|
|
|
165
|
|
|
// only proces the attributes taht have changed. |
166
|
|
|
// acutally, in this case, the entity was just created. |
167
|
|
|
if ( $entity instanceof WordPoints_Entity_ParentI ) { |
168
|
|
|
|
169
|
|
|
// this check runs on attributes only. |
170
|
|
|
foreach ( $settings['children'] as $child_slug => $child_settings ) { |
171
|
|
|
$this->process_entityish( $entity->get_child( $child_slug ), $child_settings ); |
172
|
|
|
} |
173
|
|
|
|
174
|
|
|
// we also need to check for any children, like relationships, that have |
175
|
|
|
// the settings stored separately. |
176
|
|
|
// for this we need a list of relationships. |
177
|
|
|
// if we do two-way relationships, we may need to have infinite-loop |
178
|
|
|
// halding here, depending. |
179
|
|
|
foreach ( $this->get_related_entities( $entity ) as $child_entity ) { |
180
|
|
|
// If a comment was just created, for example, and we have conditions |
181
|
|
|
// on the post entity, that affect the comment author, this allows |
182
|
|
|
// us to handle those by pulling up the settings for the post entity |
183
|
|
|
// and looping through them too. |
184
|
|
|
// however, we need to limit this to only awarding the comment author |
185
|
|
|
// don't we? But maybe not, because what about when the post awards |
186
|
|
|
// are conditioned on the post's comments? but then the data would |
187
|
|
|
// just be on the comment but with the post author as the target. |
188
|
|
|
// But we still need to have some way of limiting this to only |
189
|
|
|
// targets relating to the comment. |
190
|
|
|
// I suppose taht maybe it is as simple as continuing to pass the |
191
|
|
|
// entity hierarchy with the comment at the top around, which when |
192
|
|
|
// we attempt to get the target with get_from_hierarchy() will only |
193
|
|
|
// return a value if the target is the comment author. That would be |
194
|
|
|
// even better/easier if the settings were indexed by target somehow |
195
|
|
|
// as we've proposed... |
196
|
|
|
$this->process_entityish( |
197
|
|
|
$child_entity |
198
|
|
|
, $this->get_entity_settings( $child_entity ) |
|
|
|
|
199
|
|
|
); |
200
|
|
|
} |
201
|
|
|
} |
202
|
|
|
} |
203
|
|
|
|
204
|
|
|
// do we also listen for relationship changes, or is that a separate api? |
205
|
|
|
// I guess we do listen for some, but only because they happen to be defined on |
206
|
|
|
// entity attributes. |
207
|
|
|
|
208
|
|
|
// and are these only whole entities, or can they be just atts? I guess taht |
209
|
|
|
// doesn't really make sense. |
210
|
|
|
// I think relationships can be created and deleted, but not really updated. |
211
|
|
|
// so maybe what we need is a separate api? |
212
|
|
|
public function updated( WordPoints_Entity $before, WordPoints_Entity $after ) { |
213
|
|
|
|
214
|
|
|
$settings = $this->get_settings_for_entity( $before ); |
|
|
|
|
215
|
|
|
|
216
|
|
|
/** @var WordPoints_Class_Registry_ChildrenI $children */ |
217
|
|
|
$children = wordpoints_entities()->children; |
|
|
|
|
218
|
|
|
foreach ( $children->get_children_slugs( $before->get_slug() ) as $child_slug ) { |
219
|
|
|
|
220
|
|
|
if ( ! isset( $settings['children'][ $child_slug ] ) ) { |
221
|
|
|
continue; |
222
|
|
|
} |
223
|
|
|
|
224
|
|
|
// which ones are attributes and which are not? |
225
|
|
|
// I guess we just check the atts. |
226
|
|
|
// but it isn't as simple as that, because the atts don't necessarilly |
227
|
|
|
// match the names of the children. |
228
|
|
|
// so we could just pull up the child and check if it is an instanceof |
229
|
|
|
// the correct class. that seems expensive, but we need them anyway (see |
230
|
|
|
// below), and maybe if we have a list of relatinoships we could check |
231
|
|
|
// that too. |
232
|
|
|
// but then we'll not be checking even the relationships taht are defined |
233
|
|
|
// on the atts. so we have to decide whether those should be handled by |
234
|
|
|
// a separate api or not. |
235
|
|
|
if ( $before->get_the_attr_value( $child_slug ) === $after->get_the_attr_value( $child_slug ) ) { |
236
|
|
|
continue; |
237
|
|
|
} |
238
|
|
|
|
239
|
|
|
$this->process_modified_entityish( |
240
|
|
|
$before->get_child( $child_slug ) |
|
|
|
|
241
|
|
|
, $after->get_child( $child_slug ) |
|
|
|
|
242
|
|
|
, $settings['children'][ $child_slug ] |
243
|
|
|
); |
244
|
|
|
} |
245
|
|
|
} |
246
|
|
|
|
247
|
|
|
protected function process_modified_entityish( WordPoints_EntityishI $before, WordPoints_EntityishI $after, $settings ) { |
248
|
|
|
|
249
|
|
|
if ( ! $this->meets_conditions( $before, $settings['conditions'] ) ) { |
250
|
|
|
if ( $this->meets_conditions( $after, $settings['conditions'] ) ) { |
251
|
|
|
$this->award_points( $settings ); |
252
|
|
|
|
253
|
|
|
// also need to process other eneities that are affected by this |
254
|
|
|
// change, which may have conditions on this, i.e., that could be |
255
|
|
|
// parents of this enity. |
256
|
|
|
// that's actually only true for relationship/cascading handling. |
257
|
|
|
// otherwise we are actually fine here, since parent/child entities |
258
|
|
|
// will have points awarded by the targets. |
259
|
|
|
// but say taht this is a post, and on the user entity there is a |
260
|
|
|
// condition that the comment authors are to be awarded based on a |
261
|
|
|
// certain attribute of the post author. if the post author has |
262
|
|
|
// changed, that needs to be processed. however, that is a |
263
|
|
|
// relationship change, so maybe it will come thorugh a different |
264
|
|
|
// api. if not, we need to check if this is a relationship here and |
265
|
|
|
// then we do indeed need to run through the children/parents. |
266
|
|
|
} |
267
|
|
|
} else { |
268
|
|
|
if ( ! $this->meets_conditions( $after, $settings['conditions'] ) ) { |
269
|
|
|
$this->remove_points( $settings ); |
|
|
|
|
270
|
|
|
} |
271
|
|
|
} |
272
|
|
|
} |
273
|
|
|
|
274
|
|
|
public function deleted( WordPoints_Entity $entity ) { |
275
|
|
|
// basically the opposite of created(). |
276
|
|
|
$this->process_entityish_reverse( $entity ); |
|
|
|
|
277
|
|
|
} |
278
|
|
|
|
279
|
|
|
protected function meets_conditions( WordPoints_EntityishI $entityish, $conditions ) { |
|
|
|
|
280
|
|
|
// use conditions api |
281
|
|
|
|
282
|
|
|
return false; |
283
|
|
|
} |
284
|
|
|
|
285
|
|
|
private function award_points( $settings ) { |
286
|
|
|
|
287
|
|
|
$hierarchy = new WordPoints_Entity_Hierarchy( $this->eitnty ); |
|
|
|
|
288
|
|
|
// todo we'll need to introudce entity array targets, possibly. |
289
|
|
|
// how will we know how to reverse the target reltinoship chains in the UI |
290
|
|
|
// before saving? i guess we'll need to either have a dedicated index fo taht |
291
|
|
|
// or else juust look it up by looping through the relationships (though we'd |
292
|
|
|
// have to remove the entity array {} part from any one-to-many relationships |
293
|
|
|
// and maybe we'd have to add it to others?) |
294
|
|
|
$targets = $hierarchy->get_from_hierarchy( $settings['target'] ); |
|
|
|
|
295
|
|
|
|
296
|
|
|
// maybe just one target, maybe several, depending. |
297
|
|
|
} |
298
|
|
|
|
299
|
|
|
private function get_related_entities( WordPoints_Entity $entity ) { |
|
|
|
|
300
|
|
|
|
301
|
|
|
// what we need is parental conditions. Conditions that go up the chain, |
302
|
|
|
// and look back at parent entities. This way we can handle the info about |
303
|
|
|
// comments on a particuar post when the post entity is modified, since the |
304
|
|
|
// conditions can be on the post |
305
|
|
|
// we'd need inverse relationships, get all comements for the post, and then |
306
|
|
|
// run the "paretn" conditions on each of them. |
307
|
|
|
// or just not allow conditions/reactions on relationships |
308
|
|
|
// but just registering relationships for both entities is not enough, |
309
|
|
|
// because we can't tell the slug of the entity form the slug of the entity |
310
|
|
|
// child, unless we just loop thorugh them and attempt to get that entity |
311
|
|
|
// from each relationship. |
312
|
|
|
|
313
|
|
|
return array(); |
314
|
|
|
} |
315
|
|
|
} |
316
|
|
|
|
317
|
|
|
// EOF |
318
|
|
|
|
This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.
This is most likely a typographical error or the method has been renamed.