GalleryEntity
* @g2 GalleryPersistent
* @g2
* @g2 1
* @g2 2
* @g2
*
* @package GalleryCore
* @subpackage Classes
* @author Bharat Mediratta
* @version $Revision: 17580 $
*/
class GalleryEntity extends GalleryPersistent {
/**
* The id of this item
* @var int
*
* @g2
* @g2 id
* @g2 INTEGER
* @g2
* @g2
* @g2 READ
* @g2
*/
var $id;
/**
* Date and time this item was created, in seconds since the epoch.
* @var int
*
* @g2
* @g2 creationTimestamp
* @g2 INTEGER
* @g2
* @g2
* @g2 FULL
* @g2
*/
var $creationTimestamp;
/**
* Does this entity type support linking?
* @var boolean
*
* @g2
* @g2 isLinkable
* @g2 BOOLEAN
* @g2
* @g2
* @g2
*/
var $isLinkable;
/**
* The id of the target entity this entity is linked to
* @var int
*
* @g2
* @g2 linkId
* @g2 INTEGER
* @g2
* @g2
*/
var $linkId;
/**
* The target entity this entity is linked to
* @var GalleryEntity
*/
var $linkedEntity;
/**
* Date and time this item was last modified, in seconds since the epoch.
* @var int
*
* @g2
* @g2 modificationTimestamp
* @g2 INTEGER
* @g2
* @g2
* @g2 READ
* @g2
*/
var $modificationTimestamp;
/**
* The serial number of this object in the persistent store. This value
* will help us to avoid collisions.
* @var int
*
* @g2
* @g2 serialNumber
* @g2 INTEGER
* @g2
* @g2
* @g2 READ
* @g2
*/
var $serialNumber;
/**
* The actual type of this object. This will allow the storage class to
* correctly load this object from the database.
* @var string
*
* @g2
* @g2 entityType
* @g2 STRING
* @g2 SMALL
* @g2
* @g2 READ
* @g2
*/
var $entityType;
/**
* Handlers to run when this entity is loaded.
* @var string
*
* @g2
* @g2 onLoadHandlers
* @g2 STRING
* @g2 MEDIUM
* @g2
*/
var $onLoadHandlers;
/**
* Create a new instance of this GalleryEntity in the persistent store
*
* @return GalleryStatus a status code
*/
function create() {
global $gallery;
/* Create a new instance of this entity in the persistent store */
$storage =& $gallery->getStorage();
$ret = $storage->newEntity($this);
if ($ret) {
return $ret;
}
/* Set the creation time on this entity */
$this->setCreationTimestamp(time());
/* Set the object type */
$this->setEntityType($className = $this->getClassName());
/*
* Make sure the entity defined its own class name. This is a little draconian;
* it requires that your entity name is the same as the get_class() version. We'd
* just use get_class for getClassName() except that it's always lowercase in PHP4.
* If this causes problems we could relax the check to just make sure that
* $this->getClassName() != 'GalleryEntity'
* but that wouldn't catch the case where one entity extends another one and forgets
* to override getClassName()
* Don't use strcasecmp or strtolower because they are affected by locale.
*/
if (($thisClass = get_class($this)) != $className && $thisClass
!= strtr($className, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz')) {
return GalleryCoreApi::error(ERROR_MISSING_VALUE, __FILE__, __LINE__,
sprintf('Entity %s did not override getClassName()',
get_class($this)));
}
/* By default, entities are not linkable; init other fields */
$this->setIsLinkable(false);
$this->setLinkId(null);
$this->setLinkedEntity(null);
$this->setOnLoadHandlers(null);
$ret = $this->resetOriginalValues(true);
if ($ret) {
return $ret;
}
return null;
}
/**
* Create a new linked version of this item into a new album
*
* @param GalleryEntity $entity the entity we're linking to
* @return array GalleryStatus a status code
* GalleryItem the linked item
*/
function createLink($entity) {
global $gallery;
if (get_class($this) != get_class($entity)) {
return GalleryCoreApi::error(ERROR_BAD_PARAMETER);
}
/* Follow our usual creation process (same as create() above) */
$storage =& $gallery->getStorage();
$ret = $storage->newEntity($this);
if ($ret) {
return $ret;
}
/* Set the creation time on this entity */
$this->setCreationTimestamp(time());
/* Set the object type */
$this->setEntityType($this->getClassName());
/* But attach to the linked entity */
$this->setIsLinkable(true);
$this->setLinkId($entity->getId());
$this->setLinkedEntity($entity);
$ret = $this->resetOriginalValues(true);
if ($ret) {
return $ret;
}
return null;
}
/**
* Save the changes to this GalleryEntity.
*
* @param bool $postEvent post a save event; only disable this during core upgrades
* @param int $setAclId (optional) ACL id to assign for new entity (used by subclasses)
* @return GalleryStatus a status code
*/
function save($postEvent=true, $setAclId=null) {
global $gallery;
/*
* Newly created objects don't need to be locked 'cause they're not in
* the database yet. Everything else does.
*/
if (!GalleryCoreApi::isWriteLocked($this->getId())
&& !$this->testPersistentFlag(STORAGE_FLAG_NEWLY_CREATED)) {
return GalleryCoreApi::error(ERROR_LOCK_REQUIRED);
}
if (isset($setAclId) && $this->testPersistentFlag(STORAGE_FLAG_NEWLY_CREATED)) {
$ret = GalleryCoreApi::addMapEntry('GalleryAccessSubscriberMap',
array('itemId' => $this->getId(), 'accessListId' => $setAclId));
if ($ret) {
return $ret;
}
}
if ($this->isModified()) {
/* Change the modification date */
$phpVm = $gallery->getPhpVm();
$this->setModificationTimestamp($phpVm->time());
if ($postEvent) {
$event = GalleryCoreApi::newEvent('GalleryEntity::save');
$event->setEntity($this);
list ($ret) = GalleryCoreApi::postEvent($event);
if ($ret) {
return $ret;
}
}
$storage =& $gallery->getStorage();
$changedEntityType = $this->isModified('entityType');
$ret = $storage->saveEntity($this);
if ($ret) {
return $ret;
}
/* Update our caches */
if ($changedEntityType) {
/*
* We changed the entity type which probably means that the entity class doesn't
* line up with its embedded entityType. Clear this from our cache so that the
* next load actually gets the clean, correct version.
*/
GalleryDataCache::remove(
sprintf('GalleryEntityHelper::loadEntitiesById(%s)', $this->getId()));
GalleryDataCache::removeFromDisk(
array('type' => 'entity', 'itemId' => $this->getId()));
} else {
GalleryDataCache::put(
sprintf('GalleryEntityHelper::loadEntitiesById(%s)', $this->getId()), $this);
list ($ret, $classFile) = $this->getClassFile();
if ($ret) {
return $ret;
}
GalleryDataCache::putToDisk(array('type' => 'entity', 'itemId' => $this->getId()),
$this, array($classFile));
}
}
return null;
}
/**
* Refresh this item from the persistent store
*
* @return array GalleryStatus a status code,
* object the refreshed GalleryEntity
*/
function refresh() {
global $gallery;
/* Are we trying to refresh an object that isn't in the database? */
if ($this->testPersistentFlag(STORAGE_FLAG_DELETED) ||
$this->testPersistentFlag(STORAGE_FLAG_NEWLY_CREATED)) {
return array(GalleryCoreApi::error(ERROR_MISSING_OBJECT),
null);
}
$storage =& $gallery->getStorage();
list ($ret, $freshEntity) = $storage->refreshEntity($this);
if ($ret) {
return array($ret, null);
}
return array(null, $freshEntity);
}
/**
* Delete this GalleryEntity
*
* @return GalleryStatus a status code
*/
function delete() {
global $gallery;
if (!GalleryCoreApi::isWriteLocked($this->getId())) {
return GalleryCoreApi::error(ERROR_LOCK_REQUIRED);
}
$event = GalleryCoreApi::newEvent('GalleryEntity::delete');
$event->setEntity($this);
list ($ret) = GalleryCoreApi::postEvent($event);
if ($ret) {
return $ret;
}
$ret = GalleryCoreApi::removePluginParametersForItemId($this->getId());
if ($ret) {
return $ret;
}
$ret = GalleryCoreApi::removeMapEntry(
'GalleryAccessSubscriberMap', array('itemId' => $this->getId()));
if ($ret) {
return $ret;
}
$storage =& $gallery->getStorage();
$ret = $storage->deleteEntity($this);
if ($ret) {
return $ret;
}
GalleryDataCache::remove(
sprintf('GalleryEntityHelper::loadEntitiesById(%s)', $this->getId()));
GalleryDataCache::removeFromDisk(array('type' => 'entity', 'itemId' => $this->getId()));
return null;
}
/**
* This is called after an entity is loaded by the GalleryStorage subsystem.
* Perform any actions that are required after loading the entity.
*
* @return GalleryStatus a status code
*/
function onLoad() {
global $gallery;
$linkId = $this->getLinkId();
if (!empty($linkId)) {
list ($ret, $this->linkedEntity) =
GalleryCoreApi::loadEntitiesById($linkId, $this->entityType);
if ($ret) {
return $ret;
}
list ($ret, $data) = GalleryCoreApi::describeEntity($this->entityType);
if ($ret) {
return $ret;
}
$target = $this->entityType;
while ($target) {
foreach ($data[$target]['linked'] as $memberName) {
$setFunc = "set$memberName";
$getFunc = "get$memberName";
$this->$setFunc($this->linkedEntity->$getFunc());
}
$target = $data[$target]['parent'];
}
} else {
$this->setLinkedEntity(null);
}
/*
* Run any onLoad handlers for this entity
* Modules that wish to implement an onLoad handler for an entity must provide
* a class that implements the GalleryOnLoadHandler interface.
*/
$onLoadHandlers = $this->getOnLoadHandlers();
if (!empty($onLoadHandlers)) {
/* Determine whether we're in an upgrade process */
$session =& $gallery->getSession();
$isDuringInstallOrUpgrade = $session->get('isInstall') || $session->get('isUpgrade');
foreach (explode('|', $onLoadHandlers) as $handlerId) {
if (empty($handlerId)) {
continue;
}
list ($ret, $handler) =
GalleryCoreApi::newFactoryInstanceById('GalleryOnLoadHandler', $handlerId);
if ($ret) {
return $ret;
}
if (isset($handler)) {
/* GalleryOnLoadHandlerInterface_1_0::onLoad(&$entity, $duringUpgrade)
*
* A GalleryOnLoadHandler has to implement this method
* It is called for each entity when it is loaded from the disk cache or the
* persistent store (the database), but not when the entity is already in the
* memory cache.
*
* During the core module install or upgrade, there's no active gallery session
* and $duringUpgrade is set to false. If $duringUpgrade is set to false, be
* aware that everything that is related to the current active user will
* error-out. The recommended usage is to do nothing and just return a success
* status in onLoad if $duringUpgrade is set to false. If this would affect
* data integrity and / or you are sure that your onLoad method does not
* require an activeSession, you can ignore $duringUpgrade.
*
* @param GalleryEntity reference to an entity
* @param boolean whether the onLoad handler is being called during an upgrade
* @return GalleryStatus a status code
*/
$ret = $handler->onLoad($this, $isDuringInstallOrUpgrade);
if ($ret) {
return $ret;
}
}
}
}
return null;
}
/**
* Check for an onLoad handler.
*
* @param string $handlerId
* @return boolean
*/
function hasOnLoadHandler($handlerId) {
return (strpos($this->getOnLoadHandlers(), "|$handlerId|") !== false);
}
/**
* Add onLoad handler.
*
* @param string $handlerId
*/
function addOnLoadHandler($handlerId) {
$onLoadHandlers = $this->getOnLoadHandlers();
if (empty($onLoadHandlers)) {
$onLoadHandlers = '|';
}
$this->setOnLoadHandlers($onLoadHandlers . $handlerId . '|');
}
/**
* Remove onLoad handler.
*
* @param string $handlerId
*/
function removeOnLoadHandler($handlerId) {
$onLoadHandlers = preg_replace('{\|' . preg_quote($handlerId) . '\|}', '|',
$this->getOnLoadHandlers());
if (empty($onLoadHandlers) || $onLoadHandlers == '|') {
$onLoadHandlers = null;
}
$this->setOnLoadHandlers($onLoadHandlers);
}
/**
* This is called after an entity is saved by the GalleryStorage subsystem.
* Perform any actions that are required after saving the entity.
*
* @return GalleryStatus a status code
*/
function onSave() {
return null;
}
/**
* Return the name of this type of item.
* Subclasses must override this to provide their own type names.
*
* @param boolean $localized if the name is to be translated using the current language
* @return array string to be used by itself ("Photo")
* string to be used in context ("photo")
*/
function itemTypeName($localized=true) {
assert(false);
}
/**
* Return true if this entity is linked to another
* @return boolean
*/
function isLinked() {
$linkedEntity = $this->getLinkedEntity();
return isset($linkedEntity);
}
/**
* Detach this entity from the entity it is linked to by the simple expedient
* of overwriting over all non-null members with the equivalent from the link target.
*
* @return GalleryStatus a status code
*/
function detachLink() {
if (!$this->isLinked()) {
return GalleryCoreApi::error(ERROR_BAD_PARAMETER, __FILE__, __LINE__, 'Not a link!');
}
/*
* Copy over the linked data. It should already be here since we do this in onLoad() but
* this will guarantee it in case the values were changed before the detach happens.
*/
list ($ret, $data) = GalleryCoreApi::describeEntity($this->entityType);
if ($ret) {
return $ret;
}
foreach ($data[$this->entityType]['linked'] as $memberName) {
$setFunc = "set$memberName";
$getFunc = "get$memberName";
$this->$setFunc($this->linkedEntity->$getFunc());
}
/* Get rid of the link */
$this->setLinkedEntity(null);
$this->setLinkId(null);
return null;
}
/**
* Return the case sensitive name of this entity class. This is exactly what get_class()
* would return in PHP5. PHP4 is case-insensitive though so we must rely on it being set
* in each entity. The framework uses this as an index into entity related tables.
* @return string
*/
function getClassName() {
return 'GalleryEntity';
}
function getId() {
return $this->id;
}
function setId($id) {
$this->id = $id;
}
function getCreationTimestamp() {
return $this->creationTimestamp;
}
function setCreationTimestamp($creationTimestamp) {
$this->creationTimestamp = $creationTimestamp;
}
function getIsLinkable() {
return $this->isLinkable;
}
function setIsLinkable($isLinkable) {
$this->isLinkable = $isLinkable;
}
function getLinkId() {
return $this->linkId;
}
function setLinkId($linkId) {
$this->linkId = $linkId;
}
function getLinkedEntity() {
return $this->linkedEntity;
}
function setLinkedEntity($linkedEntity) {
$this->linkedEntity = $linkedEntity;
}
function getModificationTimestamp() {
return $this->modificationTimestamp;
}
function setModificationTimestamp($modificationTimestamp) {
$this->modificationTimestamp = $modificationTimestamp;
}
function getSerialNumber() {
return $this->serialNumber;
}
function setSerialNumber($serialNumber) {
$this->serialNumber = $serialNumber;
}
function getEntityType() {
return $this->entityType;
}
function setEntityType($entityType) {
$this->entityType = $entityType;
}
function getOnLoadHandlers() {
return $this->onLoadHandlers;
}
function setOnLoadHandlers($onLoadHandlers) {
$this->onLoadHandlers = $onLoadHandlers;
}
/**
* @todo Consider removing this method when refactoring the renderer code.
*/
function getRenderer() {
/* See bug 1662652 */
return null;
}
}
?>