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); |
|||
0 ignored issues
–
show
Are you sure the assignment to
$num is correct as _elgg_services()->hooks-...is->getType(), $params) targeting Elgg\PluginHooksService::trigger() seems to always return null.
This check looks for function or method calls that always return null and whose return value is assigned to a variable. class A
{
function getObject()
{
return null;
}
}
$a = new A();
$object = $a->getObject();
The method The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.
Loading history...
|
|||||
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); |
||||
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) |
||||
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; |
|||
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; |
|||
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) { |
|||
0 ignored issues
–
show
The call to
sizeof() has too few arguments starting with mode .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check compares calls to functions or methods with their respective definitions. If the call has less arguments than are defined, it raises an issue. If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.
Loading history...
|
|||||
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); |
|||
0 ignored issues
–
show
$this of type ElggEntity is incompatible with the type string expected by parameter $object of elgg_trigger_after_event() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||
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; |
||||
1 ignored issue
–
show
|
|||||
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); |
|||
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 |