1: <?php
2: /**
3: * The parent class for all Elgg Entities.
4: *
5: * An ElggEntity is one of the basic data models in Elgg. It is the primary
6: * means of storing and retrieving data from the database. An ElggEntity
7: * represents one row of the entities table.
8: *
9: * The ElggEntity class handles CRUD operations for the entities table.
10: * ElggEntity should always be extended by another class to handle CRUD
11: * operations on the type-specific table.
12: *
13: * ElggEntity uses magic methods for get and set, so any property that isn't
14: * declared will be assumed to be metadata and written to the database
15: * as metadata on the object. All children classes must declare which
16: * properties are columns of the type table or they will be assumed
17: * to be metadata. See ElggObject::initialise_entities() for examples.
18: *
19: * Core supports 4 types of entities: ElggObject, ElggUser, ElggGroup, and
20: * ElggSite.
21: *
22: * @tip Most plugin authors will want to extend the ElggObject class
23: * instead of this class.
24: *
25: * @package Elgg.Core
26: * @subpackage DataModel.Entities
27: *
28: * @property string $type object, user, group, or site (read-only after save)
29: * @property string $subtype Further clarifies the nature of the entity (read-only after save)
30: * @property int $guid The unique identifier for this entity (read only)
31: * @property int $owner_guid The GUID of the creator of this entity
32: * @property int $container_guid The GUID of the entity containing this entity
33: * @property int $site_guid The GUID of the website this entity is associated with
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 (read-only, set on first save)
36: * @property int $time_updated A UNIX timestamp of when the entity was last updated (automatically updated on save)
37: * @property-read string $enabled
38: */
39: abstract class ElggEntity extends ElggData implements
40: Notable, // Calendar interface
41: Locatable, // Geocoding interface
42: Importable // Allow import of data
43: {
44:
45: /**
46: * If set, overrides the value of getURL()
47: */
48: protected $url_override;
49:
50: /**
51: * Icon override, overrides the value of getIcon().
52: */
53: protected $icon_override;
54:
55: /**
56: * Holds metadata until entity is saved. Once the entity is saved,
57: * metadata are written immediately to the database.
58: */
59: protected $temp_metadata = array();
60:
61: /**
62: * Holds annotations until entity is saved. Once the entity is saved,
63: * annotations are written immediately to the database.
64: */
65: protected $temp_annotations = array();
66:
67: /**
68: * Holds private settings until entity is saved. Once the entity is saved,
69: * private settings are written immediately to the database.
70: */
71: protected $temp_private_settings = array();
72:
73: /**
74: * Volatile data structure for this object, allows for storage of data
75: * in-memory that isn't sync'd back to the metadata table.
76: */
77: protected $volatile = array();
78:
79: /**
80: * Initialize the attributes array.
81: *
82: * This is vital to distinguish between metadata and base parameters.
83: *
84: * @return void
85: */
86: protected function initializeAttributes() {
87: parent::initializeAttributes();
88:
89: $this->attributes['guid'] = NULL;
90: $this->attributes['type'] = NULL;
91: $this->attributes['subtype'] = NULL;
92:
93: $this->attributes['owner_guid'] = elgg_get_logged_in_user_guid();
94: $this->attributes['container_guid'] = elgg_get_logged_in_user_guid();
95:
96: $this->attributes['site_guid'] = NULL;
97: $this->attributes['access_id'] = ACCESS_PRIVATE;
98: $this->attributes['time_created'] = NULL;
99: $this->attributes['time_updated'] = NULL;
100: $this->attributes['last_action'] = NULL;
101: $this->attributes['enabled'] = "yes";
102:
103: // There now follows a bit of a hack
104: /* Problem: To speed things up, some objects are split over several tables,
105: * this means that it requires n number of database reads to fully populate
106: * an entity. This causes problems for caching and create events
107: * since it is not possible to tell whether a subclassed entity is complete.
108: *
109: * Solution: We have two counters, one 'tables_split' which tells whatever is
110: * interested how many tables are going to need to be searched in order to fully
111: * populate this object, and 'tables_loaded' which is how many have been
112: * loaded thus far.
113: *
114: * If the two are the same then this object is complete.
115: *
116: * Use: isFullyLoaded() to check
117: */
118: $this->attributes['tables_split'] = 1;
119: $this->attributes['tables_loaded'] = 0;
120: }
121:
122: /**
123: * Clone an entity
124: *
125: * Resets the guid so that the entity can be saved as a distinct entity from
126: * the original. Creation time will be set when this new entity is saved.
127: * The owner and container guids come from the original entity. The clone
128: * method copies metadata but does not copy annotations or private settings.
129: *
130: * @note metadata will have its owner and access id set when the entity is saved
131: * and it will be the same as that of the entity.
132: *
133: * @return void
134: */
135: public function __clone() {
136: $orig_entity = get_entity($this->guid);
137: if (!$orig_entity) {
138: elgg_log("Failed to clone entity with GUID $this->guid", "ERROR");
139: return;
140: }
141:
142: $metadata_array = elgg_get_metadata(array(
143: 'guid' => $this->guid,
144: 'limit' => 0
145: ));
146:
147: $this->attributes['guid'] = "";
148:
149: $this->attributes['subtype'] = $orig_entity->getSubtype();
150:
151: // copy metadata over to new entity - slightly convoluted due to
152: // handling of metadata arrays
153: if (is_array($metadata_array)) {
154: // create list of metadata names
155: $metadata_names = array();
156: foreach ($metadata_array as $metadata) {
157: $metadata_names[] = $metadata['name'];
158: }
159: // arrays are stored with multiple enties per name
160: $metadata_names = array_unique($metadata_names);
161:
162: // move the metadata over
163: foreach ($metadata_names as $name) {
164: $this->set($name, $orig_entity->$name);
165: }
166: }
167: }
168:
169: /**
170: * Return the value of a property.
171: *
172: * If $name is defined in $this->attributes that value is returned, otherwise it will
173: * pull from the entity's metadata.
174: *
175: * Q: Why are we not using __get overload here?
176: * A: Because overload operators cause problems during subclassing, so we put the code here and
177: * create overloads in subclasses.
178: *
179: * @todo What problems are these?
180: *
181: * @warning Subtype is returned as an id rather than the subtype string. Use getSubtype()
182: * to get the subtype string.
183: *
184: * @param string $name Name
185: *
186: * @return mixed Returns the value of a given value, or null.
187: */
188: public function get($name) {
189: // See if its in our base attributes
190: if (array_key_exists($name, $this->attributes)) {
191: return $this->attributes[$name];
192: }
193:
194: // No, so see if its in the meta data for this entity
195: $meta = $this->getMetaData($name);
196:
197: // getMetaData returns NULL if $name is not found
198: return $meta;
199: }
200:
201: /**
202: * Sets the value of a property.
203: *
204: * If $name is defined in $this->attributes that value is set, otherwise it is
205: * saved as metadata.
206: *
207: * @warning Metadata set this way will inherit the entity's owner and access ID. If you want
208: * to set metadata with a different owner, use create_metadata().
209: *
210: * @warning It is important that your class populates $this->attributes with keys
211: * for all base attributes, anything not in their gets set as METADATA.
212: *
213: * Q: Why are we not using __set overload here?
214: * A: Because overload operators cause problems during subclassing, so we put the code here and
215: * create overloads in subclasses.
216: *
217: * @todo What problems?
218: *
219: * @param string $name Name
220: * @param mixed $value Value
221: *
222: * @return bool
223: */
224: public function set($name, $value) {
225: if (array_key_exists($name, $this->attributes)) {
226: // Certain properties should not be manually changed!
227: switch ($name) {
228: case 'guid':
229: case 'time_updated':
230: case 'last_action':
231: return FALSE;
232: break;
233: default:
234: $this->attributes[$name] = $value;
235: break;
236: }
237: } else {
238: return $this->setMetaData($name, $value);
239: }
240:
241: return TRUE;
242: }
243:
244: /**
245: * Return the value of a piece of metadata.
246: *
247: * @param string $name Name
248: *
249: * @return mixed The value, or NULL if not found.
250: */
251: public function getMetaData($name) {
252: $guid = $this->getGUID();
253:
254: if (! $guid) {
255: if (isset($this->temp_metadata[$name])) {
256: // md is returned as an array only if more than 1 entry
257: if (count($this->temp_metadata[$name]) == 1) {
258: return $this->temp_metadata[$name][0];
259: } else {
260: return $this->temp_metadata[$name];
261: }
262: } else {
263: return null;
264: }
265: }
266:
267: // upon first cache miss, just load/cache all the metadata and retry.
268: // if this works, the rest of this function may not be needed!
269: $cache = elgg_get_metadata_cache();
270: if ($cache->isKnown($guid, $name)) {
271: return $cache->load($guid, $name);
272: } else {
273: $cache->populateFromEntities(array($guid));
274: // in case ignore_access was on, we have to check again...
275: if ($cache->isKnown($guid, $name)) {
276: return $cache->load($guid, $name);
277: }
278: }
279:
280: $md = elgg_get_metadata(array(
281: 'guid' => $guid,
282: 'metadata_name' => $name,
283: 'limit' => 0,
284: ));
285:
286: $value = null;
287:
288: if ($md && !is_array($md)) {
289: $value = $md->value;
290: } elseif (count($md) == 1) {
291: $value = $md[0]->value;
292: } else if ($md && is_array($md)) {
293: $value = metadata_array_to_values($md);
294: }
295:
296: $cache->save($guid, $name, $value);
297:
298: return $value;
299: }
300:
301: /**
302: * Unset a property from metadata or attribute.
303: *
304: * @warning If you use this to unset an attribute, you must save the object!
305: *
306: * @param string $name The name of the attribute or metadata.
307: *
308: * @return void
309: */
310: function __unset($name) {
311: if (array_key_exists($name, $this->attributes)) {
312: $this->attributes[$name] = "";
313: } else {
314: $this->deleteMetadata($name);
315: }
316: }
317:
318: /**
319: * Set a piece of metadata.
320: *
321: * Plugin authors should use the magic methods or create_metadata().
322: *
323: * @warning The metadata will inherit the parent entity's owner and access ID.
324: * If you want to write metadata with a different owner, use create_metadata().
325: *
326: * @access private
327: *
328: * @param string $name Name of the metadata
329: * @param mixed $value Value of the metadata (doesn't support assoc arrays)
330: * @param string $value_type Types supported: integer and string. Will auto-identify if not set
331: * @param bool $multiple Allow multiple values for a single name (doesn't support assoc arrays)
332: *
333: * @return bool
334: */
335: public function setMetaData($name, $value, $value_type = null, $multiple = false) {
336:
337: // normalize value to an array that we will loop over
338: // remove indexes if value already an array.
339: if (is_array($value)) {
340: $value = array_values($value);
341: } else {
342: $value = array($value);
343: }
344:
345: // saved entity. persist md to db.
346: if ($this->guid) {
347: // if overwriting, delete first.
348: if (!$multiple) {
349: $options = array(
350: 'guid' => $this->getGUID(),
351: 'metadata_name' => $name,
352: 'limit' => 0
353: );
354: // @todo in 1.9 make this return false if can't add metadata
355: // http://trac.elgg.org/ticket/4520
356: //
357: // need to remove access restrictions right now to delete
358: // because this is the expected behavior
359: $ia = elgg_set_ignore_access(true);
360: if (false === elgg_delete_metadata($options)) {
361: return false;
362: }
363: elgg_set_ignore_access($ia);
364: }
365:
366: // add new md
367: $result = true;
368: foreach ($value as $value_tmp) {
369: // at this point $value should be appended because it was cleared above if needed.
370: $md_id = create_metadata($this->getGUID(), $name, $value_tmp, $value_type,
371: $this->getOwnerGUID(), $this->getAccessId(), true);
372: if (!$md_id) {
373: return false;
374: }
375: }
376:
377: return $result;
378: } else {
379: // unsaved entity. store in temp array
380: // returning single entries instead of an array of 1 element is decided in
381: // getMetaData(), just like pulling from the db.
382: //
383: // if overwrite, delete first
384: if (!$multiple || !isset($this->temp_metadata[$name])) {
385: $this->temp_metadata[$name] = array();
386: }
387:
388: // add new md
389: $this->temp_metadata[$name] = array_merge($this->temp_metadata[$name], $value);
390: return true;
391: }
392: }
393:
394: /**
395: * Deletes all metadata on this object (metadata.entity_guid = $this->guid).
396: * If you pass a name, only metadata matching that name will be deleted.
397: *
398: * @warning Calling this with no $name will clear all metadata on the entity.
399: *
400: * @param null|string $name The name of the metadata to remove.
401: * @return bool
402: * @since 1.8
403: */
404: public function deleteMetadata($name = null) {
405:
406: if (!$this->guid) {
407: return false;
408: }
409:
410: $options = array(
411: 'guid' => $this->guid,
412: 'limit' => 0
413: );
414: if ($name) {
415: $options['metadata_name'] = $name;
416: }
417:
418: return elgg_delete_metadata($options);
419: }
420:
421: /**
422: * Deletes all metadata owned by this object (metadata.owner_guid = $this->guid).
423: * If you pass a name, only metadata matching that name will be deleted.
424: *
425: * @param null|string $name The name of metadata to delete.
426: * @return bool
427: * @since 1.8
428: */
429: public function deleteOwnedMetadata($name = null) {
430: // access is turned off for this because they might
431: // no longer have access to an entity they created metadata on.
432: $ia = elgg_set_ignore_access(true);
433: $options = array(
434: 'metadata_owner_guid' => $this->guid,
435: 'limit' => 0
436: );
437: if ($name) {
438: $options['metadata_name'] = $name;
439: }
440:
441: $r = elgg_delete_metadata($options);
442: elgg_set_ignore_access($ia);
443: return $r;
444: }
445:
446: /**
447: * Remove metadata
448: *
449: * @warning Calling this with no or empty arguments will clear all metadata on the entity.
450: *
451: * @param string $name The name of the metadata to clear
452: * @return mixed bool
453: * @deprecated 1.8 Use deleteMetadata()
454: */
455: public function clearMetaData($name = '') {
456: elgg_deprecated_notice('ElggEntity->clearMetadata() is deprecated by ->deleteMetadata()', 1.8);
457: return $this->deleteMetadata($name);
458: }
459:
460: /**
461: * Disables metadata for this entity, optionally based on name.
462: *
463: * @param string $name An options name of metadata to disable.
464: * @return bool
465: * @since 1.8
466: */
467: public function disableMetadata($name = '') {
468: $options = array(
469: 'guid' => $this->guid,
470: 'limit' => 0
471: );
472: if ($name) {
473: $options['metadata_name'] = $name;
474: }
475:
476: return elgg_disable_metadata($options);
477: }
478:
479: /**
480: * Enables metadata for this entity, optionally based on name.
481: *
482: * @warning Before calling this, you must use {@link access_show_hidden_entities()}
483: *
484: * @param string $name An options name of metadata to enable.
485: * @return bool
486: * @since 1.8
487: */
488: public function enableMetadata($name = '') {
489: $options = array(
490: 'guid' => $this->guid,
491: 'limit' => 0
492: );
493: if ($name) {
494: $options['metadata_name'] = $name;
495: }
496:
497: return elgg_enable_metadata($options);
498: }
499:
500: /**
501: * Get a piece of volatile (non-persisted) data on this entity.
502: *
503: * @param string $name The name of the volatile data
504: *
505: * @return mixed The value or NULL if not found.
506: */
507: public function getVolatileData($name) {
508: if (!is_array($this->volatile)) {
509: $this->volatile = array();
510: }
511:
512: if (array_key_exists($name, $this->volatile)) {
513: return $this->volatile[$name];
514: } else {
515: return NULL;
516: }
517: }
518:
519: /**
520: * Set a piece of volatile (non-persisted) data on this entity
521: *
522: * @param string $name Name
523: * @param mixed $value Value
524: *
525: * @return void
526: */
527: public function setVolatileData($name, $value) {
528: if (!is_array($this->volatile)) {
529: $this->volatile = array();
530: }
531:
532: $this->volatile[$name] = $value;
533: }
534:
535: /**
536: * Remove all relationships to and from this entity.
537: *
538: * @return true
539: * @todo This should actually return if it worked.
540: * @see ElggEntity::addRelationship()
541: * @see ElggEntity::removeRelationship()
542: */
543: public function deleteRelationships() {
544: remove_entity_relationships($this->getGUID());
545: remove_entity_relationships($this->getGUID(), "", true);
546: return true;
547: }
548:
549: /**
550: * Remove all relationships to and from this entity.
551: *
552: * @return bool
553: * @see ElggEntity::addRelationship()
554: * @see ElggEntity::removeRelationship()
555: * @deprecated 1.8 Use ->deleteRelationship()
556: */
557: public function clearRelationships() {
558: elgg_deprecated_notice('ElggEntity->clearRelationships() is deprecated by ->deleteRelationships()', 1.8);
559: return $this->deleteRelationships();
560: }
561:
562: /**
563: * Add a relationship between this an another entity.
564: *
565: * @tip Read the relationship like "$guid is a $relationship of this entity."
566: *
567: * @param int $guid Entity to link to.
568: * @param string $relationship The type of relationship.
569: *
570: * @return bool
571: * @see ElggEntity::removeRelationship()
572: * @see ElggEntity::clearRelationships()
573: */
574: public function addRelationship($guid, $relationship) {
575: return add_entity_relationship($this->getGUID(), $relationship, $guid);
576: }
577:
578: /**
579: * Remove a relationship
580: *
581: * @param int $guid GUID of the entity to make a relationship with
582: * @param str $relationship Name of relationship
583: *
584: * @return bool
585: * @see ElggEntity::addRelationship()
586: * @see ElggEntity::clearRelationships()
587: */
588: public function removeRelationship($guid, $relationship) {
589: return remove_entity_relationship($this->getGUID(), $relationship, $guid);
590: }
591:
592: /**
593: * Adds a private setting to this entity.
594: *
595: * Private settings are similar to metadata but will not
596: * be searched and there are fewer helper functions for them.
597: *
598: * @param string $name Name of private setting
599: * @param mixed $value Value of private setting
600: *
601: * @return bool
602: */
603: function setPrivateSetting($name, $value) {
604: if ((int) $this->guid > 0) {
605: return set_private_setting($this->getGUID(), $name, $value);
606: } else {
607: $this->temp_private_settings[$name] = $value;
608: return true;
609: }
610: }
611:
612: /**
613: * Returns a private setting value
614: *
615: * @param string $name Name of the private setting
616: *
617: * @return mixed
618: */
619: function getPrivateSetting($name) {
620: if ((int) ($this->guid) > 0) {
621: return get_private_setting($this->getGUID(), $name);
622: } else {
623: if (isset($this->temp_private_settings[$name])) {
624: return $this->temp_private_settings[$name];
625: }
626: }
627: return null;
628: }
629:
630: /**
631: * Removes private setting
632: *
633: * @param string $name Name of the private setting
634: *
635: * @return bool
636: */
637: function removePrivateSetting($name) {
638: return remove_private_setting($this->getGUID(), $name);
639: }
640:
641: /**
642: * Deletes all annotations on this object (annotations.entity_guid = $this->guid).
643: * If you pass a name, only annotations matching that name will be deleted.
644: *
645: * @warning Calling this with no or empty arguments will clear all annotations on the entity.
646: *
647: * @param null|string $name The annotations name to remove.
648: * @return bool
649: * @since 1.8
650: */
651: public function deleteAnnotations($name = null) {
652: $options = array(
653: 'guid' => $this->guid,
654: 'limit' => 0
655: );
656: if ($name) {
657: $options['annotation_name'] = $name;
658: }
659:
660: return elgg_delete_annotations($options);
661: }
662:
663: /**
664: * Deletes all annotations owned by this object (annotations.owner_guid = $this->guid).
665: * If you pass a name, only annotations matching that name will be deleted.
666: *
667: * @param null|string $name The name of annotations to delete.
668: * @return bool
669: * @since 1.8
670: */
671: public function deleteOwnedAnnotations($name = null) {
672: // access is turned off for this because they might
673: // no longer have access to an entity they created annotations on.
674: $ia = elgg_set_ignore_access(true);
675: $options = array(
676: 'annotation_owner_guid' => $this->guid,
677: 'limit' => 0
678: );
679: if ($name) {
680: $options['annotation_name'] = $name;
681: }
682:
683: $r = elgg_delete_annotations($options);
684: elgg_set_ignore_access($ia);
685: return $r;
686: }
687:
688: /**
689: * Disables annotations for this entity, optionally based on name.
690: *
691: * @param string $name An options name of annotations to disable.
692: * @return bool
693: * @since 1.8
694: */
695: public function disableAnnotations($name = '') {
696: $options = array(
697: 'guid' => $this->guid,
698: 'limit' => 0
699: );
700: if ($name) {
701: $options['annotation_name'] = $name;
702: }
703:
704: return elgg_disable_annotations($options);
705: }
706:
707: /**
708: * Enables annotations for this entity, optionally based on name.
709: *
710: * @warning Before calling this, you must use {@link access_show_hidden_entities()}
711: *
712: * @param string $name An options name of annotations to enable.
713: * @return bool
714: * @since 1.8
715: */
716: public function enableAnnotations($name = '') {
717: $options = array(
718: 'guid' => $this->guid,
719: 'limit' => 0
720: );
721: if ($name) {
722: $options['annotation_name'] = $name;
723: }
724:
725: return elgg_enable_annotations($options);
726: }
727:
728: /**
729: * Helper function to return annotation calculation results
730: *
731: * @param string $name The annotation name.
732: * @param string $calculation A valid MySQL function to run its values through
733: * @return mixed
734: */
735: private function getAnnotationCalculation($name, $calculation) {
736: $options = array(
737: 'guid' => $this->getGUID(),
738: 'annotation_name' => $name,
739: 'annotation_calculation' => $calculation
740: );
741:
742: return elgg_get_annotations($options);
743: }
744:
745: /**
746: * Adds an annotation to an entity.
747: *
748: * @warning By default, annotations are private.
749: *
750: * @warning Annotating an unsaved entity more than once with the same name
751: * will only save the last annotation.
752: *
753: * @param string $name Annotation name
754: * @param mixed $value Annotation value
755: * @param int $access_id Access ID
756: * @param int $owner_id GUID of the annotation owner
757: * @param string $vartype The type of annotation value
758: *
759: * @return bool
760: */
761: function annotate($name, $value, $access_id = ACCESS_PRIVATE, $owner_id = 0, $vartype = "") {
762: if ((int) $this->guid > 0) {
763: return create_annotation($this->getGUID(), $name, $value, $vartype, $owner_id, $access_id);
764: } else {
765: $this->temp_annotations[$name] = $value;
766: }
767: return true;
768: }
769:
770: /**
771: * Returns an array of annotations.
772: *
773: * @param string $name Annotation name
774: * @param int $limit Limit
775: * @param int $offset Offset
776: * @param string $order Order by time: asc or desc
777: *
778: * @return array
779: */
780: function getAnnotations($name, $limit = 50, $offset = 0, $order = "asc") {
781: if ((int) ($this->guid) > 0) {
782:
783: $options = array(
784: 'guid' => $this->guid,
785: 'annotation_name' => $name,
786: 'limit' => $limit,
787: 'offset' => $offset,
788: );
789:
790: if ($order != 'asc') {
791: $options['reverse_order_by'] = true;
792: }
793:
794: return elgg_get_annotations($options);
795: } else if (isset($this->temp_annotations[$name])) {
796: return array($this->temp_annotations[$name]);
797: } else {
798: return array();
799: }
800: }
801:
802: /**
803: * Remove an annotation or all annotations for this entity.
804: *
805: * @warning Calling this method with no or an empty argument will remove
806: * all annotations on the entity.
807: *
808: * @param string $name Annotation name
809: * @return bool
810: * @deprecated 1.8 Use ->deleteAnnotations()
811: */
812: function clearAnnotations($name = "") {
813: elgg_deprecated_notice('ElggEntity->clearAnnotations() is deprecated by ->deleteAnnotations()', 1.8);
814: return $this->deleteAnnotations($name);
815: }
816:
817: /**
818: * Count annotations.
819: *
820: * @param string $name The type of annotation.
821: *
822: * @return int
823: */
824: function countAnnotations($name = "") {
825: return $this->getAnnotationCalculation($name, 'count');
826: }
827:
828: /**
829: * Get the average of an integer type annotation.
830: *
831: * @param string $name Annotation name
832: *
833: * @return int
834: */
835: function getAnnotationsAvg($name) {
836: return $this->getAnnotationCalculation($name, 'avg');
837: }
838:
839: /**
840: * Get the sum of integer type annotations of a given name.
841: *
842: * @param string $name Annotation name
843: *
844: * @return int
845: */
846: function getAnnotationsSum($name) {
847: return $this->getAnnotationCalculation($name, 'sum');
848: }
849:
850: /**
851: * Get the minimum of integer type annotations of given name.
852: *
853: * @param string $name Annotation name
854: *
855: * @return int
856: */
857: function getAnnotationsMin($name) {
858: return $this->getAnnotationCalculation($name, 'min');
859: }
860:
861: /**
862: * Get the maximum of integer type annotations of a given name.
863: *
864: * @param string $name Annotation name
865: *
866: * @return int
867: */
868: function getAnnotationsMax($name) {
869: return $this->getAnnotationCalculation($name, 'max');
870: }
871:
872: /**
873: * Count the number of comments attached to this entity.
874: *
875: * @return int Number of comments
876: * @since 1.8.0
877: */
878: function countComments() {
879: $params = array('entity' => $this);
880: $num = elgg_trigger_plugin_hook('comments:count', $this->getType(), $params);
881:
882: if (is_int($num)) {
883: return $num;
884: } else {
885: return $this->getAnnotationCalculation('generic_comment', 'count');
886: }
887: }
888:
889: /**
890: * Gets an array of entities with a relationship to this entity.
891: *
892: * @param string $relationship Relationship type (eg "friends")
893: * @param bool $inverse Is this an inverse relationship?
894: * @param int $limit Number of elements to return
895: * @param int $offset Indexing offset
896: *
897: * @return array|false An array of entities or false on failure
898: */
899: function getEntitiesFromRelationship($relationship, $inverse = false, $limit = 50, $offset = 0) {
900: return elgg_get_entities_from_relationship(array(
901: 'relationship' => $relationship,
902: 'relationship_guid' => $this->getGUID(),
903: 'inverse_relationship' => $inverse,
904: 'limit' => $limit,
905: 'offset' => $offset
906: ));
907: }
908:
909: /**
910: * Gets the number of of entities from a specific relationship type
911: *
912: * @param string $relationship Relationship type (eg "friends")
913: * @param bool $inverse_relationship Invert relationship
914: *
915: * @return int|false The number of entities or false on failure
916: */
917: function countEntitiesFromRelationship($relationship, $inverse_relationship = FALSE) {
918: return elgg_get_entities_from_relationship(array(
919: 'relationship' => $relationship,
920: 'relationship_guid' => $this->getGUID(),
921: 'inverse_relationship' => $inverse_relationship,
922: 'count' => TRUE
923: ));
924: }
925:
926: /**
927: * Can a user edit this entity.
928: *
929: * @param int $user_guid The user GUID, optionally (default: logged in user)
930: *
931: * @return bool
932: */
933: function canEdit($user_guid = 0) {
934: return can_edit_entity($this->getGUID(), $user_guid);
935: }
936:
937: /**
938: * Can a user edit metadata on this entity
939: *
940: * @param ElggMetadata $metadata The piece of metadata to specifically check
941: * @param int $user_guid The user GUID, optionally (default: logged in user)
942: *
943: * @return bool
944: */
945: function canEditMetadata($metadata = null, $user_guid = 0) {
946: return can_edit_entity_metadata($this->getGUID(), $user_guid, $metadata);
947: }
948:
949: /**
950: * Can a user add an entity to this container
951: *
952: * @param int $user_guid The user.
953: * @param string $type The type of entity we're looking to write
954: * @param string $subtype The subtype of the entity we're looking to write
955: *
956: * @return bool
957: */
958: public function canWriteToContainer($user_guid = 0, $type = 'all', $subtype = 'all') {
959: return can_write_to_container($user_guid, $this->guid, $type, $subtype);
960: }
961:
962: /**
963: * Can a user comment on an entity?
964: *
965: * @tip Can be overridden by registering for the permissions_check:comment,
966: * <entity type> plugin hook.
967: *
968: * @param int $user_guid User guid (default is logged in user)
969: *
970: * @return bool
971: */
972: public function canComment($user_guid = 0) {
973: if ($user_guid == 0) {
974: $user_guid = elgg_get_logged_in_user_guid();
975: }
976: $user = get_entity($user_guid);
977:
978: // By default, we don't take a position of whether commenting is allowed
979: // because it is handled by the subclasses of ElggEntity
980: $params = array('entity' => $this, 'user' => $user);
981: return elgg_trigger_plugin_hook('permissions_check:comment', $this->type, $params, null);
982: }
983:
984: /**
985: * Can a user annotate an entity?
986: *
987: * @tip Can be overridden by registering for the permissions_check:annotate,
988: * <entity type> plugin hook.
989: *
990: * @tip If you want logged out users to annotate an object, do not call
991: * canAnnotate(). It's easier than using the plugin hook.
992: *
993: * @param int $user_guid User guid (default is logged in user)
994: * @param string $annotation_name The name of the annotation (default is unspecified)
995: *
996: * @return bool
997: */
998: public function canAnnotate($user_guid = 0, $annotation_name = '') {
999: if ($user_guid == 0) {
1000: $user_guid = elgg_get_logged_in_user_guid();
1001: }
1002: $user = get_entity($user_guid);
1003:
1004: $return = true;
1005: if (!$user) {
1006: $return = false;
1007: }
1008:
1009: $params = array(
1010: 'entity' => $this,
1011: 'user' => $user,
1012: 'annotation_name' => $annotation_name,
1013: );
1014: return elgg_trigger_plugin_hook('permissions_check:annotate', $this->type, $params, $return);
1015: }
1016:
1017: /**
1018: * Returns the access_id.
1019: *
1020: * @return int The access ID
1021: */
1022: public function getAccessID() {
1023: return $this->get('access_id');
1024: }
1025:
1026: /**
1027: * Returns the guid.
1028: *
1029: * @return int|null GUID
1030: */
1031: public function getGUID() {
1032: return $this->get('guid');
1033: }
1034:
1035: /**
1036: * Returns the entity type
1037: *
1038: * @return string Entity type
1039: */
1040: public function getType() {
1041: return $this->get('type');
1042: }
1043:
1044: /**
1045: * Returns the entity subtype string
1046: *
1047: * @note This returns a string. If you want the id, use ElggEntity::subtype.
1048: *
1049: * @return string The entity subtype
1050: */
1051: public function getSubtype() {
1052: // If this object hasn't been saved, then return the subtype string.
1053: if (!((int) $this->guid > 0)) {
1054: return $this->get('subtype');
1055: }
1056:
1057: return get_subtype_from_id($this->get('subtype'));
1058: }
1059:
1060: /**
1061: * Get the guid of the entity's owner.
1062: *
1063: * @return int The owner GUID
1064: */
1065: public function getOwnerGUID() {
1066: return $this->owner_guid;
1067: }
1068:
1069: /**
1070: * Return the guid of the entity's owner.
1071: *
1072: * @return int The owner GUID
1073: * @deprecated 1.8 Use getOwnerGUID()
1074: */
1075: public function getOwner() {
1076: elgg_deprecated_notice("ElggEntity::getOwner deprecated for ElggEntity::getOwnerGUID", 1.8);
1077: return $this->getOwnerGUID();
1078: }
1079:
1080: /**
1081: * Gets the ElggEntity that owns this entity.
1082: *
1083: * @return ElggEntity The owning entity
1084: */
1085: public function getOwnerEntity() {
1086: return get_entity($this->owner_guid);
1087: }
1088:
1089: /**
1090: * Set the container for this object.
1091: *
1092: * @param int $container_guid The ID of the container.
1093: *
1094: * @return bool
1095: */
1096: public function setContainerGUID($container_guid) {
1097: $container_guid = (int)$container_guid;
1098:
1099: return $this->set('container_guid', $container_guid);
1100: }
1101:
1102: /**
1103: * Set the container for this object.
1104: *
1105: * @param int $container_guid The ID of the container.
1106: *
1107: * @return bool
1108: * @deprecated 1.8 use setContainerGUID()
1109: */
1110: public function setContainer($container_guid) {
1111: elgg_deprecated_notice("ElggObject::setContainer deprecated for ElggEntity::setContainerGUID", 1.8);
1112: $container_guid = (int)$container_guid;
1113:
1114: return $this->set('container_guid', $container_guid);
1115: }
1116:
1117: /**
1118: * Gets the container GUID for this entity.
1119: *
1120: * @return int
1121: */
1122: public function getContainerGUID() {
1123: return $this->get('container_guid');
1124: }
1125:
1126: /**
1127: * Gets the container GUID for this entity.
1128: *
1129: * @return int
1130: * @deprecated 1.8 Use getContainerGUID()
1131: */
1132: public function getContainer() {
1133: elgg_deprecated_notice("ElggObject::getContainer deprecated for ElggEntity::getContainerGUID", 1.8);
1134: return $this->get('container_guid');
1135: }
1136:
1137: /**
1138: * Get the container entity for this object.
1139: *
1140: * @return ElggEntity
1141: * @since 1.8.0
1142: */
1143: public function getContainerEntity() {
1144: return get_entity($this->getContainerGUID());
1145: }
1146:
1147: /**
1148: * Returns the UNIX epoch time that this entity was last updated
1149: *
1150: * @return int UNIX epoch time
1151: */
1152: public function getTimeUpdated() {
1153: return $this->get('time_updated');
1154: }
1155:
1156: /**
1157: * Returns the URL for this entity
1158: *
1159: * @return string The URL
1160: * @see register_entity_url_handler()
1161: * @see ElggEntity::setURL()
1162: */
1163: public function getURL() {
1164: if (!empty($this->url_override)) {
1165: return $this->url_override;
1166: }
1167: return get_entity_url($this->getGUID());
1168: }
1169:
1170: /**
1171: * Overrides the URL returned by getURL()
1172: *
1173: * @warning This override exists only for the life of the object.
1174: *
1175: * @param string $url The new item URL
1176: *
1177: * @return string The URL
1178: */
1179: public function setURL($url) {
1180: $this->url_override = $url;
1181: return $url;
1182: }
1183:
1184: /**
1185: * Get the URL for this entity's icon
1186: *
1187: * Plugins can register for the 'entity:icon:url', <type> plugin hook
1188: * to customize the icon for an entity.
1189: *
1190: * @param string $size Size of the icon: tiny, small, medium, large
1191: *
1192: * @return string The URL
1193: * @since 1.8.0
1194: */
1195: public function getIconURL($size = 'medium') {
1196: $size = elgg_strtolower($size);
1197:
1198: if (isset($this->icon_override[$size])) {
1199: elgg_deprecated_notice("icon_override on an individual entity is deprecated", 1.8);
1200: return $this->icon_override[$size];
1201: }
1202:
1203: $type = $this->getType();
1204: $params = array(
1205: 'entity' => $this,
1206: 'size' => $size,
1207: );
1208:
1209: $url = elgg_trigger_plugin_hook('entity:icon:url', $type, $params, null);
1210: if ($url == null) {
1211: $url = "_graphics/icons/default/$size.png";
1212: }
1213:
1214: return elgg_normalize_url($url);
1215: }
1216:
1217: /**
1218: * Returns a URL for the entity's icon.
1219: *
1220: * @param string $size Either 'large', 'medium', 'small' or 'tiny'
1221: *
1222: * @return string The url or false if no url could be worked out.
1223: * @deprecated Use getIconURL()
1224: */
1225: public function getIcon($size = 'medium') {
1226: elgg_deprecated_notice("getIcon() deprecated by getIconURL()", 1.8);
1227: return $this->getIconURL($size);
1228: }
1229:
1230: /**
1231: * Set an icon override for an icon and size.
1232: *
1233: * @warning This override exists only for the life of the object.
1234: *
1235: * @param string $url The url of the icon.
1236: * @param string $size The size its for.
1237: *
1238: * @return bool
1239: * @deprecated 1.8 See getIconURL() for the plugin hook to use
1240: */
1241: public function setIcon($url, $size = 'medium') {
1242: elgg_deprecated_notice("icon_override on an individual entity is deprecated", 1.8);
1243:
1244: $url = sanitise_string($url);
1245: $size = sanitise_string($size);
1246:
1247: if (!$this->icon_override) {
1248: $this->icon_override = array();
1249: }
1250: $this->icon_override[$size] = $url;
1251:
1252: return true;
1253: }
1254:
1255: /**
1256: * Tests to see whether the object has been fully loaded.
1257: *
1258: * @return bool
1259: */
1260: public function isFullyLoaded() {
1261: return ! ($this->attributes['tables_loaded'] < $this->attributes['tables_split']);
1262: }
1263:
1264: /**
1265: * Save an entity.
1266: *
1267: * @return bool|int
1268: * @throws IOException
1269: */
1270: public function save() {
1271: $guid = $this->getGUID();
1272: if ($guid > 0) {
1273:
1274: // See #5600. This ensures the lower level can_edit_entity() check will use a
1275: // fresh entity from the DB so it sees the persisted owner_guid
1276: _elgg_disable_caching_for_entity($guid);
1277:
1278: $ret = update_entity(
1279: $guid,
1280: $this->get('owner_guid'),
1281: $this->get('access_id'),
1282: $this->get('container_guid'),
1283: $this->get('time_created')
1284: );
1285:
1286: _elgg_enable_caching_for_entity($guid);
1287: _elgg_cache_entity($this);
1288:
1289: return $ret;
1290: } else {
1291: // Create a new entity (nb: using attribute array directly
1292: // 'cos set function does something special!)
1293: $this->attributes['guid'] = create_entity($this->attributes['type'],
1294: $this->attributes['subtype'], $this->attributes['owner_guid'],
1295: $this->attributes['access_id'], $this->attributes['site_guid'],
1296: $this->attributes['container_guid']);
1297:
1298: if (!$this->attributes['guid']) {
1299: throw new IOException(elgg_echo('IOException:BaseEntitySaveFailed'));
1300: }
1301:
1302: // Save any unsaved metadata
1303: // @todo How to capture extra information (access id etc)
1304: if (sizeof($this->temp_metadata) > 0) {
1305: foreach ($this->temp_metadata as $name => $value) {
1306: $this->$name = $value;
1307: unset($this->temp_metadata[$name]);
1308: }
1309: }
1310:
1311: // Save any unsaved annotations.
1312: if (sizeof($this->temp_annotations) > 0) {
1313: foreach ($this->temp_annotations as $name => $value) {
1314: $this->annotate($name, $value);
1315: unset($this->temp_annotations[$name]);
1316: }
1317: }
1318:
1319: // Save any unsaved private settings.
1320: if (sizeof($this->temp_private_settings) > 0) {
1321: foreach ($this->temp_private_settings as $name => $value) {
1322: $this->setPrivateSetting($name, $value);
1323: unset($this->temp_private_settings[$name]);
1324: }
1325: }
1326:
1327: // set the subtype to id now rather than a string
1328: $this->attributes['subtype'] = get_subtype_id($this->attributes['type'],
1329: $this->attributes['subtype']);
1330:
1331: _elgg_cache_entity($this);
1332:
1333: return $this->attributes['guid'];
1334: }
1335: }
1336:
1337: /**
1338: * Loads attributes from the entities table into the object.
1339: *
1340: * @param mixed $guid GUID of entity or stdClass object from entities table
1341: *
1342: * @return bool
1343: */
1344: protected function load($guid) {
1345: if ($guid instanceof stdClass) {
1346: $row = $guid;
1347: } else {
1348: $row = get_entity_as_row($guid);
1349: }
1350:
1351: if ($row) {
1352: // Create the array if necessary - all subclasses should test before creating
1353: if (!is_array($this->attributes)) {
1354: $this->attributes = array();
1355: }
1356:
1357: // Now put these into the attributes array as core values
1358: $objarray = (array) $row;
1359: foreach ($objarray as $key => $value) {
1360: $this->attributes[$key] = $value;
1361: }
1362:
1363: // Increment the portion counter
1364: if (!$this->isFullyLoaded()) {
1365: $this->attributes['tables_loaded']++;
1366: }
1367:
1368: // guid needs to be an int http://trac.elgg.org/ticket/4111
1369: $this->attributes['guid'] = (int)$this->attributes['guid'];
1370:
1371: // Cache object handle
1372: if ($this->attributes['guid']) {
1373: _elgg_cache_entity($this);
1374: }
1375:
1376: return true;
1377: }
1378:
1379: return false;
1380: }
1381:
1382: /**
1383: * Disable this entity.
1384: *
1385: * Disabled entities are not returned by getter functions.
1386: * To enable an entity, use {@link enable_entity()}.
1387: *
1388: * Recursively disabling an entity will disable all entities
1389: * owned or contained by the parent entity.
1390: *
1391: * @internal Disabling an entity sets the 'enabled' column to 'no'.
1392: *
1393: * @param string $reason Optional reason
1394: * @param bool $recursive Recursively disable all contained entities?
1395: *
1396: * @return bool
1397: * @see enable_entity()
1398: * @see ElggEntity::enable()
1399: */
1400: public function disable($reason = "", $recursive = true) {
1401: if ($r = disable_entity($this->get('guid'), $reason, $recursive)) {
1402: $this->attributes['enabled'] = 'no';
1403: }
1404:
1405: return $r;
1406: }
1407:
1408: /**
1409: * Enable an entity
1410: *
1411: * @warning Disabled entities can't be loaded unless
1412: * {@link access_show_hidden_entities(true)} has been called.
1413: *
1414: * @see enable_entity()
1415: * @see access_show_hiden_entities()
1416: * @return bool
1417: */
1418: public function enable() {
1419: if ($r = enable_entity($this->get('guid'))) {
1420: $this->attributes['enabled'] = 'yes';
1421: }
1422:
1423: return $r;
1424: }
1425:
1426: /**
1427: * Is this entity enabled?
1428: *
1429: * @return boolean
1430: */
1431: public function isEnabled() {
1432: if ($this->enabled == 'yes') {
1433: return true;
1434: }
1435:
1436: return false;
1437: }
1438:
1439: /**
1440: * Delete this entity.
1441: *
1442: * @param bool $recursive Whether to delete all the entities contained by this entity
1443: *
1444: * @return bool
1445: */
1446: public function delete($recursive = true) {
1447: return delete_entity($this->get('guid'), $recursive);
1448: }
1449:
1450: /*
1451: * LOCATABLE INTERFACE
1452: */
1453:
1454: /**
1455: * Gets the 'location' metadata for the entity
1456: *
1457: * @return string The location
1458: */
1459: public function getLocation() {
1460: return $this->location;
1461: }
1462:
1463: /**
1464: * Sets the 'location' metadata for the entity
1465: *
1466: * @todo Unimplemented
1467: *
1468: * @param string $location String representation of the location
1469: *
1470: * @return bool
1471: */
1472: public function setLocation($location) {
1473: $this->location = $location;
1474: return true;
1475: }
1476:
1477: /**
1478: * Set latitude and longitude metadata tags for a given entity.
1479: *
1480: * @param float $lat Latitude
1481: * @param float $long Longitude
1482: *
1483: * @return bool
1484: * @todo Unimplemented
1485: */
1486: public function setLatLong($lat, $long) {
1487: $this->set('geo:lat', $lat);
1488: $this->set('geo:long', $long);
1489:
1490: return true;
1491: }
1492:
1493: /**
1494: * Return the entity's latitude.
1495: *
1496: * @return float
1497: * @todo Unimplemented
1498: */
1499: public function getLatitude() {
1500: return (float)$this->get('geo:lat');
1501: }
1502:
1503: /**
1504: * Return the entity's longitude
1505: *
1506: * @return float
1507: */
1508: public function getLongitude() {
1509: return (float)$this->get('geo:long');
1510: }
1511:
1512: /*
1513: * NOTABLE INTERFACE
1514: */
1515:
1516: /**
1517: * Set the time and duration of an object
1518: *
1519: * @param int $hour If ommitted, now is assumed.
1520: * @param int $minute If ommitted, now is assumed.
1521: * @param int $second If ommitted, now is assumed.
1522: * @param int $day If ommitted, now is assumed.
1523: * @param int $month If ommitted, now is assumed.
1524: * @param int $year If ommitted, now is assumed.
1525: * @param int $duration Duration of event, remainder of the day is assumed.
1526: *
1527: * @return true
1528: * @todo Unimplemented
1529: */
1530: public function setCalendarTimeAndDuration($hour = NULL, $minute = NULL, $second = NULL,
1531: $day = NULL, $month = NULL, $year = NULL, $duration = NULL) {
1532:
1533: $start = mktime($hour, $minute, $second, $month, $day, $year);
1534: $end = $start + abs($duration);
1535: if (!$duration) {
1536: $end = get_day_end($day, $month, $year);
1537: }
1538:
1539: $this->calendar_start = $start;
1540: $this->calendar_end = $end;
1541:
1542: return true;
1543: }
1544:
1545: /**
1546: * Returns the start timestamp.
1547: *
1548: * @return int
1549: * @todo Unimplemented
1550: */
1551: public function getCalendarStartTime() {
1552: return (int)$this->calendar_start;
1553: }
1554:
1555: /**
1556: * Returns the end timestamp.
1557: *
1558: * @todo Unimplemented
1559: *
1560: * @return int
1561: */
1562: public function getCalendarEndTime() {
1563: return (int)$this->calendar_end;
1564: }
1565:
1566: /*
1567: * EXPORTABLE INTERFACE
1568: */
1569:
1570: /**
1571: * Returns an array of fields which can be exported.
1572: *
1573: * @return array
1574: */
1575: public function getExportableValues() {
1576: return array(
1577: 'guid',
1578: 'type',
1579: 'subtype',
1580: 'time_created',
1581: 'time_updated',
1582: 'container_guid',
1583: 'owner_guid',
1584: 'site_guid'
1585: );
1586: }
1587:
1588: /**
1589: * Export this class into an array of ODD Elements containing all necessary fields.
1590: * Override if you wish to return more information than can be found in
1591: * $this->attributes (shouldn't happen)
1592: *
1593: * @return array
1594: */
1595: public function export() {
1596: $tmp = array();
1597:
1598: // Generate uuid
1599: $uuid = guid_to_uuid($this->getGUID());
1600:
1601: // Create entity
1602: $odd = new ODDEntity(
1603: $uuid,
1604: $this->attributes['type'],
1605: get_subtype_from_id($this->attributes['subtype'])
1606: );
1607:
1608: $tmp[] = $odd;
1609:
1610: $exportable_values = $this->getExportableValues();
1611:
1612: // Now add its attributes
1613: foreach ($this->attributes as $k => $v) {
1614: $meta = NULL;
1615:
1616: if (in_array($k, $exportable_values)) {
1617: switch ($k) {
1618: case 'guid': // Dont use guid in OpenDD
1619: case 'type': // Type and subtype already taken care of
1620: case 'subtype':
1621: break;
1622:
1623: case 'time_created': // Created = published
1624: $odd->setAttribute('published', date("r", $v));
1625: break;
1626:
1627: case 'site_guid': // Container
1628: $k = 'site_uuid';
1629: $v = guid_to_uuid($v);
1630: $meta = new ODDMetaData($uuid . "attr/$k/", $uuid, $k, $v);
1631: break;
1632:
1633: case 'container_guid': // Container
1634: $k = 'container_uuid';
1635: $v = guid_to_uuid($v);
1636: $meta = new ODDMetaData($uuid . "attr/$k/", $uuid, $k, $v);
1637: break;
1638:
1639: case 'owner_guid': // Convert owner guid to uuid, this will be stored in metadata
1640: $k = 'owner_uuid';
1641: $v = guid_to_uuid($v);
1642: $meta = new ODDMetaData($uuid . "attr/$k/", $uuid, $k, $v);
1643: break;
1644:
1645: default:
1646: $meta = new ODDMetaData($uuid . "attr/$k/", $uuid, $k, $v);
1647: }
1648:
1649: // set the time of any metadata created
1650: if ($meta) {
1651: $meta->setAttribute('published', date("r", $this->time_created));
1652: $tmp[] = $meta;
1653: }
1654: }
1655: }
1656:
1657: // Now we do something a bit special.
1658: /*
1659: * This provides a rendered view of the entity to foreign sites.
1660: */
1661:
1662: elgg_set_viewtype('default');
1663: $view = elgg_view_entity($this, array('full_view' => true));
1664: elgg_set_viewtype();
1665:
1666: $tmp[] = new ODDMetaData($uuid . "volatile/renderedentity/", $uuid,
1667: 'renderedentity', $view, 'volatile');
1668:
1669: return $tmp;
1670: }
1671:
1672: /*
1673: * IMPORTABLE INTERFACE
1674: */
1675:
1676: /**
1677: * Import data from an parsed ODD xml data array.
1678: *
1679: * @param ODD $data XML data
1680: *
1681: * @return true
1682: *
1683: * @throws InvalidParameterException
1684: */
1685: public function import(ODD $data) {
1686: if (!($data instanceof ODDEntity)) {
1687: throw new InvalidParameterException(elgg_echo('InvalidParameterException:UnexpectedODDClass'));
1688: }
1689:
1690: // Set type and subtype
1691: $this->attributes['type'] = $data->getAttribute('class');
1692: $this->attributes['subtype'] = $data->getAttribute('subclass');
1693:
1694: // Set owner
1695: $this->attributes['owner_guid'] = elgg_get_logged_in_user_guid(); // Import as belonging to importer.
1696:
1697: // Set time
1698: $this->attributes['time_created'] = strtotime($data->getAttribute('published'));
1699: $this->attributes['time_updated'] = time();
1700:
1701: return true;
1702: }
1703:
1704: /*
1705: * SYSTEM LOG INTERFACE
1706: */
1707:
1708: /**
1709: * Return an identification for the object for storage in the system log.
1710: * This id must be an integer.
1711: *
1712: * @return int
1713: */
1714: public function getSystemLogID() {
1715: return $this->getGUID();
1716: }
1717:
1718: /**
1719: * For a given ID, return the object associated with it.
1720: * This is used by the river functionality primarily.
1721: *
1722: * This is useful for checking access permissions etc on objects.
1723: *
1724: * @param int $id GUID.
1725: *
1726: * @todo How is this any different or more useful than get_entity($guid)
1727: * or new ElggEntity($guid)?
1728: *
1729: * @return int GUID
1730: */
1731: public function getObjectFromID($id) {
1732: return get_entity($id);
1733: }
1734:
1735: /**
1736: * Returns tags for this entity.
1737: *
1738: * @warning Tags must be registered by {@link elgg_register_tag_metadata_name()}.
1739: *
1740: * @param array $tag_names Optionally restrict by tag metadata names.
1741: *
1742: * @return array
1743: */
1744: public function getTags($tag_names = NULL) {
1745: if ($tag_names && !is_array($tag_names)) {
1746: $tag_names = array($tag_names);
1747: }
1748:
1749: $valid_tags = elgg_get_registered_tag_metadata_names();
1750: $entity_tags = array();
1751:
1752: foreach ($valid_tags as $tag_name) {
1753: if (is_array($tag_names) && !in_array($tag_name, $tag_names)) {
1754: continue;
1755: }
1756:
1757: if ($tags = $this->$tag_name) {
1758: // if a single tag, metadata returns a string.
1759: // if multiple tags, metadata returns an array.
1760: if (is_array($tags)) {
1761: $entity_tags = array_merge($entity_tags, $tags);
1762: } else {
1763: $entity_tags[] = $tags;
1764: }
1765: }
1766: }
1767:
1768: return $entity_tags;
1769: }
1770: }
1771: