1 | <?php |
||||
2 | |||||
3 | use Elgg\EntityIcon; |
||||
4 | |||||
5 | /** |
||||
6 | * The parent class for all Elgg Entities. |
||||
7 | * |
||||
8 | * An \ElggEntity is one of the basic data models in Elgg. |
||||
9 | * It is the primary means of storing and retrieving data from the database. |
||||
10 | * An \ElggEntity represents one row of the entities table. |
||||
11 | * |
||||
12 | * The \ElggEntity class handles CRUD operations for the entities table. |
||||
13 | * \ElggEntity should always be extended by another class to handle CRUD |
||||
14 | * operations on the type-specific table. |
||||
15 | * |
||||
16 | * \ElggEntity uses magic methods for get and set, so any property that isn't |
||||
17 | * declared will be assumed to be metadata and written to the database |
||||
18 | * as metadata on the object. All children classes must declare which |
||||
19 | * properties are columns of the type table or they will be assumed |
||||
20 | * to be metadata. See \ElggObject::initializeAttributes() for examples. |
||||
21 | * |
||||
22 | * Core supports 4 types of entities: \ElggObject, \ElggUser, \ElggGroup, and \ElggSite. |
||||
23 | * |
||||
24 | * @tip Plugin authors will want to extend the \ElggObject class, not this class. |
||||
25 | * |
||||
26 | * @package Elgg.Core |
||||
27 | * @subpackage DataModel.Entities |
||||
28 | * |
||||
29 | * @property string $type object, user, group, or site (read-only after save) |
||||
30 | * @property string $subtype Further clarifies the nature of the entity (this should not be read) |
||||
31 | * @property-read int $guid The unique identifier for this entity (read only) |
||||
32 | * @property int $owner_guid The GUID of the owner of this entity (usually the creator) |
||||
33 | * @property int $container_guid The GUID of the entity containing this entity |
||||
34 | * @property int $access_id Specifies the visibility level of this entity |
||||
35 | * @property int $time_created A UNIX timestamp of when the entity was created |
||||
36 | * @property-read int $time_updated A UNIX timestamp of when the entity was last updated (automatically updated on save) |
||||
37 | * @property-read int $last_action A UNIX timestamp of when the entity was last acted upon |
||||
38 | * @property string $enabled Is this entity enabled ('yes' or 'no') |
||||
39 | * |
||||
40 | * Metadata (the above are attributes) |
||||
41 | * @property string $location A location of the entity |
||||
42 | */ |
||||
43 | abstract class ElggEntity extends \ElggData implements |
||||
44 | Locatable, // Geocoding interface |
||||
45 | EntityIcon // Icon interface |
||||
46 | { |
||||
47 | |||||
48 | public static $primary_attr_names = [ |
||||
49 | 'guid', |
||||
50 | 'type', |
||||
51 | 'subtype', |
||||
52 | 'owner_guid', |
||||
53 | 'container_guid', |
||||
54 | 'access_id', |
||||
55 | 'time_created', |
||||
56 | 'time_updated', |
||||
57 | 'last_action', |
||||
58 | 'enabled', |
||||
59 | ]; |
||||
60 | |||||
61 | protected static $integer_attr_names = [ |
||||
62 | 'guid', |
||||
63 | 'owner_guid', |
||||
64 | 'container_guid', |
||||
65 | 'access_id', |
||||
66 | 'time_created', |
||||
67 | 'time_updated', |
||||
68 | 'last_action', |
||||
69 | ]; |
||||
70 | |||||
71 | /** |
||||
72 | * Holds metadata until entity is saved. Once the entity is saved, |
||||
73 | * metadata are written immediately to the database. |
||||
74 | * @var array |
||||
75 | */ |
||||
76 | protected $temp_metadata = []; |
||||
77 | |||||
78 | /** |
||||
79 | * Holds annotations until entity is saved. Once the entity is saved, |
||||
80 | * annotations are written immediately to the database. |
||||
81 | * @var array |
||||
82 | */ |
||||
83 | protected $temp_annotations = []; |
||||
84 | |||||
85 | /** |
||||
86 | * Holds private settings until entity is saved. Once the entity is saved, |
||||
87 | * private settings are written immediately to the database. |
||||
88 | * @var array |
||||
89 | */ |
||||
90 | protected $temp_private_settings = []; |
||||
91 | |||||
92 | /** |
||||
93 | * Volatile data structure for this object, allows for storage of data |
||||
94 | * in-memory that isn't sync'd back to the metadata table. |
||||
95 | * @var array |
||||
96 | */ |
||||
97 | protected $volatile = []; |
||||
98 | |||||
99 | /** |
||||
100 | * Holds the original (persisted) attribute values that have been changed but not yet saved. |
||||
101 | * @var array |
||||
102 | */ |
||||
103 | protected $orig_attributes = []; |
||||
104 | |||||
105 | /** |
||||
106 | * @var bool |
||||
107 | */ |
||||
108 | protected $_is_cacheable = true; |
||||
109 | |||||
110 | /** |
||||
111 | * Create a new entity. |
||||
112 | * |
||||
113 | * Plugin developers should only use the constructor to create a new entity. |
||||
114 | * To retrieve entities, use get_entity() and the elgg_get_entities* functions. |
||||
115 | * |
||||
116 | * If no arguments are passed, it creates a new entity. |
||||
117 | * If a database result is passed as a \stdClass instance, it instantiates |
||||
118 | * that entity. |
||||
119 | * |
||||
120 | * @param stdClass $row Database row result. Default is null to create a new object. |
||||
121 | * |
||||
122 | * @throws IOException If cannot load remaining data from db |
||||
123 | */ |
||||
124 | 5322 | public function __construct(stdClass $row = null) { |
|||
125 | 5322 | $this->initializeAttributes(); |
|||
126 | |||||
127 | 5322 | if ($row && !$this->load($row)) { |
|||
128 | $msg = "Failed to load new " . get_class() . " for GUID:" . $row->guid; |
||||
129 | throw new \IOException($msg); |
||||
130 | } |
||||
131 | 5322 | } |
|||
132 | |||||
133 | /** |
||||
134 | * Initialize the attributes array. |
||||
135 | * |
||||
136 | * This is vital to distinguish between metadata and base parameters. |
||||
137 | * |
||||
138 | * @return void |
||||
139 | */ |
||||
140 | 5322 | protected function initializeAttributes() { |
|||
141 | 5322 | parent::initializeAttributes(); |
|||
142 | |||||
143 | 5322 | $this->attributes['guid'] = null; |
|||
144 | 5322 | $this->attributes['type'] = null; |
|||
145 | 5322 | $this->attributes['subtype'] = null; |
|||
146 | |||||
147 | 5322 | $this->attributes['owner_guid'] = _elgg_services()->session->getLoggedInUserGuid(); |
|||
148 | 5322 | $this->attributes['container_guid'] = _elgg_services()->session->getLoggedInUserGuid(); |
|||
149 | |||||
150 | 5322 | $this->attributes['access_id'] = ACCESS_PRIVATE; |
|||
151 | 5322 | $this->attributes['time_updated'] = null; |
|||
152 | 5322 | $this->attributes['last_action'] = null; |
|||
153 | 5322 | $this->attributes['enabled'] = "yes"; |
|||
154 | |||||
155 | 5322 | $this->attributes['type'] = $this->getType(); |
|||
156 | 5322 | } |
|||
157 | |||||
158 | /** |
||||
159 | * Clone an entity |
||||
160 | * |
||||
161 | * Resets the guid so that the entity can be saved as a distinct entity from |
||||
162 | * the original. Creation time will be set when this new entity is saved. |
||||
163 | * The owner and container guids come from the original entity. The clone |
||||
164 | * method copies metadata but does not copy annotations or private settings. |
||||
165 | * |
||||
166 | * @note metadata will have its owner and access id set when the entity is saved |
||||
167 | * and it will be the same as that of the entity. |
||||
168 | * |
||||
169 | * @return void |
||||
170 | */ |
||||
171 | 1 | public function __clone() { |
|||
172 | 1 | $orig_entity = get_entity($this->guid); |
|||
173 | 1 | if (!$orig_entity) { |
|||
174 | _elgg_services()->logger->error("Failed to clone entity with GUID $this->guid"); |
||||
175 | return; |
||||
176 | } |
||||
177 | |||||
178 | 1 | $metadata_array = elgg_get_metadata([ |
|||
179 | 1 | 'guid' => $this->guid, |
|||
180 | 1 | 'limit' => 0 |
|||
181 | ]); |
||||
182 | |||||
183 | 1 | $this->attributes['guid'] = null; |
|||
184 | 1 | $this->attributes['time_created'] = null; |
|||
185 | 1 | $this->attributes['time_updated'] = null; |
|||
186 | 1 | $this->attributes['last_action'] = null; |
|||
187 | |||||
188 | 1 | $this->attributes['subtype'] = $orig_entity->getSubtype(); |
|||
189 | |||||
190 | // copy metadata over to new entity - slightly convoluted due to |
||||
191 | // handling of metadata arrays |
||||
192 | 1 | if (is_array($metadata_array)) { |
|||
193 | // create list of metadata names |
||||
194 | 1 | $metadata_names = []; |
|||
195 | 1 | foreach ($metadata_array as $metadata) { |
|||
196 | 1 | $metadata_names[] = $metadata['name']; |
|||
197 | } |
||||
198 | // arrays are stored with multiple enties per name |
||||
199 | 1 | $metadata_names = array_unique($metadata_names); |
|||
200 | |||||
201 | // move the metadata over |
||||
202 | 1 | foreach ($metadata_names as $name) { |
|||
203 | 1 | $this->__set($name, $orig_entity->$name); |
|||
204 | } |
||||
205 | } |
||||
206 | 1 | } |
|||
207 | |||||
208 | /** |
||||
209 | * Set an attribute or metadata value for this entity |
||||
210 | * |
||||
211 | * Anything that is not an attribute is saved as metadata. |
||||
212 | * |
||||
213 | * @warning Metadata set this way will inherit the entity's owner and |
||||
214 | * access ID. If you want more control over metadata, use \ElggEntity::setMetadata() |
||||
215 | * |
||||
216 | * @param string $name Name of the attribute or metadata |
||||
217 | * @param mixed $value The value to be set |
||||
218 | * @return void |
||||
219 | * @see \ElggEntity::setMetadata() |
||||
220 | */ |
||||
221 | 1092 | public function __set($name, $value) { |
|||
222 | 1092 | if ($this->$name === $value) { |
|||
223 | // quick return if value is not changing |
||||
224 | 289 | return; |
|||
225 | } |
||||
226 | |||||
227 | // Due to https://github.com/Elgg/Elgg/pull/5456#issuecomment-17785173, certain attributes |
||||
228 | // will store empty strings as null in the DB. In the somewhat common case that we're re-setting |
||||
229 | // the value to empty string, don't consider this a change. |
||||
230 | 1092 | if (in_array($name, ['title', 'name', 'description']) |
|||
231 | 1092 | && $this->$name === null |
|||
232 | 1092 | && $value === "") { |
|||
233 | return; |
||||
234 | } |
||||
235 | |||||
236 | 1092 | if (array_key_exists($name, $this->attributes)) { |
|||
237 | // if an attribute is 1 (integer) and it's set to "1" (string), don't consider that a change. |
||||
238 | 589 | if (is_int($this->attributes[$name]) |
|||
239 | 589 | && is_string($value) |
|||
240 | 589 | && ((string) $this->attributes[$name] === $value)) { |
|||
241 | 1 | return; |
|||
242 | } |
||||
243 | |||||
244 | // keep original values |
||||
245 | 589 | if ($this->guid && !array_key_exists($name, $this->orig_attributes)) { |
|||
246 | 9 | $this->orig_attributes[$name] = $this->attributes[$name]; |
|||
247 | } |
||||
248 | |||||
249 | // Certain properties should not be manually changed! |
||||
250 | 589 | switch ($name) { |
|||
251 | case 'guid': |
||||
252 | case 'time_updated': |
||||
253 | case 'last_action': |
||||
254 | return; |
||||
255 | break; |
||||
0 ignored issues
–
show
|
|||||
256 | case 'access_id': |
||||
257 | case 'owner_guid': |
||||
258 | case 'container_guid': |
||||
259 | 482 | if ($value !== null) { |
|||
260 | 482 | $this->attributes[$name] = (int) $value; |
|||
261 | } else { |
||||
262 | $this->attributes[$name] = null; |
||||
263 | } |
||||
264 | 482 | break; |
|||
265 | default: |
||||
266 | 443 | $this->attributes[$name] = $value; |
|||
267 | 443 | break; |
|||
268 | } |
||||
269 | 589 | return; |
|||
270 | } |
||||
271 | |||||
272 | 1062 | $this->setMetadata($name, $value); |
|||
273 | 1062 | } |
|||
274 | |||||
275 | /** |
||||
276 | * Get the original values of attribute(s) that have been modified since the entity was persisted. |
||||
277 | * |
||||
278 | * @return array |
||||
279 | */ |
||||
280 | 59 | public function getOriginalAttributes() { |
|||
281 | 59 | return $this->orig_attributes; |
|||
282 | } |
||||
283 | |||||
284 | /** |
||||
285 | * Get an attribute or metadata value |
||||
286 | * |
||||
287 | * If the name matches an attribute, the attribute is returned. If metadata |
||||
288 | * does not exist with that name, a null is returned. |
||||
289 | * |
||||
290 | * This only returns an array if there are multiple values for a particular |
||||
291 | * $name key. |
||||
292 | * |
||||
293 | * @param string $name Name of the attribute or metadata |
||||
294 | * @return mixed |
||||
295 | */ |
||||
296 | 5387 | public function __get($name) { |
|||
297 | 5387 | if (array_key_exists($name, $this->attributes)) { |
|||
298 | 5386 | return $this->attributes[$name]; |
|||
299 | } |
||||
300 | |||||
301 | 5363 | return $this->getMetadata($name); |
|||
302 | } |
||||
303 | |||||
304 | /** |
||||
305 | * Get the entity's display name |
||||
306 | * |
||||
307 | * @return string The title or name of this entity. |
||||
308 | */ |
||||
309 | 19 | public function getDisplayName() { |
|||
310 | 19 | return $this->name; |
|||
311 | } |
||||
312 | |||||
313 | /** |
||||
314 | * Sets the title or name of this entity. |
||||
315 | * |
||||
316 | * @param string $display_name The title or name of this entity. |
||||
317 | * @return void |
||||
318 | */ |
||||
319 | public function setDisplayName($display_name) { |
||||
320 | $this->name = $display_name; |
||||
321 | } |
||||
322 | |||||
323 | /** |
||||
324 | * Return the value of a piece of metadata. |
||||
325 | * |
||||
326 | * @param string $name Name |
||||
327 | * |
||||
328 | * @return mixed The value, or null if not found. |
||||
329 | */ |
||||
330 | 5363 | public function getMetadata($name) { |
|||
331 | 5363 | $guid = $this->guid; |
|||
332 | |||||
333 | 5363 | if (!$guid) { |
|||
334 | 572 | if (isset($this->temp_metadata[$name])) { |
|||
335 | // md is returned as an array only if more than 1 entry |
||||
336 | 285 | if (count($this->temp_metadata[$name]) == 1) { |
|||
337 | 285 | return $this->temp_metadata[$name][0]; |
|||
338 | } else { |
||||
339 | 158 | return $this->temp_metadata[$name]; |
|||
340 | } |
||||
341 | } else { |
||||
342 | 572 | return null; |
|||
343 | } |
||||
344 | } |
||||
345 | |||||
346 | // upon first cache miss, just load/cache all the metadata and retry. |
||||
347 | // if this works, the rest of this function may not be needed! |
||||
348 | 5354 | $cache = _elgg_services()->metadataCache; |
|||
349 | 5354 | if ($cache->isLoaded($guid)) { |
|||
350 | 2238 | return $cache->getSingle($guid, $name); |
|||
351 | } else { |
||||
352 | 4136 | $cache->populateFromEntities([$guid]); |
|||
353 | // in case ignore_access was on, we have to check again... |
||||
354 | 4136 | if ($cache->isLoaded($guid)) { |
|||
355 | 1082 | return $cache->getSingle($guid, $name); |
|||
356 | } |
||||
357 | } |
||||
358 | |||||
359 | 4083 | $md = elgg_get_metadata([ |
|||
360 | 4083 | 'guid' => $guid, |
|||
361 | 4083 | 'metadata_name' => $name, |
|||
362 | 4083 | 'limit' => 0, |
|||
363 | 'distinct' => false, |
||||
364 | ]); |
||||
365 | |||||
366 | 4083 | $value = null; |
|||
367 | |||||
368 | 4083 | if ($md && !is_array($md)) { |
|||
369 | $value = $md->value; |
||||
0 ignored issues
–
show
|
|||||
370 | 4083 | } elseif (count($md) == 1) { |
|||
0 ignored issues
–
show
It seems like
$md can also be of type integer and false ; however, parameter $var of count() does only seem to accept Countable|array , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||
371 | $value = $md[0]->value; |
||||
372 | 4083 | } else if ($md && is_array($md)) { |
|||
373 | $value = metadata_array_to_values($md); |
||||
374 | } |
||||
375 | |||||
376 | 4083 | return $value; |
|||
377 | } |
||||
378 | |||||
379 | /** |
||||
380 | * Unset a property from metadata or attribute. |
||||
381 | * |
||||
382 | * @warning If you use this to unset an attribute, you must save the object! |
||||
383 | * |
||||
384 | * @param string $name The name of the attribute or metadata. |
||||
385 | * |
||||
386 | * @return void |
||||
387 | * @todo some attributes should be set to null or other default values |
||||
388 | */ |
||||
389 | 49 | public function __unset($name) { |
|||
390 | 49 | if (array_key_exists($name, $this->attributes)) { |
|||
391 | $this->attributes[$name] = ""; |
||||
392 | } else { |
||||
393 | 49 | $this->deleteMetadata($name); |
|||
394 | } |
||||
395 | 49 | } |
|||
396 | |||||
397 | /** |
||||
398 | * Set metadata on this entity. |
||||
399 | * |
||||
400 | * Plugin developers usually want to use the magic set method ($entity->name = 'value'). |
||||
401 | * Use this method if you want to explicitly set the owner or access of the metadata. |
||||
402 | * You cannot set the owner/access before the entity has been saved. |
||||
403 | * |
||||
404 | * @param string $name Name of the metadata |
||||
405 | * @param mixed $value Value of the metadata (doesn't support assoc arrays) |
||||
406 | * @param string $value_type 'text', 'integer', or '' for automatic detection |
||||
407 | * @param bool $multiple Allow multiple values for a single name. |
||||
408 | * Does not support associative arrays. |
||||
409 | * |
||||
410 | * @return bool |
||||
411 | * @throws InvalidArgumentException |
||||
412 | */ |
||||
413 | 1062 | public function setMetadata($name, $value, $value_type = '', $multiple = false) { |
|||
414 | |||||
415 | // normalize value to an array that we will loop over |
||||
416 | // remove indexes if value already an array. |
||||
417 | 1062 | if (is_array($value)) { |
|||
418 | 162 | $value = array_values($value); |
|||
419 | } else { |
||||
420 | 1061 | $value = [$value]; |
|||
421 | } |
||||
422 | |||||
423 | // strip null values from array |
||||
424 | 1062 | $value = array_filter($value, function($var) { |
|||
425 | 1062 | return !is_null($var); |
|||
426 | 1062 | }); |
|||
427 | |||||
428 | 1062 | if (empty($this->guid)) { |
|||
429 | // unsaved entity. store in temp array |
||||
430 | 569 | return $this->setTempMetadata($name, $value, $multiple); |
|||
431 | } |
||||
432 | |||||
433 | // saved entity. persist md to db. |
||||
434 | 1028 | if (!$multiple) { |
|||
435 | 1028 | $current_metadata = $this->getMetadata($name); |
|||
436 | |||||
437 | 1028 | if ((is_array($current_metadata) || count($value) > 1 || $value === []) && isset($current_metadata)) { |
|||
438 | // remove current metadata if needed |
||||
439 | // need to remove access restrictions right now to delete |
||||
440 | // because this is the expected behavior |
||||
441 | 8 | $ia = elgg_set_ignore_access(true); |
|||
442 | 8 | $delete_result = elgg_delete_metadata([ |
|||
443 | 8 | 'guid' => $this->guid, |
|||
444 | 8 | 'metadata_name' => $name, |
|||
445 | 'limit' => false, |
||||
446 | ]); |
||||
447 | 8 | elgg_set_ignore_access($ia); |
|||
448 | |||||
449 | 8 | if (false === $delete_result) { |
|||
450 | return false; |
||||
451 | } |
||||
452 | } |
||||
453 | |||||
454 | 1028 | if (count($value) > 1) { |
|||
455 | // new value is a multiple valued metadata |
||||
456 | 162 | $multiple = true; |
|||
457 | } |
||||
458 | } |
||||
459 | |||||
460 | // create new metadata |
||||
461 | 1028 | foreach ($value as $value_tmp) { |
|||
462 | 1028 | $metadata = new ElggMetadata(); |
|||
463 | 1028 | $metadata->entity_guid = $this->guid; |
|||
464 | 1028 | $metadata->name = $name; |
|||
465 | 1028 | $metadata->value_type = $value_type; |
|||
466 | 1028 | $metadata->value = $value_tmp; |
|||
467 | 1028 | $md_id = _elgg_services()->metadataTable->create($metadata, $multiple); |
|||
468 | 1028 | if (!$md_id) { |
|||
469 | 1028 | return false; |
|||
470 | } |
||||
471 | } |
||||
472 | |||||
473 | 1028 | return true; |
|||
474 | } |
||||
475 | |||||
476 | /** |
||||
477 | * Set temp metadata on this entity. |
||||
478 | * |
||||
479 | * @param string $name Name of the metadata |
||||
480 | * @param mixed $value Value of the metadata (doesn't support assoc arrays) |
||||
481 | * @param bool $multiple Allow multiple values for a single name. |
||||
482 | * Does not support associative arrays. |
||||
483 | * |
||||
484 | * @return bool |
||||
485 | */ |
||||
486 | 569 | protected function setTempMetadata($name, $value, $multiple = false) { |
|||
487 | // if overwrite, delete first |
||||
488 | 569 | if (!$multiple) { |
|||
489 | 569 | unset($this->temp_metadata[$name]); |
|||
490 | 569 | if (count($value)) { |
|||
491 | // only save if value array contains data |
||||
492 | 569 | $this->temp_metadata[$name] = $value; |
|||
493 | } |
||||
494 | 569 | return true; |
|||
495 | } |
||||
496 | |||||
497 | 3 | if (!isset($this->temp_metadata[$name])) { |
|||
498 | $this->temp_metadata[$name] = []; |
||||
499 | } |
||||
500 | |||||
501 | 3 | $this->temp_metadata[$name] = array_merge($this->temp_metadata[$name], $value); |
|||
502 | |||||
503 | 3 | return true; |
|||
504 | } |
||||
505 | |||||
506 | |||||
507 | |||||
508 | /** |
||||
509 | * Deletes all metadata on this object (metadata.entity_guid = $this->guid). |
||||
510 | * If you pass a name, only metadata matching that name will be deleted. |
||||
511 | * |
||||
512 | * @warning Calling this with no $name will clear all metadata on the entity. |
||||
513 | * |
||||
514 | * @param null|string $name The name of the metadata to remove. |
||||
515 | * @return bool|null |
||||
516 | * @since 1.8 |
||||
517 | */ |
||||
518 | 266 | public function deleteMetadata($name = null) { |
|||
519 | |||||
520 | 266 | if (!$this->guid) { |
|||
521 | // remove from temp_metadata |
||||
522 | 2 | if ($name) { |
|||
523 | 2 | if (!isset($this->temp_metadata[$name])) { |
|||
524 | return null; |
||||
525 | } else { |
||||
526 | 2 | unset($this->temp_metadata[$name]); |
|||
527 | 2 | return true; |
|||
528 | } |
||||
529 | } else { |
||||
530 | $this->temp_metadata = []; |
||||
531 | return true; |
||||
532 | } |
||||
533 | } |
||||
534 | |||||
535 | $options = [ |
||||
536 | 266 | 'guid' => $this->guid, |
|||
537 | 266 | 'limit' => 0 |
|||
538 | ]; |
||||
539 | 266 | if ($name) { |
|||
0 ignored issues
–
show
The expression
$name of type null|string is loosely compared to true ; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.
In PHP, under loose comparison (like For '' == false // true
'' == null // true
'ab' == false // false
'ab' == null // false
// It is often better to use strict comparison
'' === false // false
'' === null // false
Loading history...
|
|||||
540 | 55 | $options['metadata_name'] = $name; |
|||
541 | } |
||||
542 | |||||
543 | 266 | return elgg_delete_metadata($options); |
|||
544 | } |
||||
545 | |||||
546 | /** |
||||
547 | * Get a piece of volatile (non-persisted) data on this entity. |
||||
548 | * |
||||
549 | * @param string $name The name of the volatile data |
||||
550 | * |
||||
551 | * @return mixed The value or null if not found. |
||||
552 | */ |
||||
553 | 25 | public function getVolatileData($name) { |
|||
554 | 25 | return array_key_exists($name, $this->volatile) ? $this->volatile[$name] : null; |
|||
555 | } |
||||
556 | |||||
557 | /** |
||||
558 | * Set a piece of volatile (non-persisted) data on this entity |
||||
559 | * |
||||
560 | * @param string $name Name |
||||
561 | * @param mixed $value Value |
||||
562 | * |
||||
563 | * @return void |
||||
564 | */ |
||||
565 | 26 | public function setVolatileData($name, $value) { |
|||
566 | 26 | $this->volatile[$name] = $value; |
|||
567 | 26 | } |
|||
568 | |||||
569 | /** |
||||
570 | * Remove all relationships to and from this entity. |
||||
571 | * If you pass a relationship name, only relationships matching that name |
||||
572 | * will be deleted. |
||||
573 | * |
||||
574 | * @warning Calling this with no $relationship will clear all relationships |
||||
575 | * for this entity. |
||||
576 | * |
||||
577 | * @param null|string $relationship The name of the relationship to remove. |
||||
578 | * @return bool |
||||
579 | * @see \ElggEntity::addRelationship() |
||||
580 | * @see \ElggEntity::removeRelationship() |
||||
581 | */ |
||||
582 | 214 | public function deleteRelationships($relationship = null) { |
|||
583 | 214 | $relationship = (string) $relationship; |
|||
584 | 214 | $result = remove_entity_relationships($this->getGUID(), $relationship); |
|||
585 | 214 | return $result && remove_entity_relationships($this->getGUID(), $relationship, true); |
|||
586 | } |
||||
587 | |||||
588 | /** |
||||
589 | * Add a relationship between this an another entity. |
||||
590 | * |
||||
591 | * @tip Read the relationship like "This entity is a $relationship of $guid_two." |
||||
592 | * |
||||
593 | * @param int $guid_two GUID of the target entity of the relationship. |
||||
594 | * @param string $relationship The type of relationship. |
||||
595 | * |
||||
596 | * @return bool |
||||
597 | * @see \ElggEntity::removeRelationship() |
||||
598 | * @see \ElggEntity::deleteRelationships() |
||||
599 | */ |
||||
600 | 5 | public function addRelationship($guid_two, $relationship) { |
|||
601 | 5 | return add_entity_relationship($this->getGUID(), $relationship, $guid_two); |
|||
602 | } |
||||
603 | |||||
604 | /** |
||||
605 | * Remove a relationship |
||||
606 | * |
||||
607 | * @param int $guid_two GUID of the target entity of the relationship. |
||||
608 | * @param string $relationship The type of relationship. |
||||
609 | * |
||||
610 | * @return bool |
||||
611 | * @see \ElggEntity::addRelationship() |
||||
612 | * @see \ElggEntity::deleteRelationships() |
||||
613 | */ |
||||
614 | 1 | public function removeRelationship($guid_two, $relationship) { |
|||
615 | 1 | return remove_entity_relationship($this->getGUID(), $relationship, $guid_two); |
|||
616 | } |
||||
617 | |||||
618 | /** |
||||
619 | * Adds a private setting to this entity. |
||||
620 | * |
||||
621 | * Private settings are similar to metadata but will not |
||||
622 | * be searched and there are fewer helper functions for them. |
||||
623 | * |
||||
624 | * @param string $name Name of private setting |
||||
625 | * @param mixed $value Value of private setting |
||||
626 | * |
||||
627 | * @return bool |
||||
628 | */ |
||||
629 | 124 | public function setPrivateSetting($name, $value) { |
|||
630 | 124 | if ((int) $this->guid > 0) { |
|||
631 | 123 | return set_private_setting($this->getGUID(), $name, $value); |
|||
632 | } else { |
||||
633 | 45 | $this->temp_private_settings[$name] = $value; |
|||
634 | 45 | return true; |
|||
635 | } |
||||
636 | } |
||||
637 | |||||
638 | /** |
||||
639 | * Returns a private setting value |
||||
640 | * |
||||
641 | * @param string $name Name of the private setting |
||||
642 | * |
||||
643 | * @return mixed Null if the setting does not exist |
||||
644 | */ |
||||
645 | 37 | public function getPrivateSetting($name) { |
|||
646 | 37 | if ((int) ($this->guid) > 0) { |
|||
647 | 37 | return get_private_setting($this->getGUID(), $name); |
|||
648 | } else { |
||||
649 | 5 | if (isset($this->temp_private_settings[$name])) { |
|||
650 | 5 | return $this->temp_private_settings[$name]; |
|||
651 | } |
||||
652 | } |
||||
653 | 5 | return null; |
|||
654 | } |
||||
655 | |||||
656 | /** |
||||
657 | * Removes private setting |
||||
658 | * |
||||
659 | * @param string $name Name of the private setting |
||||
660 | * |
||||
661 | * @return bool |
||||
662 | */ |
||||
663 | 3 | public function removePrivateSetting($name) { |
|||
664 | 3 | return remove_private_setting($this->getGUID(), $name); |
|||
665 | } |
||||
666 | |||||
667 | /** |
||||
668 | * Deletes all annotations on this object (annotations.entity_guid = $this->guid). |
||||
669 | * If you pass a name, only annotations matching that name will be deleted. |
||||
670 | * |
||||
671 | * @warning Calling this with no or empty arguments will clear all annotations on the entity. |
||||
672 | * |
||||
673 | * @param null|string $name The annotations name to remove. |
||||
674 | * @return bool |
||||
675 | * @since 1.8 |
||||
676 | */ |
||||
677 | 214 | public function deleteAnnotations($name = null) { |
|||
678 | $options = [ |
||||
679 | 214 | 'guid' => $this->guid, |
|||
680 | 214 | 'limit' => 0 |
|||
681 | ]; |
||||
682 | 214 | if ($name) { |
|||
0 ignored issues
–
show
The expression
$name of type null|string is loosely compared to true ; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.
In PHP, under loose comparison (like For '' == false // true
'' == null // true
'ab' == false // false
'ab' == null // false
// It is often better to use strict comparison
'' === false // false
'' === null // false
Loading history...
|
|||||
683 | 1 | $options['annotation_name'] = $name; |
|||
684 | } |
||||
685 | |||||
686 | 214 | return elgg_delete_annotations($options); |
|||
687 | } |
||||
688 | |||||
689 | /** |
||||
690 | * Deletes all annotations owned by this object (annotations.owner_guid = $this->guid). |
||||
691 | * If you pass a name, only annotations matching that name will be deleted. |
||||
692 | * |
||||
693 | * @param null|string $name The name of annotations to delete. |
||||
694 | * @return bool |
||||
695 | * @since 1.8 |
||||
696 | */ |
||||
697 | 214 | public function deleteOwnedAnnotations($name = null) { |
|||
698 | // access is turned off for this because they might |
||||
699 | // no longer have access to an entity they created annotations on. |
||||
700 | 214 | $ia = elgg_set_ignore_access(true); |
|||
701 | $options = [ |
||||
702 | 214 | 'annotation_owner_guid' => $this->guid, |
|||
703 | 214 | 'limit' => 0 |
|||
704 | ]; |
||||
705 | 214 | if ($name) { |
|||
0 ignored issues
–
show
The expression
$name of type null|string is loosely compared to true ; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.
In PHP, under loose comparison (like For '' == false // true
'' == null // true
'ab' == false // false
'ab' == null // false
// It is often better to use strict comparison
'' === false // false
'' === null // false
Loading history...
|
|||||
706 | $options['annotation_name'] = $name; |
||||
707 | } |
||||
708 | |||||
709 | 214 | $r = elgg_delete_annotations($options); |
|||
710 | 214 | elgg_set_ignore_access($ia); |
|||
711 | 214 | return $r; |
|||
712 | } |
||||
713 | |||||
714 | /** |
||||
715 | * Disables annotations for this entity, optionally based on name. |
||||
716 | * |
||||
717 | * @param string $name An options name of annotations to disable. |
||||
718 | * @return bool |
||||
719 | * @since 1.8 |
||||
720 | */ |
||||
721 | 5 | public function disableAnnotations($name = '') { |
|||
722 | $options = [ |
||||
723 | 5 | 'guid' => $this->guid, |
|||
724 | 5 | 'limit' => 0 |
|||
725 | ]; |
||||
726 | 5 | if ($name) { |
|||
727 | $options['annotation_name'] = $name; |
||||
728 | } |
||||
729 | |||||
730 | 5 | return elgg_disable_annotations($options); |
|||
731 | } |
||||
732 | |||||
733 | /** |
||||
734 | * Enables annotations for this entity, optionally based on name. |
||||
735 | * |
||||
736 | * @warning Before calling this, you must use {@link access_show_hidden_entities()} |
||||
737 | * |
||||
738 | * @param string $name An options name of annotations to enable. |
||||
739 | * @return bool |
||||
740 | * @since 1.8 |
||||
741 | */ |
||||
742 | 3 | public function enableAnnotations($name = '') { |
|||
743 | $options = [ |
||||
744 | 3 | 'guid' => $this->guid, |
|||
745 | 3 | 'limit' => 0 |
|||
746 | ]; |
||||
747 | 3 | if ($name) { |
|||
748 | $options['annotation_name'] = $name; |
||||
749 | } |
||||
750 | |||||
751 | 3 | return elgg_enable_annotations($options); |
|||
752 | } |
||||
753 | |||||
754 | /** |
||||
755 | * Helper function to return annotation calculation results |
||||
756 | * |
||||
757 | * @param string $name The annotation name. |
||||
758 | * @param string $calculation A valid MySQL function to run its values through |
||||
759 | * @return mixed |
||||
760 | */ |
||||
761 | 2 | private function getAnnotationCalculation($name, $calculation) { |
|||
762 | $options = [ |
||||
763 | 2 | 'guid' => $this->getGUID(), |
|||
764 | 'distinct' => false, |
||||
765 | 2 | 'annotation_name' => $name, |
|||
766 | 2 | 'annotation_calculation' => $calculation |
|||
767 | ]; |
||||
768 | |||||
769 | 2 | return elgg_get_annotations($options); |
|||
770 | } |
||||
771 | |||||
772 | /** |
||||
773 | * Adds an annotation to an entity. |
||||
774 | * |
||||
775 | * @warning By default, annotations are private. |
||||
776 | * |
||||
777 | * @warning Annotating an unsaved entity more than once with the same name |
||||
778 | * will only save the last annotation. |
||||
779 | * |
||||
780 | * @todo Update temp_annotations to store an instance of ElggAnnotation and simply call ElggAnnotation::save(), |
||||
781 | * after entity is saved |
||||
782 | * |
||||
783 | * @param string $name Annotation name |
||||
784 | * @param mixed $value Annotation value |
||||
785 | * @param int $access_id Access ID |
||||
786 | * @param int $owner_guid GUID of the annotation owner |
||||
787 | * @param string $value_type The type of annotation value |
||||
788 | * |
||||
789 | * @return bool|int Returns int if an annotation is saved |
||||
790 | */ |
||||
791 | 93 | public function annotate($name, $value, $access_id = ACCESS_PRIVATE, $owner_guid = 0, $value_type = "") { |
|||
792 | 93 | if ($this->guid) { |
|||
793 | 93 | if (!$owner_guid) { |
|||
794 | 92 | $owner_guid = elgg_get_logged_in_user_guid(); |
|||
795 | } |
||||
796 | 93 | $annotation = new ElggAnnotation(); |
|||
797 | 93 | $annotation->entity_guid = $this->guid; |
|||
798 | 93 | $annotation->name = $name; |
|||
799 | 93 | $annotation->value_type = $value_type; |
|||
800 | 93 | $annotation->value = $value; |
|||
801 | 93 | $annotation->owner_guid = $owner_guid; |
|||
802 | 93 | $annotation->access_id = $access_id; |
|||
803 | 93 | return $annotation->save(); |
|||
804 | } else { |
||||
805 | 17 | $this->temp_annotations[$name] = $value; |
|||
806 | } |
||||
807 | 17 | return true; |
|||
808 | } |
||||
809 | |||||
810 | /** |
||||
811 | * Gets an array of annotations. |
||||
812 | * |
||||
813 | * To retrieve annotations on an unsaved entity, pass array('name' => [annotation name]) |
||||
814 | * as the options array. |
||||
815 | * |
||||
816 | * @param array $options Array of options for elgg_get_annotations() except guid. |
||||
817 | * |
||||
818 | * @return array |
||||
819 | * @see elgg_get_annotations() |
||||
820 | */ |
||||
821 | 9 | public function getAnnotations(array $options = []) { |
|||
822 | 9 | if ($this->guid) { |
|||
823 | 9 | $options['guid'] = $this->guid; |
|||
824 | |||||
825 | 9 | return elgg_get_annotations($options); |
|||
0 ignored issues
–
show
|
|||||
826 | } else { |
||||
827 | $name = elgg_extract('annotation_name', $options, ''); |
||||
828 | |||||
829 | if (isset($this->temp_annotations[$name])) { |
||||
830 | return [$this->temp_annotations[$name]]; |
||||
831 | } |
||||
832 | } |
||||
833 | |||||
834 | return []; |
||||
835 | } |
||||
836 | |||||
837 | /** |
||||
838 | * Count annotations. |
||||
839 | * |
||||
840 | * @param string $name The type of annotation. |
||||
841 | * |
||||
842 | * @return int |
||||
843 | */ |
||||
844 | 2 | public function countAnnotations($name = "") { |
|||
845 | 2 | return $this->getAnnotationCalculation($name, 'count'); |
|||
0 ignored issues
–
show
|
|||||
846 | } |
||||
847 | |||||
848 | /** |
||||
849 | * Get the average of an integer type annotation. |
||||
850 | * |
||||
851 | * @param string $name Annotation name |
||||
852 | * |
||||
853 | * @return int |
||||
854 | */ |
||||
855 | public function getAnnotationsAvg($name) { |
||||
856 | return $this->getAnnotationCalculation($name, 'avg'); |
||||
0 ignored issues
–
show
|
|||||
857 | } |
||||
858 | |||||
859 | /** |
||||
860 | * Get the sum of integer type annotations of a given name. |
||||
861 | * |
||||
862 | * @param string $name Annotation name |
||||
863 | * |
||||
864 | * @return int |
||||
865 | */ |
||||
866 | public function getAnnotationsSum($name) { |
||||
867 | return $this->getAnnotationCalculation($name, 'sum'); |
||||
0 ignored issues
–
show
|
|||||
868 | } |
||||
869 | |||||
870 | /** |
||||
871 | * Get the minimum of integer type annotations of given name. |
||||
872 | * |
||||
873 | * @param string $name Annotation name |
||||
874 | * |
||||
875 | * @return int |
||||
876 | */ |
||||
877 | public function getAnnotationsMin($name) { |
||||
878 | return $this->getAnnotationCalculation($name, 'min'); |
||||
0 ignored issues
–
show
|
|||||
879 | } |
||||
880 | |||||
881 | /** |
||||
882 | * Get the maximum of integer type annotations of a given name. |
||||
883 | * |
||||
884 | * @param string $name Annotation name |
||||
885 | * |
||||
886 | * @return int |
||||
887 | */ |
||||
888 | public function getAnnotationsMax($name) { |
||||
889 | return $this->getAnnotationCalculation($name, 'max'); |
||||
0 ignored issues
–
show
|
|||||
890 | } |
||||
891 | |||||
892 | /** |
||||
893 | * Count the number of comments attached to this entity. |
||||
894 | * |
||||
895 | * @return int Number of comments |
||||
896 | * @since 1.8.0 |
||||
897 | */ |
||||
898 | 2 | public function countComments() { |
|||
899 | 2 | $params = ['entity' => $this]; |
|||
900 | 2 | $num = _elgg_services()->hooks->trigger('comments:count', $this->getType(), $params); |
|||
901 | |||||
902 | 2 | if (is_int($num)) { |
|||
903 | return $num; |
||||
904 | } |
||||
905 | |||||
906 | 2 | return elgg_get_entities([ |
|||
907 | 2 | 'type' => 'object', |
|||
908 | 2 | 'subtype' => 'comment', |
|||
909 | 2 | 'container_guid' => $this->getGUID(), |
|||
910 | 'count' => true, |
||||
911 | 'distinct' => false, |
||||
912 | ]); |
||||
913 | } |
||||
914 | |||||
915 | /** |
||||
916 | * Returns the ACLs owned by the entity |
||||
917 | * |
||||
918 | * @param array $options additional options to get the access collections with |
||||
919 | * |
||||
920 | * @return \ElggAccessCollection[] |
||||
921 | * |
||||
922 | * @see elgg_get_access_collections() |
||||
923 | * @since 3.0 |
||||
924 | */ |
||||
925 | 218 | public function getOwnedAccessCollections($options = []) { |
|||
926 | 218 | $options['owner_guid'] = $this->guid; |
|||
927 | 218 | return _elgg_services()->accessCollections->getEntityCollections($options); |
|||
928 | } |
||||
929 | |||||
930 | /** |
||||
931 | * Returns the first ACL owned by the entity with a given subtype |
||||
932 | * |
||||
933 | * @param string $subtype subtype of the ACL |
||||
934 | * |
||||
935 | * @return \ElggAccessCollection|false |
||||
936 | * |
||||
937 | * @since 3.0 |
||||
938 | */ |
||||
939 | public function getOwnedAccessCollection($subtype) { |
||||
940 | if (!is_string($subtype) || $subtype === '') { |
||||
941 | return false; |
||||
942 | } |
||||
943 | |||||
944 | $acls = $this->getOwnedAccessCollections([ |
||||
945 | 'subtype' => $subtype, |
||||
946 | ]); |
||||
947 | |||||
948 | return elgg_extract(0, $acls, false); |
||||
949 | } |
||||
950 | |||||
951 | /** |
||||
952 | * Gets an array of entities with a relationship to this entity. |
||||
953 | * |
||||
954 | * @param array $options Options array. See elgg_get_entities_from_relationship() |
||||
955 | * for a list of options. 'relationship_guid' is set to |
||||
956 | * this entity. |
||||
957 | * |
||||
958 | * @return array|false An array of entities or false on failure |
||||
959 | * @see elgg_get_entities_from_relationship() |
||||
960 | */ |
||||
961 | public function getEntitiesFromRelationship(array $options = []) { |
||||
962 | $options['relationship_guid'] = $this->guid; |
||||
963 | return elgg_get_entities($options); |
||||
0 ignored issues
–
show
|
|||||
964 | } |
||||
965 | |||||
966 | /** |
||||
967 | * Gets the number of entities from a specific relationship type |
||||
968 | * |
||||
969 | * @param string $relationship Relationship type (eg "friends") |
||||
970 | * @param bool $inverse_relationship Invert relationship |
||||
971 | * |
||||
972 | * @return int|false The number of entities or false on failure |
||||
973 | */ |
||||
974 | public function countEntitiesFromRelationship($relationship, $inverse_relationship = false) { |
||||
975 | return elgg_get_entities([ |
||||
976 | 'relationship' => $relationship, |
||||
977 | 'relationship_guid' => $this->getGUID(), |
||||
978 | 'inverse_relationship' => $inverse_relationship, |
||||
979 | 'count' => true |
||||
980 | ]); |
||||
981 | } |
||||
982 | |||||
983 | /** |
||||
984 | * Can a user edit this entity? |
||||
985 | * |
||||
986 | * @tip Can be overridden by registering for the permissions_check plugin hook. |
||||
987 | * |
||||
988 | * @param int $user_guid The user GUID, optionally (default: logged in user) |
||||
989 | * |
||||
990 | * @return bool Whether this entity is editable by the given user. |
||||
991 | * @see elgg_set_ignore_access() |
||||
992 | */ |
||||
993 | 399 | public function canEdit($user_guid = 0) { |
|||
994 | 399 | return _elgg_services()->userCapabilities->canEdit($this, $user_guid); |
|||
995 | } |
||||
996 | |||||
997 | /** |
||||
998 | * Can a user delete this entity? |
||||
999 | * |
||||
1000 | * @tip Can be overridden by registering for the permissions_check:delete plugin hook. |
||||
1001 | * |
||||
1002 | * @param int $user_guid The user GUID, optionally (default: logged in user) |
||||
1003 | * |
||||
1004 | * @return bool Whether this entity is deletable by the given user. |
||||
1005 | * @since 1.11 |
||||
1006 | * @see elgg_set_ignore_access() |
||||
1007 | */ |
||||
1008 | 462 | public function canDelete($user_guid = 0) { |
|||
1009 | 462 | return _elgg_services()->userCapabilities->canDelete($this, $user_guid); |
|||
1010 | } |
||||
1011 | |||||
1012 | /** |
||||
1013 | * Can a user edit metadata on this entity? |
||||
1014 | * |
||||
1015 | * If no specific metadata is passed, it returns whether the user can |
||||
1016 | * edit any metadata on the entity. |
||||
1017 | * |
||||
1018 | * @tip Can be overridden by by registering for the permissions_check:metadata |
||||
1019 | * plugin hook. |
||||
1020 | * |
||||
1021 | * @param \ElggMetadata $metadata The piece of metadata to specifically check or null for any metadata |
||||
1022 | * @param int $user_guid The user GUID, optionally (default: logged in user) |
||||
1023 | * |
||||
1024 | * @return bool |
||||
1025 | * @see elgg_set_ignore_access() |
||||
1026 | */ |
||||
1027 | 338 | public function canEditMetadata($metadata = null, $user_guid = 0) { |
|||
1028 | 338 | return _elgg_services()->userCapabilities->canEditMetadata($this, $user_guid, $metadata); |
|||
1029 | } |
||||
1030 | |||||
1031 | /** |
||||
1032 | * Can a user add an entity to this container |
||||
1033 | * |
||||
1034 | * @param int $user_guid The GUID of the user creating the entity (0 for logged in user). |
||||
1035 | * @param string $type The type of entity we're looking to write |
||||
1036 | * @param string $subtype The subtype of the entity we're looking to write |
||||
1037 | * |
||||
1038 | * @return bool |
||||
1039 | * @see elgg_set_ignore_access() |
||||
1040 | */ |
||||
1041 | 407 | public function canWriteToContainer($user_guid = 0, $type = 'all', $subtype = 'all') { |
|||
1042 | 407 | return _elgg_services()->userCapabilities->canWriteToContainer($this, $user_guid, $type, $subtype); |
|||
1043 | } |
||||
1044 | |||||
1045 | /** |
||||
1046 | * Can a user comment on an entity? |
||||
1047 | * |
||||
1048 | * @tip Can be overridden by registering for the permissions_check:comment, |
||||
1049 | * <entity type> plugin hook. |
||||
1050 | * |
||||
1051 | * @param int $user_guid User guid (default is logged in user) |
||||
The
break
statement is not necessary if it is preceded for example by areturn
statement:If you would like to keep this construct to be consistent with other
case
statements, you can safely mark this issue as a false-positive.