diff --git a/lib/api/ktcmis/classes/CMISObject.inc.php b/lib/api/ktcmis/classes/CMISObject.inc.php index 198283d..cb49313 100644 --- a/lib/api/ktcmis/classes/CMISObject.inc.php +++ b/lib/api/ktcmis/classes/CMISObject.inc.php @@ -44,22 +44,33 @@ * @version Version 0.1 */ -abstract class CMISObject { +// NOTE designation "opaque" means the value may not be changed + +// TODO consider attributes as a class similar to property definitions, in order to more easily extract without having +// to have attribute specific code - protected $typeId; - protected $queryName; - protected $displayName; - protected $baseType; - protected $baseTypeQueryName; - protected $parentId; - protected $description; - protected $creatable; - protected $fileable; - protected $queryable; - protected $includedInSupertypeQuery; - protected $controllable; // NOTE deprecated? part of policy objects specification, policy objects are indicated as TODO remove - protected $contentStreamAllowed = 'notAllowed'; +abstract class CMISObject { + protected $id; // ID (opaque); identifies the object-type in the repository + protected $localName; // String (opaque, optional); local name for object-type - need not be set + protected $localNamespace; // String (opaque, optional); optional local namespace for object-type - need not be set + // NOTE queryName should not contain characters that negatively interact with BNF grammar + protected $queryName; // String (opaque); used for query and filter operations on object-types + protected $displayName; // String (optional); used for presentation by application + protected $baseId; // Enum; indicates base type + protected $parentId; // ID; id of immediate parent type; must be "not set" for a base type (Document, Folder, Relationship, Policy) + protected $description; // String (optional); used for presentation by application + protected $creatable; // Boolean; indicates whether new objects of this type may be created + protected $fileable; // Boolean; indicates whether objects of this type are fileable + protected $queryable; // Boolean; indicates whether this object-type can appear inthe FROM clause of a query statement + protected $controllablePolicy; // Boolean; indicates whether objects of this type are controllable via policies + protected $controllableACL; // Boolean; indicates whether objects of this type are controllable by ACLs + protected $fulltextIndexed; // Boolean; indicates whether objects of this type are indexed for full-text search + // for querying via the CONTAINS() query predicate + protected $includedInSupertypeQuery; // Boolean; indicates whether this type and sub-types appear in a query of this type's ancestor types + // For example: if Invoice is a sub-type of cmis:document, if this is TRUE on Invoice then for a query + // 391 on cmis:document, instances of Invoice will be returned if they match. + protected $properties; // list of property objects which define the additional properties for this object // TODO all we have here so far is getAttributes & getProperties @@ -82,18 +93,21 @@ abstract class CMISObject { // TODO look at how chemistry does this and implement something similar // for now this is fine as we are just trying to get things up and running :) - $attributes['typeId'] = $this->typeId; + $attributes['id'] = $this->id; + $attributes['localName'] = $this->localName; + $attributes['localNamespace'] = $this->localNamespace; $attributes['queryName'] = $this->queryName; $attributes['displayName'] = $this->displayName; - $attributes['baseType'] = $this->baseType; - $attributes['baseTypeQueryName'] = $this->baseTypeQueryName; + $attributes['baseId'] = $this->baseId; $attributes['parentId'] = $this->parentId; $attributes['description'] = $this->description; $attributes['creatable'] = $this->creatable; $attributes['fileable'] = $this->fileable; $attributes['queryable'] = $this->queryable; + $attributes['controllablePolicy'] = $this->controllablePolicy; + $attributes['controllableACL'] = $this->controllableACL; + $attributes['fulltextIndexed'] = $this->fulltextIndexed; $attributes['includedInSupertypeQuery'] = $this->includedInSupertypeQuery; - $attributes['controllable'] = $this->includedInSupertypeQuery; return $attributes; } @@ -136,12 +150,12 @@ abstract class CMISObject { return $this->properties->getValue($property); } - public function reload($documentId) + public function reload($objectId) { - $this->_get($documentId); + $this->_get($objectId); } - private function _get($documentId) + private function _get($objectId) { // override in child classes } diff --git a/lib/api/ktcmis/objecttypes/CMISDocumentObject.inc.php b/lib/api/ktcmis/objecttypes/CMISDocumentObject.inc.php index df2d424..e5493c1 100644 --- a/lib/api/ktcmis/objecttypes/CMISDocumentObject.inc.php +++ b/lib/api/ktcmis/objecttypes/CMISDocumentObject.inc.php @@ -52,41 +52,34 @@ require_once(CMIS_DIR . '/util/CMISUtil.inc.php'); class CMISDocumentObject extends CMISObject { - protected $versionable; - private $ktapi; - private $uri; - + protected $versionable; // Bolean; indicates whether objects of this type are versionable + protected $contentStreamAllowed; // Enum; notallowed, allowed, required + protected $ktapi; + // TODO some of this should probably come from configuration files as it is repository specific function __construct($documentId = null, &$ktapi = null, $uri = null) { $this->ktapi = $ktapi; - // uri to use for document links - $this->uri = $uri; // attributes - $this->typeId = 'Document'; // - $this->queryName = 'Document'; - $this->displayName = ''; // - $this->baseType = 'document'; - $this->baseTypeQueryName = 'Document'; - $this->parentId = null; // MUST NOT be set - $this->description = ''; // - $this->creatable = ''; // - /* - * fileable SHOULD be set as follows: - * If the repository does NOT support the “un-filing� capability: - * TRUE - * If the repository does support the “un-filing� capability: - * , but SHOULD be TRUE - */ - $this->fileable = true; // TODO implement check for whether un-filing is supported + $this->id = 'cmis:document'; + $this->localName = null; // + $this->localNamespace = null; // + $this->queryName = 'cmis:document'; + $this->displayName = 'Document'; // + $this->baseId = 'cmis:document'; + $this->parentId = null; // MUST NOT be set for base document object-type + $this->description = null; // + $this->creatable = true; // + $this->fileable = true; $this->queryable = true; // SHOULD be true - $this->includedInSupertypeQuery = true; // - // TODO determine what these next 3 should be - $this->controllable = false; // + $this->controllablePolicy = false; // + $this->includedInSupertypeQuery = true; // $this->versionable = true; // - $this->contentStreamAllowed = 'required'; // notAllowed/allowed/required - + $this->contentStreamAllowed = 'required'; // notallowed/allowed/required + $this->controllableACL = false; // + $this->fulltextIndexed = false; // + // properties $this->properties = new CMISDocumentPropertyCollection(); @@ -98,7 +91,7 @@ class CMISDocumentObject extends CMISObject { if (!is_null($documentId)) { try { - $this->get($documentId); + $this->_get($documentId); } catch (exception $e) { throw new ObjectNotFoundException($e->getMessage()); @@ -107,8 +100,9 @@ class CMISDocumentObject extends CMISObject { // TODO throw exception if unable to create? } - - private function get($documentId) + + // TODO abstract shared stuff to base class where possible + private function _get($documentId) { $object = $this->ktapi->get_document_by_id((int)$documentId); @@ -131,9 +125,9 @@ class CMISDocumentObject extends CMISObject { // $this->_setPropertyInternal('uri', $uri); $this->_setPropertyInternal('uri', ''); // TODO what is this? Assuming it is the object type id, and not OUR document type? - $this->_setPropertyInternal('objectTypeId', 'cmis:' . strtolower($this->getAttribute('typeId'))); + $this->_setPropertyInternal('objectTypeId', strtolower($this->getAttribute('id'))); // Needed to distinguish type - $this->_setPropertyInternal('baseTypeId', 'cmis:' . strtolower($this->getAttribute('typeId'))); + $this->_setPropertyInternal('baseTypeId', strtolower($this->getAttribute('id'))); $this->_setPropertyInternal('createdBy', $objectProperties['created_by']); $this->_setPropertyInternal('creationDate', $objectProperties['created_date']); $this->_setPropertyInternal('lastModifiedBy', $objectProperties['modified_by']); @@ -181,6 +175,22 @@ class CMISDocumentObject extends CMISObject { $this->_setPropertyInternal('contentStreamUri', $this->getProperty('objectId') . '/' . $objectProperties['filename']); $this->_setPropertyInternal('author', $objectProperties['created_by']); } + + /** + * Returns a listing of all attributes in an array + * + * @return array $attributes + */ + public function getAttributes() + { + $attributes = parent::getAttributes(); + + // add document object-type specific attributes + $attributes['versionable'] = $this->versionable; + $attributes['contentStreamAllowed'] = $this->contentStreamAllowed; + + return $attributes; + } } diff --git a/lib/api/ktcmis/objecttypes/CMISFolderObject.inc.php b/lib/api/ktcmis/objecttypes/CMISFolderObject.inc.php index 283ab56..9126de6 100644 --- a/lib/api/ktcmis/objecttypes/CMISFolderObject.inc.php +++ b/lib/api/ktcmis/objecttypes/CMISFolderObject.inc.php @@ -50,34 +50,36 @@ require_once(CMIS_DIR . '/util/CMISUtil.inc.php'); class CMISFolderObject extends CMISObject { - private $ktapi; - private $uri; + protected $ktapi; public function __construct($folderId = null, &$ktapi = null, $uri = null) { $this->ktapi = $ktapi; - $this->uri = $uri; - $this->typeId = 'Folder'; // - $this->queryName = 'Folder'; - $this->displayName = ''; // - $this->baseType = 'folder'; - $this->baseTypeQueryName = 'Folder'; + $this->id = 'cmis:folder'; // + $this->localName = null; // + $this->localNamespace = null; // + $this->queryName = 'cmis:folder'; + $this->displayName = 'Folder'; // + $this->baseId = 'cmis:folder'; $this->parentId = null; // MUST NOT be set - $this->description = ''; // - $this->creatable = ''; // + $this->description = null; // + $this->creatable = true; // $this->fileable = true; $this->queryable = true; // SHOULD be true - $this->includedInSupertypeQuery = true; // - $this->controllable = ''; // - + $this->controllablePolicy = false; // + $this->includedInSupertypeQuery = true; // + $this->contentStreamAllowed = 'required'; // notallowed/allowed/required + $this->controllableACL = false; // + $this->fulltextIndexed = false; // + // properties $this->properties = new CMISFolderPropertyCollection(); if (!is_null($folderId)) { try { - $this->get($folderId); + $this->_get($folderId); } catch (exception $e) { throw new ObjectNotFoundException($e->getMessage()); @@ -85,7 +87,8 @@ class CMISFolderObject extends CMISObject { } } - private function get($folderId) + // TODO abstract shared stuff to base class where possible + private function _get($folderId) { $object = $this->ktapi->get_folder_by_id((int)$folderId); @@ -109,9 +112,9 @@ class CMISFolderObject extends CMISObject { // $this->_setPropertyInternal('uri', $uri); $this->_setPropertyInternal('uri', ''); // TODO what is this? Assuming it is the object type id, and not OUR document type? - $this->_setPropertyInternal('objectTypeId', 'cmis:' . strtolower($this->getAttribute('typeId'))); + $this->_setPropertyInternal('objectTypeId', strtolower($this->getAttribute('id'))); // Needed to distinguish type - $this->_setPropertyInternal('baseTypeId', 'cmis:' . strtolower($this->getAttribute('typeId'))); + $this->_setPropertyInternal('baseTypeId', strtolower($this->getAttribute('id'))); $this->_setPropertyInternal('createdBy', $objectProperties['created_by']); // TODO cannot currently retrieve via ktapi or regular folder code - add as with created by $this->_setPropertyInternal('creationDate', $objectProperties['created_date']); diff --git a/lib/api/ktcmis/services/CMISObjectService.inc.php b/lib/api/ktcmis/services/CMISObjectService.inc.php index e04c53b..96c19de 100644 --- a/lib/api/ktcmis/services/CMISObjectService.inc.php +++ b/lib/api/ktcmis/services/CMISObjectService.inc.php @@ -64,7 +64,7 @@ class CMISObjectService { throw new ConstraintViolationException('Object base type could not be determined. ' . $e->getMessage()); } - if ($typeDefinition['attributes']['baseType'] != 'document') + if ($typeDefinition['attributes']['baseId'] != 'cmis:document') { throw new ConstraintViolationException('Object is not of base type document'); } @@ -244,7 +244,7 @@ class CMISObjectService { throw new StorageException('The repository was unable to create the document. ' . $response['message']); } else { - $objectId = CMISUtil::encodeObjectId('Document', $response['results']['document_id']); + $objectId = CMISUtil::encodeObjectId(DOCUMENT, $response['results']['document_id']); } // remove temporary file @@ -294,7 +294,7 @@ class CMISObjectService { throw new ConstraintViolationException('Object is not of base type folder. ' . $e->getMessage()); } - if ($typeDefinition['attributes']['baseType'] != 'folder') { + if ($typeDefinition['attributes']['baseId'] != 'cmis:folder') { throw new ConstraintViolationException('Object is not of base type folder'); } @@ -322,7 +322,7 @@ class CMISObjectService { } else { - $objectId = CMISUtil::encodeObjectId('Folder', $response['results']['id']); + $objectId = CMISUtil::encodeObjectId(FOLDER, $response['results']['id']); } return $objectId; @@ -633,7 +633,7 @@ class CMISObjectService { // TODO consider sending back full properties on each object? // Not sure yet what this output may be used for by a client, and the current specification (0.61c) says: // "A list of identifiers of objects in the folder tree that were not deleted", so let's leave it returning just ids for now. - $failedToDelete[] = CMISUtil::encodeObjectId('Folder', $objectId); + $failedToDelete[] = CMISUtil::encodeObjectId(FOLDER, $objectId); $folderContents = $object->get_full_listing(); foreach($folderContents as $folderObject) { @@ -723,7 +723,7 @@ class CMISObjectService { } // else // { -// $objectId = CMISUtil::encodeObjectId('Document', $response['results']['id']); +// $objectId = CMISUtil::encodeObjectId(DOCUMENT, $response['results']['id']); // } @unlink($csFile); diff --git a/lib/api/ktcmis/services/CMISVersioningService.inc.php b/lib/api/ktcmis/services/CMISVersioningService.inc.php index f92487b..e23beb0 100644 --- a/lib/api/ktcmis/services/CMISVersioningService.inc.php +++ b/lib/api/ktcmis/services/CMISVersioningService.inc.php @@ -117,7 +117,7 @@ class CMISVersioningService { // if successful, set $contentCopied = true; unless contentStream is not set if ($pwc->getProperty('contentStreamFilename') != '') $contentCopied = true; - $documentId = CMISUtil::encodeObjectId('Document', $documentId); + $documentId = CMISUtil::encodeObjectId(DOCUMENT, $documentId); // mark document object as checked out $pwc->setProperty('isVersionSeriesCheckedOut', true); diff --git a/lib/api/ktcmis/util/CMISUtil.inc.php b/lib/api/ktcmis/util/CMISUtil.inc.php index dd0ba39..f22a5d3 100644 --- a/lib/api/ktcmis/util/CMISUtil.inc.php +++ b/lib/api/ktcmis/util/CMISUtil.inc.php @@ -307,8 +307,11 @@ class CMISUtil { * via var_export (which returns a useable PHP string for creating the object from array content) * and regular expressions to extract the array definitions and structure without the class specific code * - * NOTE this function is not reliable for objects which contain ktapi instances, as it appears there is a recursive reference - * TODO attempt to deal with recursive references? + * NOTE this function is not reliable for objects which contain ktapi instances, as it appears there is a recursive reference; + * this will apply to any class which contains recursive references (which is bad practice and should not be done - the + * problem is with the object and not this code + * + * TODO attempt to deal with recursive references? - better to fix the objects in question, if possible * * @param object $data * @return array $array @@ -318,7 +321,7 @@ class CMISUtil { $array = array(); $stringdata = var_export($data, true); - // clean up ", )" - NOTE this may not be necessary + // clean up ", )" - NOTE this may not be necessary, but is included for safety $stringdata = preg_replace('/, *\r?\n? *\)/', ')', $stringdata); // NOTE is this while loop even needed? @@ -351,14 +354,14 @@ class CMISUtil { /** * Checks the contentStream and ensures that it is a correct base64 string; * This is purely for clients such as CMISSpaces breaking the content into - * chunks before base64 encoding. + * chunks before base64 encoding each and this coming through as a single string containing multiple base64 chunks. * * If the stream is chunked, it is decoded in chunks and sent back as a single stream. * If it is not chunked it is decoded as is and sent back as a single stream. * * NOTE there is an alternative version of this function called decodeChunkedContentStreamLong. * that version checks line lengths, which should not be necessary. - * this version merely splits on one or two "=" which is less complex and possibly faster (test this assumption) + * this version merely splits on one or two "=" which is less complex and appears to be faster * (one or two "=" signs is the specified padding used for base64 encoding at the end of an encoded string, when needed) * * @param object $contentStream @@ -394,7 +397,7 @@ class CMISUtil { } } - // decode, append to output to be re-encoded + // decode, append to output $decoded .= base64_decode($part); }