Overview

Packages

  • ClipIt
    • clipit
      • api
    • urjc
      • backend
  • Elgg
    • Core
      • Access
      • Authentication
      • Cache
      • Caches
      • Core
      • DataMode
        • Site
      • DataModel
        • Annotations
        • Entities
        • Extender
        • File
        • Importable
        • Loggable
        • Notable
        • Object
        • User
      • DataStorage
      • Exception
      • Exceptions
        • Stub
      • FileStore
        • Disk
      • Groups
      • Helpers
      • HMAC
      • Memcache
      • Metadata
      • Navigation
      • ODD
      • Output
      • Plugins
        • Settings
      • Sessions
      • SocialModel
        • Friendable
        • Locatable
      • WebServicesAPI
      • Widgets
      • XML
      • XMLRPC
    • Exceptions
      • Stub
  • None
  • PHP

Classes

  • ElggEntity
  • Overview
  • Package
  • Class
  • Tree
   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: 
API documentation generated by ApiGen 2.8.0