1 | <?php |
||||
2 | |||||
3 | namespace Elgg\Database; |
||||
4 | |||||
5 | use Elgg\Database; |
||||
6 | use Elgg\Database\Clauses\AnnotationWhereClause; |
||||
7 | use Elgg\EventsService; |
||||
8 | use ElggAnnotation; |
||||
9 | use ElggEntity; |
||||
10 | |||||
11 | /** |
||||
12 | * Interfaces with the database to perform CRUD operations on annotations |
||||
13 | * |
||||
14 | * WARNING: API IN FLUX. DO NOT USE DIRECTLY. |
||||
15 | * |
||||
16 | * @access private |
||||
17 | */ |
||||
18 | class AnnotationsTable { |
||||
19 | |||||
20 | use \Elgg\TimeUsing; |
||||
21 | |||||
22 | /** |
||||
23 | * @var Database |
||||
24 | */ |
||||
25 | protected $db; |
||||
26 | |||||
27 | /** |
||||
28 | * @var EventsService |
||||
29 | */ |
||||
30 | protected $events; |
||||
31 | |||||
32 | /** |
||||
33 | * Constructor |
||||
34 | * |
||||
35 | * @param Database $db Database |
||||
36 | * @param EventsService $events Events |
||||
37 | */ |
||||
38 | 4419 | public function __construct(Database $db, EventsService $events) { |
|||
39 | 4419 | $this->db = $db; |
|||
40 | 4419 | $this->events = $events; |
|||
41 | 4419 | } |
|||
42 | |||||
43 | /** |
||||
44 | * Get a specific annotation by its id |
||||
45 | * |
||||
46 | * @param int $id The id of the annotation object |
||||
47 | * |
||||
48 | * @return ElggAnnotation|false |
||||
49 | */ |
||||
50 | 8 | public function get($id) { |
|||
51 | 8 | $qb = Select::fromTable('annotations'); |
|||
52 | 8 | $qb->select('*'); |
|||
53 | |||||
54 | 8 | $where = new AnnotationWhereClause(); |
|||
55 | 8 | $where->ids = $id; |
|||
1 ignored issue
–
show
|
|||||
56 | 8 | $qb->addClause($where); |
|||
57 | |||||
58 | 8 | $row = $this->db->getDataRow($qb); |
|||
59 | 8 | if ($row) { |
|||
1 ignored issue
–
show
The expression
$row of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.
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
Loading history...
|
|||||
60 | 8 | return new ElggAnnotation($row); |
|||
61 | } |
||||
62 | |||||
63 | 1 | return false; |
|||
64 | } |
||||
65 | |||||
66 | /** |
||||
67 | * Deletes an annotation using its ID |
||||
68 | * |
||||
69 | * @param ElggAnnotation $annotation Annotation |
||||
70 | * |
||||
71 | * @return bool |
||||
72 | */ |
||||
73 | 30 | public function delete(ElggAnnotation $annotation) { |
|||
74 | 30 | if (!$annotation->canEdit()) { |
|||
75 | return false; |
||||
76 | } |
||||
77 | |||||
78 | 30 | if (!$this->events->trigger('delete', 'annotation', $annotation)) { |
|||
79 | return false; |
||||
80 | } |
||||
81 | |||||
82 | 30 | $qb = Delete::fromTable('annotations'); |
|||
83 | 30 | $qb->where($qb->compare('id', '=', $annotation->id, ELGG_VALUE_INTEGER)); |
|||
84 | 30 | $deleted = $this->db->deleteData($qb); |
|||
85 | |||||
86 | 30 | if ($deleted) { |
|||
87 | 30 | elgg_delete_river([ |
|||
88 | 30 | 'annotation_id' => $annotation->id, |
|||
89 | 'limit' => false, |
||||
90 | ]); |
||||
91 | } |
||||
92 | |||||
93 | 30 | return $deleted; |
|||
0 ignored issues
–
show
|
|||||
94 | } |
||||
95 | |||||
96 | /** |
||||
97 | * Create a new annotation and return its ID |
||||
98 | * |
||||
99 | * @param ElggAnnotation $annotation Annotation |
||||
100 | * @param ElggEntity $entity Entity being annotated |
||||
101 | * |
||||
102 | * @return int|bool |
||||
103 | */ |
||||
104 | 118 | public function create(ElggAnnotation $annotation, ElggEntity $entity) { |
|||
105 | 118 | if ($annotation->id) { |
|||
106 | return $this->update($annotation); |
||||
107 | } |
||||
108 | |||||
109 | 118 | $annotation->entity_guid = $entity->guid; |
|||
110 | |||||
111 | // @todo It looks like annotations permissions are not being checked anywhere... |
||||
112 | // Uncomment once tests have been updated |
||||
113 | // See #11418 |
||||
114 | //if (!$entity->canAnnotate(0, $annotation->name)) { |
||||
115 | // return false; |
||||
116 | //} |
||||
117 | |||||
118 | 118 | if (!$this->events->trigger('annotate', $entity->getType(), $entity)) { |
|||
119 | return false; |
||||
120 | } |
||||
121 | |||||
122 | 118 | if (!$this->events->triggerBefore('create', 'annotation', $annotation)) { |
|||
0 ignored issues
–
show
$annotation of type ElggAnnotation is incompatible with the type string expected by parameter $object of Elgg\EventsService::triggerBefore() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||
123 | return false; |
||||
124 | } |
||||
125 | |||||
126 | 118 | $time_created = $this->getCurrentTime()->getTimestamp(); |
|||
127 | |||||
128 | 118 | $qb = Insert::intoTable('annotations'); |
|||
129 | 118 | $qb->values([ |
|||
130 | 118 | 'entity_guid' => $qb->param($annotation->entity_guid, ELGG_VALUE_INTEGER), |
|||
131 | 118 | 'name' => $qb->param($annotation->name, ELGG_VALUE_STRING), |
|||
132 | 118 | 'value' => $qb->param($annotation->value, $annotation->value_type === 'integer' ? ELGG_VALUE_INTEGER : ELGG_VALUE_STRING), |
|||
133 | 118 | 'value_type' => $qb->param($annotation->value_type, ELGG_VALUE_STRING), |
|||
134 | 118 | 'owner_guid' => $qb->param($annotation->owner_guid, ELGG_VALUE_INTEGER), |
|||
135 | 118 | 'time_created' => $qb->param($time_created, ELGG_VALUE_INTEGER), |
|||
136 | 118 | 'access_id' => $qb->param($annotation->access_id, ELGG_VALUE_INTEGER), |
|||
137 | ]); |
||||
138 | |||||
139 | 118 | $result = $this->db->insertData($qb); |
|||
140 | 118 | if ($result === false) { |
|||
141 | return false; |
||||
142 | } |
||||
143 | |||||
144 | 118 | $annotation->id = $result; |
|||
145 | 118 | $annotation->time_created = $time_created; |
|||
146 | |||||
147 | 118 | if (!$this->events->trigger('create', 'annotation', $annotation)) { |
|||
148 | elgg_delete_annotation_by_id($result); |
||||
149 | |||||
150 | return false; |
||||
151 | } |
||||
152 | |||||
153 | 118 | $entity->updateLastAction($annotation->time_created); |
|||
154 | |||||
155 | 118 | $this->events->triggerAfter('create', 'annotation', $annotation); |
|||
0 ignored issues
–
show
$annotation of type ElggAnnotation is incompatible with the type string expected by parameter $object of Elgg\EventsService::triggerAfter() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||
156 | |||||
157 | 118 | return $result; |
|||
158 | } |
||||
159 | |||||
160 | /** |
||||
161 | * Store updated annotation in the database |
||||
162 | * |
||||
163 | * @todo Add canAnnotate check if entity guid changes |
||||
164 | * |
||||
165 | * @param ElggAnnotation $annotation Annotation to store |
||||
166 | * |
||||
167 | * @return bool |
||||
168 | */ |
||||
169 | public function update(ElggAnnotation $annotation) { |
||||
170 | if (!$annotation->canEdit()) { |
||||
171 | return false; |
||||
172 | } |
||||
173 | |||||
174 | if (!$this->events->triggerBefore('update', 'annotation', $annotation)) { |
||||
0 ignored issues
–
show
$annotation of type ElggAnnotation is incompatible with the type string expected by parameter $object of Elgg\EventsService::triggerBefore() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||
175 | return false; |
||||
176 | } |
||||
177 | |||||
178 | $qb = Update::table('annotations'); |
||||
179 | $qb->set('name', $qb->param($annotation->name, ELGG_VALUE_STRING)) |
||||
180 | ->set('value', $qb->param($annotation->value, $annotation->value_type === 'integer' ? ELGG_VALUE_INTEGER : ELGG_VALUE_STRING)) |
||||
181 | ->set('value_type', $qb->param($annotation->value_type, ELGG_VALUE_STRING)) |
||||
182 | ->set('access_id', $qb->param($annotation->access_id, ELGG_VALUE_INTEGER)) |
||||
183 | ->set('owner_guid', $qb->param($annotation->owner_guid, ELGG_VALUE_INTEGER)) |
||||
184 | ->where($qb->compare('id', '=', $annotation->id, ELGG_VALUE_INTEGER)); |
||||
185 | |||||
186 | $result = $this->db->updateData($qb); |
||||
187 | |||||
188 | if ($result === false) { |
||||
189 | return false; |
||||
190 | } |
||||
191 | |||||
192 | $this->events->trigger('update', 'annotation', $annotation); |
||||
193 | $this->events->triggerAfter('update', 'annotation', $annotation); |
||||
0 ignored issues
–
show
$annotation of type ElggAnnotation is incompatible with the type string expected by parameter $object of Elgg\EventsService::triggerAfter() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||
194 | |||||
195 | return $result; |
||||
196 | } |
||||
197 | |||||
198 | /** |
||||
199 | * Disable the annotation. |
||||
200 | * |
||||
201 | * @param ElggAnnotation $annotation Annotation |
||||
202 | * |
||||
203 | * @return bool |
||||
204 | * @since 1.8 |
||||
205 | */ |
||||
206 | 9 | public function disable(ElggAnnotation $annotation) { |
|||
207 | 9 | if ($annotation->enabled == 'no') { |
|||
208 | return true; |
||||
209 | } |
||||
210 | |||||
211 | 9 | if (!$annotation->canEdit()) { |
|||
212 | return false; |
||||
213 | } |
||||
214 | |||||
215 | 9 | if (!elgg_trigger_event('disable', $annotation->getType(), $annotation)) { |
|||
216 | return false; |
||||
217 | } |
||||
218 | |||||
219 | 9 | if ($annotation->id) { |
|||
220 | 9 | $qb = Update::table('annotations'); |
|||
221 | 9 | $qb->set('enabled', $qb->param('no', ELGG_VALUE_STRING)) |
|||
222 | 9 | ->where($qb->compare('id', '=', $annotation->id, ELGG_VALUE_INTEGER)); |
|||
223 | |||||
224 | 9 | if (!$this->db->updateData($qb)) { |
|||
225 | return false; |
||||
226 | } |
||||
227 | } |
||||
228 | |||||
229 | 9 | $annotation->enabled = 'no'; |
|||
230 | |||||
231 | 9 | return true; |
|||
232 | } |
||||
233 | |||||
234 | /** |
||||
235 | * Enable the annotation |
||||
236 | * |
||||
237 | * @param ElggAnnotation $annotation Annotation |
||||
238 | * |
||||
239 | * @return bool |
||||
240 | * @since 1.8 |
||||
241 | */ |
||||
242 | 4 | public function enable(ElggAnnotation $annotation) { |
|||
243 | 4 | if ($annotation->enabled == 'yes') { |
|||
244 | return true; |
||||
245 | } |
||||
246 | |||||
247 | 4 | if (!$annotation->canEdit()) { |
|||
248 | return false; |
||||
249 | } |
||||
250 | |||||
251 | 4 | if (!$this->events->trigger('enable', $annotation->getType(), $annotation)) { |
|||
252 | return false; |
||||
253 | } |
||||
254 | |||||
255 | 4 | if ($annotation->id) { |
|||
256 | 4 | $qb = Update::table('annotations'); |
|||
257 | 4 | $qb->set('enabled', $qb->param('yes', ELGG_VALUE_STRING)) |
|||
258 | 4 | ->where($qb->compare('id', '=', $annotation->id, ELGG_VALUE_INTEGER)); |
|||
259 | |||||
260 | 4 | if (!$this->db->updateData($qb)) { |
|||
261 | return false; |
||||
262 | } |
||||
263 | } |
||||
264 | |||||
265 | 4 | $annotation->enabled = 'yes'; |
|||
266 | |||||
267 | 4 | return true; |
|||
268 | } |
||||
269 | |||||
270 | /** |
||||
271 | * Returns annotations. Accepts all {@link elgg_get_entities()} options |
||||
272 | * |
||||
273 | * @see elgg_get_entities() |
||||
274 | * |
||||
275 | * @param array $options Options |
||||
276 | * |
||||
277 | * @return ElggAnnotation[]|mixed |
||||
278 | */ |
||||
279 | 20 | public function find(array $options = []) { |
|||
280 | 20 | $options['metastring_type'] = 'annotations'; |
|||
281 | 20 | $options = _elgg_normalize_metastrings_options($options); |
|||
282 | |||||
283 | 20 | return Annotations::find($options); |
|||
284 | } |
||||
285 | |||||
286 | /** |
||||
287 | * Deletes annotations based on $options. |
||||
288 | * |
||||
289 | * @warning Unlike elgg_get_annotations() this will not accept an empty options array! |
||||
290 | * This requires at least one constraint: annotation_owner_guid(s), |
||||
291 | * annotation_name(s), annotation_value(s), or guid(s) must be set. |
||||
292 | * |
||||
293 | * @see elgg_get_annotations() |
||||
294 | * @see elgg_get_entities() |
||||
295 | * |
||||
296 | * @param array $options Options |
||||
297 | * |
||||
298 | * @return bool|null true on success, false on failure, null if no annotations to delete. |
||||
299 | */ |
||||
300 | 215 | public function deleteAll(array $options) { |
|||
301 | 215 | if (!_elgg_is_valid_options_for_batch_operation($options, 'annotation')) { |
|||
302 | return false; |
||||
303 | } |
||||
304 | |||||
305 | 215 | $options['batch'] = true; |
|||
306 | 215 | $options['batch_size'] = 50; |
|||
307 | 215 | $options['batch_inc_offset'] = false; |
|||
308 | |||||
309 | 215 | $annotations = Annotations::find($options); |
|||
310 | 215 | $count = $annotations->count(); |
|||
311 | |||||
312 | 215 | if (!$count) { |
|||
313 | 214 | return; |
|||
314 | } |
||||
315 | |||||
316 | 25 | $success = 0; |
|||
317 | 25 | foreach ($annotations as $annotation) { |
|||
318 | 25 | if ($annotation->delete()) { |
|||
319 | 25 | $success++; |
|||
320 | } |
||||
321 | } |
||||
322 | |||||
323 | 25 | return $success == $count; |
|||
324 | } |
||||
325 | |||||
326 | /** |
||||
327 | * Disables annotations based on $options. |
||||
328 | * |
||||
329 | * @warning Unlike elgg_get_annotations() this will not accept an empty options array! |
||||
330 | * |
||||
331 | * @param array $options An options array. {@link elgg_get_annotations()} |
||||
332 | * @return bool|null true on success, false on failure, null if no annotations disabled. |
||||
333 | */ |
||||
334 | 9 | public function disableAll(array $options) { |
|||
335 | 9 | if (!_elgg_is_valid_options_for_batch_operation($options, 'annotation')) { |
|||
336 | return false; |
||||
337 | } |
||||
338 | |||||
339 | // if we can see hidden (disabled) we need to use the offset |
||||
340 | // otherwise we risk an infinite loop if there are more than 50 |
||||
341 | 9 | $inc_offset = access_get_show_hidden_status(); |
|||
342 | |||||
343 | 9 | $options['batch'] = true; |
|||
344 | 9 | $options['batch_size'] = 50; |
|||
345 | 9 | $options['batch_inc_offset'] = $inc_offset; |
|||
346 | |||||
347 | 9 | $annotations = Annotations::find($options); |
|||
348 | 9 | $count = $annotations->count(); |
|||
349 | |||||
350 | 9 | if (!$count) { |
|||
351 | 4 | return; |
|||
352 | } |
||||
353 | |||||
354 | 6 | $success = 0; |
|||
355 | 6 | foreach ($annotations as $annotation) { |
|||
356 | 6 | if ($annotation->disable()) { |
|||
357 | 6 | $success++; |
|||
358 | } |
||||
359 | } |
||||
360 | |||||
361 | 6 | return $success == $count; |
|||
362 | } |
||||
363 | |||||
364 | /** |
||||
365 | * Enables annotations based on $options. |
||||
366 | * |
||||
367 | * @warning Unlike elgg_get_annotations() this will not accept an empty options array! |
||||
368 | * |
||||
369 | * @warning In order to enable annotations, you must first use |
||||
370 | * {@link access_show_hidden_entities()}. |
||||
371 | * |
||||
372 | * @param array $options An options array. {@link elgg_get_annotations()} |
||||
373 | * @return bool|null true on success, false on failure, null if no metadata enabled. |
||||
374 | */ |
||||
375 | 4 | public function enableAll(array $options) { |
|||
376 | 4 | if (!_elgg_is_valid_options_for_batch_operation($options, 'annotation')) { |
|||
377 | return false; |
||||
378 | } |
||||
379 | |||||
380 | 4 | $options['batch'] = true; |
|||
381 | 4 | $options['batch_size'] = 50; |
|||
382 | |||||
383 | 4 | $annotations = Annotations::find($options); |
|||
384 | 4 | $count = $annotations->count(); |
|||
385 | |||||
386 | 4 | if (!$count) { |
|||
387 | 3 | return; |
|||
388 | } |
||||
389 | |||||
390 | 3 | $success = 0; |
|||
391 | 3 | foreach ($annotations as $annotation) { |
|||
392 | 3 | if ($annotation->enable()) { |
|||
393 | 3 | $success++; |
|||
394 | } |
||||
395 | } |
||||
396 | |||||
397 | 3 | return $success == $count; |
|||
398 | } |
||||
399 | |||||
400 | /** |
||||
401 | * Check to see if a user has already created an annotation on an object |
||||
402 | * |
||||
403 | * @param int $entity_guid Entity guid |
||||
404 | * @param string $name Annotation name |
||||
405 | * @param int $owner_guid Owner guid |
||||
406 | * |
||||
407 | * @return bool |
||||
408 | */ |
||||
409 | 1 | public function exists($entity_guid, $name, $owner_guid) { |
|||
410 | 1 | if (!$owner_guid) { |
|||
411 | return false; |
||||
412 | } |
||||
413 | |||||
414 | 1 | $qb = Select::fromTable('annotations'); |
|||
415 | 1 | $qb->select('id'); |
|||
416 | 1 | $qb->where($qb->compare('owner_guid', '=', $owner_guid, ELGG_VALUE_INTEGER)) |
|||
417 | 1 | ->andWhere($qb->compare('entity_guid', '=', $entity_guid, ELGG_VALUE_INTEGER)) |
|||
418 | 1 | ->andWhere($qb->compare('name', '=', $name, ELGG_VALUE_STRING)); |
|||
419 | |||||
420 | 1 | $result = $this->db->getDataRow($qb); |
|||
421 | |||||
422 | 1 | return $result && $result->id; |
|||
0 ignored issues
–
show
The expression
$result of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.
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
Loading history...
|
|||||
423 | } |
||||
424 | } |
||||
425 |
Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.
Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..