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; |
||||
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
Bug
introduced
by
Loading history...
|
|||||
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([ |
||||
0 ignored issues
–
show
|
|||||
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) |
||||
1052 | * @param bool $default Default permission |
||||
1053 | * @return bool |
||||
1054 | */ |
||||
1055 | 4 | public function canComment($user_guid = 0, $default = null) { |
|||
1056 | 4 | return _elgg_services()->userCapabilities->canComment($this, $user_guid, $default); |
|||
1057 | } |
||||
1058 | |||||
1059 | /** |
||||
1060 | * Can a user annotate an entity? |
||||
1061 | * |
||||
1062 | * @tip Can be overridden by registering for the plugin hook [permissions_check:annotate:<name>, |
||||
1063 | * <entity type>] or [permissions_check:annotate, <entity type>]. The hooks are called in that order. |
||||
1064 | * |
||||
1065 | * @tip If you want logged out users to annotate an object, do not call |
||||
1066 | * canAnnotate(). It's easier than using the plugin hook. |
||||
1067 | * |
||||
1068 | * @param int $user_guid User guid (default is logged in user) |
||||
1069 | * @param string $annotation_name The name of the annotation (default is unspecified) |
||||
1070 | * |
||||
1071 | * @return bool |
||||
1072 | */ |
||||
1073 | 8 | public function canAnnotate($user_guid = 0, $annotation_name = '') { |
|||
1074 | 8 | return _elgg_services()->userCapabilities->canAnnotate($this, $user_guid, $annotation_name); |
|||
1075 | } |
||||
1076 | |||||
1077 | /** |
||||
1078 | * Returns the access_id. |
||||
1079 | * |
||||
1080 | * @return int The access ID |
||||
1081 | */ |
||||
1082 | public function getAccessID() { |
||||
1083 | return $this->access_id; |
||||
1084 | } |
||||
1085 | |||||
1086 | /** |
||||
1087 | * Returns the guid. |
||||
1088 | * |
||||
1089 | * @return int|null GUID |
||||
1090 | */ |
||||
1091 | 548 | public function getGUID() { |
|||
1092 | 548 | return $this->guid; |
|||
1093 | } |
||||
1094 | |||||
1095 | /** |
||||
1096 | * Returns the entity type |
||||
1097 | * |
||||
1098 | * @return string The entity type |
||||
1099 | */ |
||||
1100 | 1 | public function getType() { |
|||
1101 | // this is just for the PHPUnit mocking framework |
||||
1102 | 1 | return $this->type; |
|||
1103 | } |
||||
1104 | |||||
1105 | /** |
||||
1106 | * Get the entity subtype |
||||
1107 | * |
||||
1108 | * @return string The entity subtype |
||||
1109 | */ |
||||
1110 | 566 | public function getSubtype() { |
|||
1111 | 566 | return $this->attributes['subtype']; |
|||
1112 | } |
||||
1113 | |||||
1114 | /** |
||||
1115 | * Get the guid of the entity's owner. |
||||
1116 | * |
||||
1117 | * @return int The owner GUID |
||||
1118 | */ |
||||
1119 | 95 | public function getOwnerGUID() { |
|||
1120 | 95 | return (int) $this->owner_guid; |
|||
1121 | } |
||||
1122 | |||||
1123 | /** |
||||
1124 | * Gets the \ElggEntity that owns this entity. |
||||
1125 | * |
||||
1126 | * @return \ElggEntity The owning entity |
||||
1127 | */ |
||||
1128 | 414 | public function getOwnerEntity() { |
|||
1129 | 414 | return get_entity($this->owner_guid); |
|||
1130 | } |
||||
1131 | |||||
1132 | /** |
||||
1133 | * Set the container for this object. |
||||
1134 | * |
||||
1135 | * @param int $container_guid The ID of the container. |
||||
1136 | * |
||||
1137 | * @return bool |
||||
1138 | */ |
||||
1139 | 1 | public function setContainerGUID($container_guid) { |
|||
1140 | 1 | return $this->container_guid = (int) $container_guid; |
|||
0 ignored issues
–
show
|
|||||
1141 | } |
||||
1142 | |||||
1143 | /** |
||||
1144 | * Gets the container GUID for this entity. |
||||
1145 | * |
||||
1146 | * @return int |
||||
1147 | */ |
||||
1148 | 425 | public function getContainerGUID() { |
|||
1149 | 425 | return (int) $this->container_guid; |
|||
1150 | } |
||||
1151 | |||||
1152 | /** |
||||
1153 | * Get the container entity for this object. |
||||
1154 | * |
||||
1155 | * @return \ElggEntity |
||||
1156 | * @since 1.8.0 |
||||
1157 | */ |
||||
1158 | 420 | public function getContainerEntity() { |
|||
1159 | 420 | return get_entity($this->getContainerGUID()); |
|||
1160 | } |
||||
1161 | |||||
1162 | /** |
||||
1163 | * Returns the UNIX epoch time that this entity was last updated |
||||
1164 | * |
||||
1165 | * @return int UNIX epoch time |
||||
1166 | */ |
||||
1167 | 5 | public function getTimeUpdated() { |
|||
1168 | 5 | return $this->time_updated; |
|||
1169 | } |
||||
1170 | |||||
1171 | /** |
||||
1172 | * Gets the URL for this entity. |
||||
1173 | * |
||||
1174 | * Plugins can register for the 'entity:url', <type> plugin hook to |
||||
1175 | * customize the url for an entity. |
||||
1176 | * |
||||
1177 | * @return string The URL of the entity |
||||
1178 | */ |
||||
1179 | 42 | public function getURL() { |
|||
1180 | 42 | $url = _elgg_services()->hooks->trigger('entity:url', $this->getType(), ['entity' => $this]); |
|||
1181 | |||||
1182 | 42 | if ($url === null || $url === '' || $url === false) { |
|||
1183 | 39 | return ''; |
|||
1184 | } |
||||
1185 | |||||
1186 | 3 | return elgg_normalize_url($url); |
|||
1187 | } |
||||
1188 | |||||
1189 | /** |
||||
1190 | * Saves icons using an uploaded file as the source. |
||||
1191 | * |
||||
1192 | * @param string $input_name Form input name |
||||
1193 | * @param string $type The name of the icon. e.g., 'icon', 'cover_photo' |
||||
1194 | * @param array $coords An array of cropping coordinates x1, y1, x2, y2 |
||||
1195 | * @return bool |
||||
1196 | */ |
||||
1197 | public function saveIconFromUploadedFile($input_name, $type = 'icon', array $coords = []) { |
||||
1198 | return _elgg_services()->iconService->saveIconFromUploadedFile($this, $input_name, $type, $coords); |
||||
1199 | } |
||||
1200 | |||||
1201 | /** |
||||
1202 | * Saves icons using a local file as the source. |
||||
1203 | * |
||||
1204 | * @param string $filename The full path to the local file |
||||
1205 | * @param string $type The name of the icon. e.g., 'icon', 'cover_photo' |
||||
1206 | * @param array $coords An array of cropping coordinates x1, y1, x2, y2 |
||||
1207 | * @return bool |
||||
1208 | */ |
||||
1209 | public function saveIconFromLocalFile($filename, $type = 'icon', array $coords = []) { |
||||
1210 | return _elgg_services()->iconService->saveIconFromLocalFile($this, $filename, $type, $coords); |
||||
1211 | } |
||||
1212 | |||||
1213 | /** |
||||
1214 | * Saves icons using a file located in the data store as the source. |
||||
1215 | * |
||||
1216 | * @param string $file An ElggFile instance |
||||
1217 | * @param string $type The name of the icon. e.g., 'icon', 'cover_photo' |
||||
1218 | * @param array $coords An array of cropping coordinates x1, y1, x2, y2 |
||||
1219 | * @return bool |
||||
1220 | */ |
||||
1221 | public function saveIconFromElggFile(\ElggFile $file, $type = 'icon', array $coords = []) { |
||||
1222 | return _elgg_services()->iconService->saveIconFromElggFile($this, $file, $type, $coords); |
||||
1223 | } |
||||
1224 | |||||
1225 | /** |
||||
1226 | * Returns entity icon as an ElggIcon object |
||||
1227 | * The icon file may or may not exist on filestore |
||||
1228 | * |
||||
1229 | * @param string $size Size of the icon |
||||
1230 | * @param string $type The name of the icon. e.g., 'icon', 'cover_photo' |
||||
1231 | * @return \ElggIcon |
||||
1232 | */ |
||||
1233 | 7 | public function getIcon($size, $type = 'icon') { |
|||
1234 | 7 | return _elgg_services()->iconService->getIcon($this, $size, $type); |
|||
1235 | } |
||||
1236 | |||||
1237 | /** |
||||
1238 | * Removes all icon files and metadata for the passed type of icon. |
||||
1239 | * |
||||
1240 | * @param string $type The name of the icon. e.g., 'icon', 'cover_photo' |
||||
1241 | * @return bool |
||||
1242 | */ |
||||
1243 | 1 | public function deleteIcon($type = 'icon') { |
|||
1244 | 1 | return _elgg_services()->iconService->deleteIcon($this, $type); |
|||
1245 | } |
||||
1246 | |||||
1247 | /** |
||||
1248 | * Returns the timestamp of when the icon was changed. |
||||
1249 | * |
||||
1250 | * @param string $size The size of the icon |
||||
1251 | * @param string $type The name of the icon. e.g., 'icon', 'cover_photo' |
||||
1252 | * |
||||
1253 | * @return int|null A unix timestamp of when the icon was last changed, or null if not set. |
||||
1254 | */ |
||||
1255 | public function getIconLastChange($size, $type = 'icon') { |
||||
1256 | return _elgg_services()->iconService->getIconLastChange($this, $size, $type); |
||||
1257 | } |
||||
1258 | |||||
1259 | /** |
||||
1260 | * Returns if the entity has an icon of the passed type. |
||||
1261 | * |
||||
1262 | * @param string $size The size of the icon |
||||
1263 | * @param string $type The name of the icon. e.g., 'icon', 'cover_photo' |
||||
1264 | * @return bool |
||||
1265 | */ |
||||
1266 | 3 | public function hasIcon($size, $type = 'icon') { |
|||
1267 | 3 | return _elgg_services()->iconService->hasIcon($this, $size, $type); |
|||
1268 | } |
||||
1269 | |||||
1270 | /** |
||||
1271 | * Get the URL for this entity's icon |
||||
1272 | * |
||||
1273 | * Plugins can register for the 'entity:icon:url', <type> plugin hook |
||||
1274 | * to customize the icon for an entity. |
||||
1275 | * |
||||
1276 | * @param mixed $params A string defining the size of the icon (e.g. tiny, small, medium, large) |
||||
1277 | * or an array of parameters including 'size' |
||||
1278 | * @return string The URL |
||||
1279 | * @since 1.8.0 |
||||
1280 | */ |
||||
1281 | 12 | public function getIconURL($params = []) { |
|||
1282 | 12 | return _elgg_services()->iconService->getIconURL($this, $params); |
|||
1283 | } |
||||
1284 | |||||
1285 | /** |
||||
1286 | * Save an entity. |
||||
1287 | * |
||||
1288 | * @return bool|int |
||||
1289 | */ |
||||
1290 | 533 | public function save() { |
|||
1291 | 533 | $guid = $this->guid; |
|||
1292 | 533 | if ($guid > 0) { |
|||
1293 | 194 | $guid = $this->update(); |
|||
1294 | } else { |
||||
1295 | 509 | $guid = $this->create(); |
|||
1296 | 509 | if ($guid && !_elgg_services()->hooks->getEvents()->trigger('create', $this->type, $this)) { |
|||
1297 | // plugins that return false to event don't need to override the access system |
||||
1298 | $ia = elgg_set_ignore_access(true); |
||||
1299 | $this->delete(); |
||||
1300 | elgg_set_ignore_access($ia); |
||||
1301 | return false; |
||||
1302 | } |
||||
1303 | } |
||||
1304 | |||||
1305 | 533 | if ($guid) { |
|||
1306 | 513 | $this->cache(); |
|||
1307 | } |
||||
1308 | |||||
1309 | 533 | return $guid; |
|||
1 ignored issue
–
show
|
|||||
1310 | } |
||||
1311 | |||||
1312 | /** |
||||
1313 | * Create a new entry in the entities table. |
||||
1314 | * |
||||
1315 | * Saves the base information in the entities table for the entity. Saving |
||||
1316 | * the type-specific information is handled in the calling class method. |
||||
1317 | * |
||||
1318 | * @warning Entities must have an entry in both the entities table and their type table |
||||
1319 | * or they will throw an exception when loaded. |
||||
1320 | * |
||||
1321 | * @return int The new entity's GUID |
||||
1322 | * @throws InvalidParameterException If the entity's type has not been set. |
||||
1323 | * @throws IOException If the new row fails to write to the DB. |
||||
1324 | */ |
||||
1325 | 509 | protected function create() { |
|||
1326 | |||||
1327 | 509 | $type = $this->attributes['type']; |
|||
1328 | 509 | if (!in_array($type, \Elgg\Config::getEntityTypes())) { |
|||
1329 | throw new \InvalidParameterException('Entity type must be one of the allowed types: ' |
||||
1330 | . implode(', ', \Elgg\Config::getEntityTypes())); |
||||
1331 | } |
||||
1332 | |||||
1333 | 509 | $subtype = $this->attributes['subtype']; |
|||
1334 | 509 | if (!$subtype) { |
|||
1335 | throw new \InvalidParameterException("All entities must have a subtype"); |
||||
1336 | } |
||||
1337 | |||||
1338 | 509 | $owner_guid = (int) $this->attributes['owner_guid']; |
|||
1339 | 509 | $access_id = (int) $this->attributes['access_id']; |
|||
1340 | 509 | $now = $this->getCurrentTime()->getTimestamp(); |
|||
1341 | 509 | $time_created = isset($this->attributes['time_created']) ? (int) $this->attributes['time_created'] : $now; |
|||
1342 | |||||
1343 | 509 | $container_guid = $this->attributes['container_guid']; |
|||
1344 | 509 | if ($container_guid == 0) { |
|||
1345 | 179 | $container_guid = $owner_guid; |
|||
1346 | 179 | $this->attributes['container_guid'] = $container_guid; |
|||
1347 | } |
||||
1348 | 509 | $container_guid = (int) $container_guid; |
|||
1349 | |||||
1350 | 509 | if ($access_id == ACCESS_DEFAULT) { |
|||
1351 | throw new \InvalidParameterException('ACCESS_DEFAULT is not a valid access level. See its documentation in constants.php'); |
||||
1352 | } |
||||
1353 | |||||
1354 | 509 | if ($access_id == ACCESS_FRIENDS) { |
|||
1355 | throw new \InvalidParameterException('ACCESS_FRIENDS is not a valid access level. See its documentation in constants.php'); |
||||
1356 | } |
||||
1357 | |||||
1358 | 509 | $user_guid = elgg_get_logged_in_user_guid(); |
|||
1359 | |||||
1360 | // If given an owner, verify it can be loaded |
||||
1361 | 509 | if ($owner_guid) { |
|||
1362 | 402 | $owner = $this->getOwnerEntity(); |
|||
1363 | 402 | if (!$owner) { |
|||
1364 | _elgg_services()->logger->error("User $user_guid tried to create a ($type, $subtype), but the given" |
||||
1365 | . " owner $owner_guid could not be loaded."); |
||||
1366 | return false; |
||||
0 ignored issues
–
show
|
|||||
1367 | } |
||||
1368 | |||||
1369 | // If different owner than logged in, verify can write to container. |
||||
1370 | |||||
1371 | 402 | if ($user_guid != $owner_guid && !$owner->canWriteToContainer($user_guid, $type, $subtype)) { |
|||
1372 | _elgg_services()->logger->error("User $user_guid tried to create a ($type, $subtype) with owner" |
||||
1373 | . " $owner_guid, but the user wasn't permitted to write to the owner's container."); |
||||
1374 | return false; |
||||
1375 | } |
||||
1376 | } |
||||
1377 | |||||
1378 | // If given a container, verify it can be loaded and that the current user can write to it |
||||
1379 | 509 | if ($container_guid) { |
|||
1380 | 403 | $container = $this->getContainerEntity(); |
|||
1381 | 403 | if (!$container) { |
|||
1382 | _elgg_services()->logger->error("User $user_guid tried to create a ($type, $subtype), but the given" |
||||
1383 | . " container $container_guid could not be loaded."); |
||||
1384 | return false; |
||||
0 ignored issues
–
show
|
|||||
1385 | } |
||||
1386 | |||||
1387 | 403 | if (!$container->canWriteToContainer($user_guid, $type, $subtype)) { |
|||
1388 | _elgg_services()->logger->error("User $user_guid tried to create a ($type, $subtype), but was not" |
||||
1389 | . " permitted to write to container $container_guid."); |
||||
1390 | return false; |
||||
1391 | } |
||||
1392 | } |
||||
1393 | |||||
1394 | // Create primary table row |
||||
1395 | 509 | $guid = _elgg_services()->entityTable->insertRow((object) [ |
|||
1396 | 509 | 'type' => $type, |
|||
1397 | 509 | 'subtype' => $subtype, |
|||
1398 | 509 | 'owner_guid' => $owner_guid, |
|||
1399 | 509 | 'container_guid' => $container_guid, |
|||
1400 | 509 | 'access_id' => $access_id, |
|||
1401 | 509 | 'time_created' => $time_created, |
|||
1402 | 509 | 'time_updated' => $now, |
|||
1403 | 509 | 'last_action' => $now, |
|||
1404 | 509 | ], $this->attributes); |
|||
1405 | |||||
1406 | 509 | if (!$guid) { |
|||
1407 | throw new \IOException("Unable to save new object's base entity information!"); |
||||
1408 | } |
||||
1409 | |||||
1410 | 509 | $this->attributes['subtype'] = $subtype; |
|||
1411 | 509 | $this->attributes['guid'] = (int) $guid; |
|||
1412 | 509 | $this->attributes['time_created'] = (int) $time_created; |
|||
1413 | 509 | $this->attributes['time_updated'] = (int) $now; |
|||
1414 | 509 | $this->attributes['last_action'] = (int) $now; |
|||
1415 | 509 | $this->attributes['container_guid'] = (int) $container_guid; |
|||
1416 | |||||
1417 | // We are writing this new entity to cache to make sure subsequent calls |
||||
1418 | // to get_entity() load the entity from cache and not from the DB. This |
||||
1419 | // MUST come before the metadata and annotation writes below! |
||||
1420 | 509 | $this->cache(); |
|||
1421 | |||||
1422 | // Save any unsaved metadata |
||||
1423 | 509 | if (sizeof($this->temp_metadata) > 0) { |
|||
1424 | 475 | foreach ($this->temp_metadata as $name => $value) { |
|||
1425 | 475 | if (count($value) == 1) { |
|||
1426 | // temp metadata is always an array, but if there is only one value return just the value |
||||
1427 | 475 | $this->$name = $value[0]; |
|||
1428 | } else { |
||||
1429 | 475 | $this->$name = $value; |
|||
1430 | } |
||||
1431 | } |
||||
1432 | |||||
1433 | 475 | $this->temp_metadata = []; |
|||
1434 | } |
||||
1435 | |||||
1436 | // Save any unsaved annotations. |
||||
1437 | 509 | if (sizeof($this->temp_annotations) > 0) { |
|||
1438 | 17 | foreach ($this->temp_annotations as $name => $value) { |
|||
1439 | 17 | $this->annotate($name, $value); |
|||
1440 | } |
||||
1441 | |||||
1442 | 17 | $this->temp_annotations = []; |
|||
1443 | } |
||||
1444 | |||||
1445 | // Save any unsaved private settings. |
||||
1446 | 509 | if (sizeof($this->temp_private_settings) > 0) { |
|||
1447 | 44 | foreach ($this->temp_private_settings as $name => $value) { |
|||
1448 | 44 | $this->setPrivateSetting($name, $value); |
|||
1449 | } |
||||
1450 | |||||
1451 | 44 | $this->temp_private_settings = []; |
|||
1452 | } |
||||
1453 | |||||
1454 | 509 | return $guid; |
|||
1455 | } |
||||
1456 | |||||
1457 | /** |
||||
1458 | * Update the entity in the database. |
||||
1459 | * |
||||
1460 | * @return bool Whether the update was successful. |
||||
1461 | * |
||||
1462 | * @throws InvalidParameterException |
||||
1463 | */ |
||||
1464 | 194 | protected function update() { |
|||
1465 | |||||
1466 | 194 | if (!$this->canEdit()) { |
|||
1467 | 26 | return false; |
|||
1468 | } |
||||
1469 | |||||
1470 | // give old update event a chance to stop the update |
||||
1471 | 172 | if (!_elgg_services()->hooks->getEvents()->trigger('update', $this->type, $this)) { |
|||
1472 | return false; |
||||
1473 | } |
||||
1474 | |||||
1475 | 172 | $this->invalidateCache(); |
|||
1476 | |||||
1477 | // See #6225. We copy these after the update event in case a handler changed one of them. |
||||
1478 | 172 | $guid = (int) $this->guid; |
|||
1479 | 172 | $owner_guid = (int) $this->owner_guid; |
|||
1480 | 172 | $access_id = (int) $this->access_id; |
|||
1481 | 172 | $container_guid = (int) $this->container_guid; |
|||
1482 | 172 | $time_created = (int) $this->time_created; |
|||
1483 | 172 | $time = $this->getCurrentTime()->getTimestamp(); |
|||
1484 | |||||
1485 | 172 | if ($access_id == ACCESS_DEFAULT) { |
|||
1486 | throw new \InvalidParameterException('ACCESS_DEFAULT is not a valid access level. See its documentation in constants.php'); |
||||
1487 | } |
||||
1488 | |||||
1489 | 172 | if ($access_id == ACCESS_FRIENDS) { |
|||
1490 | throw new \InvalidParameterException('ACCESS_FRIENDS is not a valid access level. See its documentation in constants.php'); |
||||
1491 | } |
||||
1492 | |||||
1493 | // Update primary table |
||||
1494 | 172 | $ret = _elgg_services()->entityTable->updateRow($guid, (object) [ |
|||
1495 | 172 | 'owner_guid' => $owner_guid, |
|||
1496 | 172 | 'container_guid' => $container_guid, |
|||
1497 | 172 | 'access_id' => $access_id, |
|||
1498 | 172 | 'time_created' => $time_created, |
|||
1499 | 172 | 'time_updated' => $time, |
|||
1500 | 172 | 'guid' => $guid, |
|||
1501 | ]); |
||||
1502 | 172 | if ($ret === false) { |
|||
1503 | return false; |
||||
1504 | } |
||||
1505 | |||||
1506 | 172 | $this->attributes['time_updated'] = $time; |
|||
1507 | |||||
1508 | 172 | elgg_trigger_after_event('update', $this->type, $this); |
|||
1509 | |||||
1510 | // TODO(evan): Move this to \ElggObject? |
||||
1511 | 172 | if ($this instanceof \ElggObject && isset($this->orig_attributes['access_id'])) { |
|||
1512 | 5 | update_river_access_by_object($guid, $access_id); |
|||
1513 | } |
||||
1514 | |||||
1515 | 172 | $this->orig_attributes = []; |
|||
1516 | |||||
1517 | 172 | $this->cache(); |
|||
1518 | |||||
1519 | // Handle cases where there was no error BUT no rows were updated! |
||||
1520 | 172 | return true; |
|||
1521 | } |
||||
1522 | |||||
1523 | /** |
||||
1524 | * Loads attributes from the entities table into the object. |
||||
1525 | * |
||||
1526 | * @param stdClass $row Object of properties from database row(s) |
||||
1527 | * |
||||
1528 | * @return bool |
||||
1529 | */ |
||||
1530 | 5313 | protected function load(stdClass $row) { |
|||
1531 | 5313 | $attributes = array_merge($this->attributes, (array) $row); |
|||
1532 | |||||
1533 | 5313 | if (array_diff(self::$primary_attr_names, array_keys($attributes)) !== []) { |
|||
1534 | // Some primary attributes are missing |
||||
1535 | return false; |
||||
1536 | } |
||||
1537 | |||||
1538 | 5313 | foreach ($attributes as $name => $value) { |
|||
1539 | 5313 | if (!in_array($name, self::$primary_attr_names)) { |
|||
1540 | 24 | $this->setVolatileData("select:$name", $value); |
|||
1541 | 24 | unset($attributes[$name]); |
|||
1542 | 24 | continue; |
|||
1543 | } |
||||
1544 | |||||
1545 | 5313 | if (in_array($name, self::$integer_attr_names)) { |
|||
1546 | 5313 | $attributes[$name] = (int) $value; |
|||
1547 | } |
||||
1548 | } |
||||
1549 | |||||
1550 | 5313 | $this->attributes = $attributes; |
|||
1551 | |||||
1552 | 5313 | $this->cache(); |
|||
1553 | |||||
1554 | 5313 | return true; |
|||
1555 | } |
||||
1556 | |||||
1557 | /** |
||||
1558 | * Load new data from database into existing entity. Overwrites data but |
||||
1559 | * does not change values not included in the latest data. |
||||
1560 | * |
||||
1561 | * @internal This is used when the same entity is selected twice during a |
||||
1562 | * request in case different select clauses were used to load different data |
||||
1563 | * into volatile data. |
||||
1564 | * |
||||
1565 | * @param stdClass $row DB row with new entity data |
||||
1566 | * @return bool |
||||
1567 | * @access private |
||||
1568 | */ |
||||
1569 | public function refresh(stdClass $row) { |
||||
1570 | if ($row instanceof stdClass) { |
||||
1571 | return $this->load($row); |
||||
1572 | } |
||||
1573 | return false; |
||||
1574 | } |
||||
1575 | |||||
1576 | /** |
||||
1577 | * Disable this entity. |
||||
1578 | * |
||||
1579 | * Disabled entities are not returned by getter functions. |
||||
1580 | * To enable an entity, use {@link \ElggEntity::enable()}. |
||||
1581 | * |
||||
1582 | * Recursively disabling an entity will disable all entities |
||||
1583 | * owned or contained by the parent entity. |
||||
1584 | * |
||||
1585 | * You can ignore the disabled field by using {@link access_show_hidden_entities()}. |
||||
1586 | * |
||||
1587 | * @note Internal: Disabling an entity sets the 'enabled' column to 'no'. |
||||
1588 | * |
||||
1589 | * @param string $reason Optional reason |
||||
1590 | * @param bool $recursive Recursively disable all contained entities? |
||||
1591 | * |
||||
1592 | * @return bool |
||||
1593 | * @see \ElggEntity::enable() |
||||
1594 | */ |
||||
1595 | 5 | public function disable($reason = "", $recursive = true) { |
|||
1596 | 5 | if (!$this->guid) { |
|||
1597 | return false; |
||||
1598 | } |
||||
1599 | |||||
1600 | 5 | if (!_elgg_services()->hooks->getEvents()->trigger('disable', $this->type, $this)) { |
|||
1601 | return false; |
||||
1602 | } |
||||
1603 | |||||
1604 | 5 | if (!$this->canEdit()) { |
|||
1605 | return false; |
||||
1606 | } |
||||
1607 | |||||
1608 | 5 | if ($this instanceof ElggUser && !$this->isBanned()) { |
|||
1609 | // temporarily ban to prevent using the site during disable |
||||
1610 | 1 | $this->ban(); |
|||
1611 | 1 | $unban_after = true; |
|||
1612 | } else { |
||||
1613 | 4 | $unban_after = false; |
|||
1614 | } |
||||
1615 | |||||
1616 | 5 | if ($reason) { |
|||
1617 | $this->disable_reason = $reason; |
||||
1618 | } |
||||
1619 | |||||
1620 | 5 | $dbprefix = _elgg_config()->dbprefix; |
|||
1621 | |||||
1622 | 5 | $guid = (int) $this->guid; |
|||
1623 | |||||
1624 | 5 | if ($recursive) { |
|||
1625 | // Only disable enabled subentities |
||||
1626 | 5 | $hidden = access_get_show_hidden_status(); |
|||
1627 | 5 | access_show_hidden_entities(false); |
|||
1628 | |||||
1629 | 5 | $ia = elgg_set_ignore_access(true); |
|||
1630 | |||||
1631 | $base_options = [ |
||||
1632 | 5 | 'wheres' => [ |
|||
1633 | 5 | "e.guid != $guid", |
|||
1634 | ], |
||||
1635 | 'limit' => false, |
||||
1636 | ]; |
||||
1637 | |||||
1638 | 5 | foreach (['owner_guid', 'container_guid'] as $db_column) { |
|||
1639 | 5 | $options = $base_options; |
|||
1640 | 5 | $options[$db_column] = $guid; |
|||
1641 | |||||
1642 | 5 | $subentities = new \ElggBatch('elgg_get_entities', $options); |
|||
1643 | 5 | $subentities->setIncrementOffset(false); |
|||
1644 | |||||
1645 | 5 | foreach ($subentities as $subentity) { |
|||
1646 | /* @var $subentity \ElggEntity */ |
||||
1647 | 2 | if (!$subentity->isEnabled()) { |
|||
1648 | continue; |
||||
1649 | } |
||||
1650 | 2 | add_entity_relationship($subentity->guid, 'disabled_with', $guid); |
|||
1651 | 5 | $subentity->disable($reason); |
|||
1652 | } |
||||
1653 | } |
||||
1654 | |||||
1655 | 5 | access_show_hidden_entities($hidden); |
|||
1656 | 5 | elgg_set_ignore_access($ia); |
|||
1657 | } |
||||
1658 | |||||
1659 | 5 | $this->disableAnnotations(); |
|||
1660 | |||||
1661 | $sql = " |
||||
1662 | 5 | UPDATE {$dbprefix}entities |
|||
1663 | SET enabled = 'no' |
||||
1664 | WHERE guid = :guid |
||||
1665 | "; |
||||
1666 | $params = [ |
||||
1667 | 5 | ':guid' => $guid, |
|||
1668 | ]; |
||||
1669 | 5 | $disabled = $this->getDatabase()->updateData($sql, false, $params); |
|||
1670 | |||||
1671 | 5 | if ($unban_after) { |
|||
1672 | 1 | $this->unban(); |
|||
1673 | } |
||||
1674 | |||||
1675 | 5 | if ($disabled) { |
|||
1676 | 5 | $this->invalidateCache(); |
|||
1677 | |||||
1678 | 5 | $this->attributes['enabled'] = 'no'; |
|||
1679 | 5 | _elgg_services()->hooks->getEvents()->trigger('disable:after', $this->type, $this); |
|||
1680 | } |
||||
1681 | |||||
1682 | 5 | return (bool) $disabled; |
|||
1683 | } |
||||
1684 | |||||
1685 | /** |
||||
1686 | * Enable the entity |
||||
1687 | * |
||||
1688 | * @warning Disabled entities can't be loaded unless |
||||
1689 | * {@link access_show_hidden_entities(true)} has been called. |
||||
1690 | * |
||||
1691 | * @param bool $recursive Recursively enable all entities disabled with the entity? |
||||
1692 | * @see access_show_hiden_entities() |
||||
1693 | * @return bool |
||||
1694 | */ |
||||
1695 | 3 | public function enable($recursive = true) { |
|||
1696 | 3 | $guid = (int) $this->guid; |
|||
1697 | 3 | if (!$guid) { |
|||
1698 | return false; |
||||
1699 | } |
||||
1700 | |||||
1701 | 3 | if (!_elgg_services()->hooks->getEvents()->trigger('enable', $this->type, $this)) { |
|||
1702 | return false; |
||||
1703 | } |
||||
1704 | |||||
1705 | 3 | if (!$this->canEdit()) { |
|||
1706 | return false; |
||||
1707 | } |
||||
1708 | |||||
1709 | // Override access only visible entities |
||||
1710 | 3 | $old_access_status = access_get_show_hidden_status(); |
|||
1711 | 3 | access_show_hidden_entities(true); |
|||
1712 | |||||
1713 | 3 | $db = $this->getDatabase(); |
|||
1714 | 3 | $result = $db->updateData(" |
|||
1715 | 3 | UPDATE {$db->prefix}entities |
|||
1716 | SET enabled = 'yes' |
||||
1717 | 3 | WHERE guid = $guid |
|||
1718 | "); |
||||
1719 | |||||
1720 | 3 | $this->deleteMetadata('disable_reason'); |
|||
1721 | 3 | $this->enableAnnotations(); |
|||
1722 | |||||
1723 | 3 | if ($recursive) { |
|||
1724 | 3 | $disabled_with_it = elgg_get_entities([ |
|||
1725 | 3 | 'relationship' => 'disabled_with', |
|||
1726 | 3 | 'relationship_guid' => $guid, |
|||
1727 | 'inverse_relationship' => true, |
||||
1728 | 3 | 'limit' => 0, |
|||
1729 | ]); |
||||
1730 | |||||
1731 | 3 | foreach ($disabled_with_it as $e) { |
|||
1732 | 1 | $e->enable(); |
|||
1733 | 1 | remove_entity_relationship($e->guid, 'disabled_with', $guid); |
|||
1734 | } |
||||
1735 | } |
||||
1736 | |||||
1737 | 3 | access_show_hidden_entities($old_access_status); |
|||
1738 | |||||
1739 | 3 | if ($result) { |
|||
1740 | 3 | $this->attributes['enabled'] = 'yes'; |
|||
1741 | 3 | _elgg_services()->hooks->getEvents()->trigger('enable:after', $this->type, $this); |
|||
1742 | } |
||||
1743 | |||||
1744 | 3 | return $result; |
|||
1745 | } |
||||
1746 | |||||
1747 | /** |
||||
1748 | * Is this entity enabled? |
||||
1749 | * |
||||
1750 | * @return boolean Whether this entity is enabled. |
||||
1751 | */ |
||||
1752 | 8 | public function isEnabled() { |
|||
1753 | 8 | return $this->enabled == 'yes'; |
|||
1754 | } |
||||
1755 | |||||
1756 | /** |
||||
1757 | * Deletes the entity. |
||||
1758 | * |
||||
1759 | * Removes the entity and its metadata, annotations, relationships, |
||||
1760 | * river entries, and private data. |
||||
1761 | * |
||||
1762 | * Optionally can remove entities contained and owned by this entity. |
||||
1763 | * |
||||
1764 | * @warning If deleting recursively, this bypasses ownership of items contained by |
||||
1765 | * the entity. That means that if the container_guid = $this->guid, the item will |
||||
1766 | * be deleted regardless of who owns it. |
||||
1767 | * |
||||
1768 | * @param bool $recursive If true (default) then all entities which are |
||||
1769 | * owned or contained by $this will also be deleted. |
||||
1770 | * |
||||
1771 | * @return bool |
||||
1772 | */ |
||||
1773 | 459 | public function delete($recursive = true) { |
|||
1774 | // first check if we can delete this entity |
||||
1775 | // NOTE: in Elgg <= 1.10.3 this was after the delete event, |
||||
1776 | // which could potentially remove some content if the user didn't have access |
||||
1777 | 459 | if (!$this->canDelete()) { |
|||
1778 | 247 | return false; |
|||
1779 | } |
||||
1780 | |||||
1781 | try { |
||||
1782 | 215 | return _elgg_services()->entityTable->delete($this, $recursive); |
|||
1783 | } catch (DatabaseException $ex) { |
||||
1784 | elgg_log($ex->getMessage(), 'ERROR'); |
||||
1785 | return false; |
||||
1786 | } |
||||
1787 | } |
||||
1788 | |||||
1789 | /** |
||||
1790 | * {@inheritdoc} |
||||
1791 | */ |
||||
1792 | 5 | public function toObject() { |
|||
1793 | 5 | $object = $this->prepareObject(new stdClass()); |
|||
1794 | 5 | $params = ['entity' => $this]; |
|||
1795 | 5 | $object = _elgg_services()->hooks->trigger('to:object', 'entity', $params, $object); |
|||
1796 | 5 | return $object; |
|||
1797 | } |
||||
1798 | |||||
1799 | /** |
||||
1800 | * Prepare an object copy for toObject() |
||||
1801 | * |
||||
1802 | * @param stdClass $object Object representation of the entity |
||||
1803 | * @return stdClass |
||||
1804 | */ |
||||
1805 | 5 | protected function prepareObject($object) { |
|||
1806 | 5 | $object->guid = $this->guid; |
|||
1807 | 5 | $object->type = $this->getType(); |
|||
1808 | 5 | $object->subtype = $this->getSubtype(); |
|||
1809 | 5 | $object->owner_guid = $this->getOwnerGUID(); |
|||
1810 | 5 | $object->container_guid = $this->getContainerGUID(); |
|||
1811 | 5 | $object->time_created = date('c', $this->getTimeCreated()); |
|||
1812 | 5 | $object->time_updated = date('c', $this->getTimeUpdated()); |
|||
1813 | 5 | $object->url = $this->getURL(); |
|||
1814 | 5 | $object->read_access = (int) $this->access_id; |
|||
1815 | 5 | return $object; |
|||
1816 | } |
||||
1817 | |||||
1818 | /* |
||||
1819 | * LOCATABLE INTERFACE |
||||
1820 | */ |
||||
1821 | |||||
1822 | /** |
||||
1823 | * Gets the 'location' metadata for the entity |
||||
1824 | * |
||||
1825 | * @return string The location |
||||
1826 | */ |
||||
1827 | public function getLocation() { |
||||
1828 | return $this->location; |
||||
1829 | } |
||||
1830 | |||||
1831 | /** |
||||
1832 | * Sets the 'location' metadata for the entity |
||||
1833 | * |
||||
1834 | * @param string $location String representation of the location |
||||
1835 | * |
||||
1836 | * @return void |
||||
1837 | */ |
||||
1838 | public function setLocation($location) { |
||||
1839 | $this->location = $location; |
||||
1840 | } |
||||
1841 | |||||
1842 | /** |
||||
1843 | * Set latitude and longitude metadata tags for a given entity. |
||||
1844 | * |
||||
1845 | * @param float $lat Latitude |
||||
1846 | * @param float $long Longitude |
||||
1847 | * |
||||
1848 | * @return void |
||||
1849 | * @todo Unimplemented |
||||
1850 | */ |
||||
1851 | public function setLatLong($lat, $long) { |
||||
1852 | $this->{"geo:lat"} = $lat; |
||||
1853 | $this->{"geo:long"} = $long; |
||||
1854 | } |
||||
1855 | |||||
1856 | /** |
||||
1857 | * Return the entity's latitude. |
||||
1858 | * |
||||
1859 | * @return float |
||||
1860 | * @todo Unimplemented |
||||
1861 | */ |
||||
1862 | 3 | public function getLatitude() { |
|||
1863 | 3 | return (float) $this->{"geo:lat"}; |
|||
1864 | } |
||||
1865 | |||||
1866 | /** |
||||
1867 | * Return the entity's longitude |
||||
1868 | * |
||||
1869 | * @return float |
||||
1870 | * @todo Unimplemented |
||||
1871 | */ |
||||
1872 | 3 | public function getLongitude() { |
|||
1873 | 3 | return (float) $this->{"geo:long"}; |
|||
1874 | } |
||||
1875 | |||||
1876 | /* |
||||
1877 | * SYSTEM LOG INTERFACE |
||||
1878 | */ |
||||
1879 | |||||
1880 | /** |
||||
1881 | * Return an identification for the object for storage in the system log. |
||||
1882 | * This id must be an integer. |
||||
1883 | * |
||||
1884 | * @return int |
||||
1885 | */ |
||||
1886 | 350 | public function getSystemLogID() { |
|||
1887 | 350 | return $this->getGUID(); |
|||
1888 | } |
||||
1889 | |||||
1890 | /** |
||||
1891 | * For a given ID, return the object associated with it. |
||||
1892 | * This is used by the system log. It can be called on any Loggable object. |
||||
1893 | * |
||||
1894 | * @param int $id GUID. |
||||
1895 | * @return int GUID |
||||
1896 | */ |
||||
1897 | public function getObjectFromID($id) { |
||||
1898 | return get_entity($id); |
||||
0 ignored issues
–
show
|
|||||
1899 | } |
||||
1900 | |||||
1901 | /** |
||||
1902 | * Returns tags for this entity. |
||||
1903 | * |
||||
1904 | * @warning Tags must be registered by {@link elgg_register_tag_metadata_name()}. |
||||
1905 | * |
||||
1906 | * @param array $tag_names Optionally restrict by tag metadata names. |
||||
1907 | * |
||||
1908 | * @return array |
||||
1909 | */ |
||||
1910 | public function getTags($tag_names = null) { |
||||
1911 | if ($tag_names && !is_array($tag_names)) { |
||||
1912 | $tag_names = [$tag_names]; |
||||
1913 | } |
||||
1914 | |||||
1915 | $valid_tags = elgg_get_registered_tag_metadata_names(); |
||||
1916 | $entity_tags = []; |
||||
1917 | |||||
1918 | foreach ($valid_tags as $tag_name) { |
||||
1919 | if (is_array($tag_names) && !in_array($tag_name, $tag_names)) { |
||||
1920 | continue; |
||||
1921 | } |
||||
1922 | |||||
1923 | if ($tags = $this->$tag_name) { |
||||
1924 | // if a single tag, metadata returns a string. |
||||
1925 | // if multiple tags, metadata returns an array. |
||||
1926 | if (is_array($tags)) { |
||||
1927 | $entity_tags = array_merge($entity_tags, $tags); |
||||
1928 | } else { |
||||
1929 | $entity_tags[] = $tags; |
||||
1930 | } |
||||
1931 | } |
||||
1932 | } |
||||
1933 | |||||
1934 | return $entity_tags; |
||||
1935 | } |
||||
1936 | |||||
1937 | /** |
||||
1938 | * Remove the membership of all access collections for this entity (if the entity is a user) |
||||
1939 | * |
||||
1940 | * @return bool |
||||
1941 | * @since 1.11 |
||||
1942 | */ |
||||
1943 | 214 | public function deleteAccessCollectionMemberships() { |
|||
1944 | |||||
1945 | 214 | if (!$this->guid) { |
|||
1946 | return false; |
||||
1947 | } |
||||
1948 | |||||
1949 | 214 | if ($this->type !== 'user') { |
|||
1950 | 191 | return true; |
|||
1951 | } |
||||
1952 | |||||
1953 | 70 | $ac = _elgg_services()->accessCollections; |
|||
1954 | |||||
1955 | 70 | $collections = $ac->getCollectionsByMember($this->guid); |
|||
1956 | 70 | if (empty($collections)) { |
|||
1957 | 69 | return true; |
|||
1958 | } |
||||
1959 | |||||
1960 | 4 | $result = true; |
|||
1961 | 4 | foreach ($collections as $collection) { |
|||
1962 | 4 | $result = $result & $ac->removeUser($this->guid, $collection->id); |
|||
1963 | } |
||||
1964 | |||||
1965 | 4 | return $result; |
|||
1 ignored issue
–
show
|
|||||
1966 | } |
||||
1967 | |||||
1968 | /** |
||||
1969 | * Remove all access collections owned by this entity |
||||
1970 | * |
||||
1971 | * @return bool |
||||
1972 | * @since 1.11 |
||||
1973 | */ |
||||
1974 | 214 | public function deleteOwnedAccessCollections() { |
|||
1975 | |||||
1976 | 214 | if (!$this->guid) { |
|||
1977 | return false; |
||||
1978 | } |
||||
1979 | |||||
1980 | 214 | $collections = $this->getOwnedAccessCollections(); |
|||
1981 | 214 | if (empty($collections)) { |
|||
1982 | 208 | return true; |
|||
1983 | } |
||||
1984 | |||||
1985 | 45 | $result = true; |
|||
1986 | 45 | foreach ($collections as $collection) { |
|||
1987 | 45 | $result = $result & $collection->delete(); |
|||
1988 | } |
||||
1989 | |||||
1990 | 45 | return $result; |
|||
1 ignored issue
–
show
|
|||||
1991 | } |
||||
1992 | |||||
1993 | /** |
||||
1994 | * Update the last_action column in the entities table. |
||||
1995 | * |
||||
1996 | * @warning This is different to time_updated. Time_updated is automatically set, |
||||
1997 | * while last_action is only set when explicitly called. |
||||
1998 | * |
||||
1999 | * @param int $posted Timestamp of last action |
||||
2000 | * @return int|false |
||||
2001 | * @access private |
||||
2002 | */ |
||||
2003 | 122 | public function updateLastAction($posted = null) { |
|||
2004 | 122 | $posted = _elgg_services()->entityTable->updateLastAction($this, $posted); |
|||
2005 | 122 | if ($posted) { |
|||
2006 | 122 | $this->attributes['last_action'] = $posted; |
|||
2007 | 122 | $this->cache(); |
|||
2008 | } |
||||
2009 | 122 | return $posted; |
|||
2010 | } |
||||
2011 | |||||
2012 | /** |
||||
2013 | * Disable runtime caching for entity |
||||
2014 | * |
||||
2015 | * @return void |
||||
2016 | * @internal |
||||
2017 | */ |
||||
2018 | 2 | public function disableCaching() { |
|||
2019 | 2 | $this->_is_cacheable = false; |
|||
2020 | 2 | if ($this->guid) { |
|||
2021 | 2 | _elgg_services()->entityCache->delete($this->guid); |
|||
2022 | } |
||||
2023 | 2 | } |
|||
2024 | |||||
2025 | /** |
||||
2026 | * Enable runtime caching for entity |
||||
2027 | * |
||||
2028 | * @return void |
||||
2029 | * @internal |
||||
2030 | */ |
||||
2031 | 1 | public function enableCaching() { |
|||
2032 | 1 | $this->_is_cacheable = true; |
|||
2033 | 1 | } |
|||
2034 | |||||
2035 | /** |
||||
2036 | * Is entity cacheable in the runtime cache |
||||
2037 | * |
||||
2038 | * @return bool |
||||
2039 | * @internal |
||||
2040 | */ |
||||
2041 | 5308 | public function isCacheable() { |
|||
2042 | 5308 | if (_elgg_services()->session->getIgnoreAccess()) { |
|||
2043 | 827 | return false; |
|||
2044 | } |
||||
2045 | 5118 | return $this->_is_cacheable; |
|||
2046 | } |
||||
2047 | |||||
2048 | /** |
||||
2049 | * Cache the entity in a session and persisted caches |
||||
2050 | * |
||||
2051 | * @param bool $persist Store in persistent cache |
||||
2052 | * |
||||
2053 | * @return void |
||||
2054 | * @internal |
||||
2055 | */ |
||||
2056 | 5313 | public function cache($persist = true) { |
|||
2057 | 5313 | if (!$this->isCacheable()) { |
|||
2058 | 828 | return; |
|||
2059 | } |
||||
2060 | |||||
2061 | 5125 | _elgg_services()->entityCache->save($this); |
|||
2062 | |||||
2063 | 5125 | if ($persist) { |
|||
2064 | 5125 | $tmp = $this->volatile; |
|||
2065 | |||||
2066 | // don't store volatile data |
||||
2067 | 5125 | $this->volatile = []; |
|||
2068 | |||||
2069 | 5125 | _elgg_services()->dataCache->entities->save($this->guid, $this); |
|||
0 ignored issues
–
show
$this of type ElggEntity is incompatible with the type string expected by parameter $data of Elgg\Cache\CompositeCache::save() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||
2070 | |||||
2071 | 5125 | $this->volatile = $tmp; |
|||
2072 | } |
||||
2073 | 5125 | } |
|||
2074 | |||||
2075 | /** |
||||
2076 | * Invalidate cache for entity |
||||
2077 | * |
||||
2078 | * @return void |
||||
2079 | * @internal |
||||
2080 | */ |
||||
2081 | 1068 | public function invalidateCache() { |
|||
2082 | 1068 | if (!$this->guid) { |
|||
2083 | return; |
||||
2084 | } |
||||
2085 | |||||
2086 | 1068 | _elgg_services()->boot->invalidateCache(); |
|||
2087 | |||||
2088 | 1068 | _elgg_services()->entityCache->delete($this->guid); |
|||
2089 | |||||
2090 | $namespaces = [ |
||||
2091 | 1068 | 'entities', |
|||
2092 | 'metadata', |
||||
2093 | 'private_settings', |
||||
2094 | ]; |
||||
2095 | |||||
2096 | 1068 | foreach ($namespaces as $namespace) { |
|||
2097 | 1068 | _elgg_services()->dataCache->get($namespace)->delete($this->guid); |
|||
2098 | } |
||||
2099 | 1068 | } |
|||
2100 | } |
||||
2101 |