Commit 8d56157abf064bb4477a3b193132ffa4d502bcd8

Authored by Paul Barrett
1 parent d82d4ae8

Update CMIS Object Attributes

Story ID:2295472. Update KT CMIS implementation to 1.0 compliance

Committed by: Paul Barrett
lib/api/ktcmis/classes/CMISObject.inc.php
... ... @@ -44,22 +44,33 @@
44 44 * @version Version 0.1
45 45 */
46 46  
47   -abstract class CMISObject {
  47 +// NOTE designation "opaque" means the value may not be changed
  48 +
  49 +// TODO consider attributes as a class similar to property definitions, in order to more easily extract without having
  50 +// to have attribute specific code
48 51  
49   - protected $typeId;
50   - protected $queryName;
51   - protected $displayName;
52   - protected $baseType;
53   - protected $baseTypeQueryName;
54   - protected $parentId;
55   - protected $description;
56   - protected $creatable;
57   - protected $fileable;
58   - protected $queryable;
59   - protected $includedInSupertypeQuery;
60   - protected $controllable; // NOTE deprecated? part of policy objects specification, policy objects are indicated as TODO remove
61   - protected $contentStreamAllowed = 'notAllowed';
  52 +abstract class CMISObject {
62 53  
  54 + protected $id; // ID (opaque); identifies the object-type in the repository
  55 + protected $localName; // String (opaque, optional); local name for object-type - need not be set
  56 + protected $localNamespace; // String (opaque, optional); optional local namespace for object-type - need not be set
  57 + // NOTE queryName should not contain characters that negatively interact with BNF grammar
  58 + protected $queryName; // String (opaque); used for query and filter operations on object-types
  59 + protected $displayName; // String (optional); used for presentation by application
  60 + protected $baseId; // Enum; indicates base type
  61 + protected $parentId; // ID; id of immediate parent type; must be "not set" for a base type (Document, Folder, Relationship, Policy)
  62 + protected $description; // String (optional); used for presentation by application
  63 + protected $creatable; // Boolean; indicates whether new objects of this type may be created
  64 + protected $fileable; // Boolean; indicates whether objects of this type are fileable
  65 + protected $queryable; // Boolean; indicates whether this object-type can appear inthe FROM clause of a query statement
  66 + protected $controllablePolicy; // Boolean; indicates whether objects of this type are controllable via policies
  67 + protected $controllableACL; // Boolean; indicates whether objects of this type are controllable by ACLs
  68 + protected $fulltextIndexed; // Boolean; indicates whether objects of this type are indexed for full-text search
  69 + // for querying via the CONTAINS() query predicate
  70 + protected $includedInSupertypeQuery; // Boolean; indicates whether this type and sub-types appear in a query of this type's ancestor types
  71 + // For example: if Invoice is a sub-type of cmis:document, if this is TRUE on Invoice then for a query
  72 + // 391 on cmis:document, instances of Invoice will be returned if they match.
  73 +
63 74 protected $properties; // list of property objects which define the additional properties for this object
64 75  
65 76 // TODO all we have here so far is getAttributes & getProperties
... ... @@ -82,18 +93,21 @@ abstract class CMISObject {
82 93  
83 94 // TODO look at how chemistry does this and implement something similar
84 95 // for now this is fine as we are just trying to get things up and running :)
85   - $attributes['typeId'] = $this->typeId;
  96 + $attributes['id'] = $this->id;
  97 + $attributes['localName'] = $this->localName;
  98 + $attributes['localNamespace'] = $this->localNamespace;
86 99 $attributes['queryName'] = $this->queryName;
87 100 $attributes['displayName'] = $this->displayName;
88   - $attributes['baseType'] = $this->baseType;
89   - $attributes['baseTypeQueryName'] = $this->baseTypeQueryName;
  101 + $attributes['baseId'] = $this->baseId;
90 102 $attributes['parentId'] = $this->parentId;
91 103 $attributes['description'] = $this->description;
92 104 $attributes['creatable'] = $this->creatable;
93 105 $attributes['fileable'] = $this->fileable;
94 106 $attributes['queryable'] = $this->queryable;
  107 + $attributes['controllablePolicy'] = $this->controllablePolicy;
  108 + $attributes['controllableACL'] = $this->controllableACL;
  109 + $attributes['fulltextIndexed'] = $this->fulltextIndexed;
95 110 $attributes['includedInSupertypeQuery'] = $this->includedInSupertypeQuery;
96   - $attributes['controllable'] = $this->includedInSupertypeQuery;
97 111  
98 112 return $attributes;
99 113 }
... ... @@ -136,12 +150,12 @@ abstract class CMISObject {
136 150 return $this->properties->getValue($property);
137 151 }
138 152  
139   - public function reload($documentId)
  153 + public function reload($objectId)
140 154 {
141   - $this->_get($documentId);
  155 + $this->_get($objectId);
142 156 }
143 157  
144   - private function _get($documentId)
  158 + private function _get($objectId)
145 159 {
146 160 // override in child classes
147 161 }
... ...
lib/api/ktcmis/objecttypes/CMISDocumentObject.inc.php
... ... @@ -52,41 +52,34 @@ require_once(CMIS_DIR . '/util/CMISUtil.inc.php');
52 52  
53 53 class CMISDocumentObject extends CMISObject {
54 54  
55   - protected $versionable;
56   - private $ktapi;
57   - private $uri;
58   -
  55 + protected $versionable; // Bolean; indicates whether objects of this type are versionable
  56 + protected $contentStreamAllowed; // Enum; notallowed, allowed, required
  57 + protected $ktapi;
  58 +
59 59 // TODO some of this should probably come from configuration files as it is repository specific
60 60 function __construct($documentId = null, &$ktapi = null, $uri = null)
61 61 {
62 62 $this->ktapi = $ktapi;
63   - // uri to use for document links
64   - $this->uri = $uri;
65 63  
66 64 // attributes
67   - $this->typeId = 'Document'; // <repository-specific>
68   - $this->queryName = 'Document';
69   - $this->displayName = ''; // <repository-specific>
70   - $this->baseType = 'document';
71   - $this->baseTypeQueryName = 'Document';
72   - $this->parentId = null; // MUST NOT be set
73   - $this->description = ''; // <repository-specific>
74   - $this->creatable = ''; // <repository-specific>
75   - /*
76   - * fileable SHOULD be set as follows:
77   - * If the repository does NOT support the รขโ‚ฌล“un-filingรขโ‚ฌ? capability:
78   - * TRUE
79   - * If the repository does support the รขโ‚ฌล“un-filingรขโ‚ฌ? capability:
80   - * <repository-specific>, but SHOULD be TRUE
81   - */
82   - $this->fileable = true; // TODO implement check for whether un-filing is supported
  65 + $this->id = 'cmis:document';
  66 + $this->localName = null; // <repository-specific>
  67 + $this->localNamespace = null; // <repository-specific>
  68 + $this->queryName = 'cmis:document';
  69 + $this->displayName = 'Document'; // <repository-specific>
  70 + $this->baseId = 'cmis:document';
  71 + $this->parentId = null; // MUST NOT be set for base document object-type
  72 + $this->description = null; // <repository-specific>
  73 + $this->creatable = true; // <repository-specific>
  74 + $this->fileable = true;
83 75 $this->queryable = true; // SHOULD be true
84   - $this->includedInSupertypeQuery = true; //
85   - // TODO determine what these next 3 should be
86   - $this->controllable = false; // <repository-specific>
  76 + $this->controllablePolicy = false; // <repository-specific>
  77 + $this->includedInSupertypeQuery = true; // <repository-specific>
87 78 $this->versionable = true; // <repository-specific>
88   - $this->contentStreamAllowed = 'required'; // <repository-specific> notAllowed/allowed/required
89   -
  79 + $this->contentStreamAllowed = 'required'; // <repository-specific> notallowed/allowed/required
  80 + $this->controllableACL = false; // <repository-specific>
  81 + $this->fulltextIndexed = false; // <repository-specific>
  82 +
90 83 // properties
91 84 $this->properties = new CMISDocumentPropertyCollection();
92 85  
... ... @@ -98,7 +91,7 @@ class CMISDocumentObject extends CMISObject {
98 91 if (!is_null($documentId))
99 92 {
100 93 try {
101   - $this->get($documentId);
  94 + $this->_get($documentId);
102 95 }
103 96 catch (exception $e) {
104 97 throw new ObjectNotFoundException($e->getMessage());
... ... @@ -107,8 +100,9 @@ class CMISDocumentObject extends CMISObject {
107 100  
108 101 // TODO throw exception if unable to create?
109 102 }
110   -
111   - private function get($documentId)
  103 +
  104 + // TODO abstract shared stuff to base class where possible
  105 + private function _get($documentId)
112 106 {
113 107 $object = $this->ktapi->get_document_by_id((int)$documentId);
114 108  
... ... @@ -131,9 +125,9 @@ class CMISDocumentObject extends CMISObject {
131 125 // $this->_setPropertyInternal('uri', $uri);
132 126 $this->_setPropertyInternal('uri', '');
133 127 // TODO what is this? Assuming it is the object type id, and not OUR document type?
134   - $this->_setPropertyInternal('objectTypeId', 'cmis:' . strtolower($this->getAttribute('typeId')));
  128 + $this->_setPropertyInternal('objectTypeId', strtolower($this->getAttribute('id')));
135 129 // Needed to distinguish type
136   - $this->_setPropertyInternal('baseTypeId', 'cmis:' . strtolower($this->getAttribute('typeId')));
  130 + $this->_setPropertyInternal('baseTypeId', strtolower($this->getAttribute('id')));
137 131 $this->_setPropertyInternal('createdBy', $objectProperties['created_by']);
138 132 $this->_setPropertyInternal('creationDate', $objectProperties['created_date']);
139 133 $this->_setPropertyInternal('lastModifiedBy', $objectProperties['modified_by']);
... ... @@ -181,6 +175,22 @@ class CMISDocumentObject extends CMISObject {
181 175 $this->_setPropertyInternal('contentStreamUri', $this->getProperty('objectId') . '/' . $objectProperties['filename']);
182 176 $this->_setPropertyInternal('author', $objectProperties['created_by']);
183 177 }
  178 +
  179 + /**
  180 + * Returns a listing of all attributes in an array
  181 + *
  182 + * @return array $attributes
  183 + */
  184 + public function getAttributes()
  185 + {
  186 + $attributes = parent::getAttributes();
  187 +
  188 + // add document object-type specific attributes
  189 + $attributes['versionable'] = $this->versionable;
  190 + $attributes['contentStreamAllowed'] = $this->contentStreamAllowed;
  191 +
  192 + return $attributes;
  193 + }
184 194  
185 195 }
186 196  
... ...
lib/api/ktcmis/objecttypes/CMISFolderObject.inc.php
... ... @@ -50,34 +50,36 @@ require_once(CMIS_DIR . &#39;/util/CMISUtil.inc.php&#39;);
50 50  
51 51 class CMISFolderObject extends CMISObject {
52 52  
53   - private $ktapi;
54   - private $uri;
  53 + protected $ktapi;
55 54  
56 55 public function __construct($folderId = null, &$ktapi = null, $uri = null)
57 56 {
58 57 $this->ktapi = $ktapi;
59   - $this->uri = $uri;
60 58  
61   - $this->typeId = 'Folder'; // <repository-specific>
62   - $this->queryName = 'Folder';
63   - $this->displayName = ''; // <repository-specific>
64   - $this->baseType = 'folder';
65   - $this->baseTypeQueryName = 'Folder';
  59 + $this->id = 'cmis:folder'; // <repository-specific>
  60 + $this->localName = null; // <repository-specific>
  61 + $this->localNamespace = null; // <repository-specific>
  62 + $this->queryName = 'cmis:folder';
  63 + $this->displayName = 'Folder'; // <repository-specific>
  64 + $this->baseId = 'cmis:folder';
66 65 $this->parentId = null; // MUST NOT be set
67   - $this->description = ''; // <repository-specific>
68   - $this->creatable = ''; // <repository-specific>
  66 + $this->description = null; // <repository-specific>
  67 + $this->creatable = true; // <repository-specific>
69 68 $this->fileable = true;
70 69 $this->queryable = true; // SHOULD be true
71   - $this->includedInSupertypeQuery = true; //
72   - $this->controllable = ''; // <repository-specific>
73   -
  70 + $this->controllablePolicy = false; // <repository-specific>
  71 + $this->includedInSupertypeQuery = true; // <repository-specific>
  72 + $this->contentStreamAllowed = 'required'; // <repository-specific> notallowed/allowed/required
  73 + $this->controllableACL = false; // <repository-specific>
  74 + $this->fulltextIndexed = false; // <repository-specific>
  75 +
74 76 // properties
75 77 $this->properties = new CMISFolderPropertyCollection();
76 78  
77 79 if (!is_null($folderId))
78 80 {
79 81 try {
80   - $this->get($folderId);
  82 + $this->_get($folderId);
81 83 }
82 84 catch (exception $e) {
83 85 throw new ObjectNotFoundException($e->getMessage());
... ... @@ -85,7 +87,8 @@ class CMISFolderObject extends CMISObject {
85 87 }
86 88 }
87 89  
88   - private function get($folderId)
  90 + // TODO abstract shared stuff to base class where possible
  91 + private function _get($folderId)
89 92 {
90 93 $object = $this->ktapi->get_folder_by_id((int)$folderId);
91 94  
... ... @@ -109,9 +112,9 @@ class CMISFolderObject extends CMISObject {
109 112 // $this->_setPropertyInternal('uri', $uri);
110 113 $this->_setPropertyInternal('uri', '');
111 114 // TODO what is this? Assuming it is the object type id, and not OUR document type?
112   - $this->_setPropertyInternal('objectTypeId', 'cmis:' . strtolower($this->getAttribute('typeId')));
  115 + $this->_setPropertyInternal('objectTypeId', strtolower($this->getAttribute('id')));
113 116 // Needed to distinguish type
114   - $this->_setPropertyInternal('baseTypeId', 'cmis:' . strtolower($this->getAttribute('typeId')));
  117 + $this->_setPropertyInternal('baseTypeId', strtolower($this->getAttribute('id')));
115 118 $this->_setPropertyInternal('createdBy', $objectProperties['created_by']);
116 119 // TODO cannot currently retrieve via ktapi or regular folder code - add as with created by
117 120 $this->_setPropertyInternal('creationDate', $objectProperties['created_date']);
... ...
lib/api/ktcmis/services/CMISObjectService.inc.php
... ... @@ -64,7 +64,7 @@ class CMISObjectService {
64 64 throw new ConstraintViolationException('Object base type could not be determined. ' . $e->getMessage());
65 65 }
66 66  
67   - if ($typeDefinition['attributes']['baseType'] != 'document')
  67 + if ($typeDefinition['attributes']['baseId'] != 'cmis:document')
68 68 {
69 69 throw new ConstraintViolationException('Object is not of base type document');
70 70 }
... ... @@ -244,7 +244,7 @@ class CMISObjectService {
244 244 throw new StorageException('The repository was unable to create the document. ' . $response['message']);
245 245 }
246 246 else {
247   - $objectId = CMISUtil::encodeObjectId('Document', $response['results']['document_id']);
  247 + $objectId = CMISUtil::encodeObjectId(DOCUMENT, $response['results']['document_id']);
248 248 }
249 249  
250 250 // remove temporary file
... ... @@ -294,7 +294,7 @@ class CMISObjectService {
294 294 throw new ConstraintViolationException('Object is not of base type folder. ' . $e->getMessage());
295 295 }
296 296  
297   - if ($typeDefinition['attributes']['baseType'] != 'folder') {
  297 + if ($typeDefinition['attributes']['baseId'] != 'cmis:folder') {
298 298 throw new ConstraintViolationException('Object is not of base type folder');
299 299 }
300 300  
... ... @@ -322,7 +322,7 @@ class CMISObjectService {
322 322 }
323 323 else
324 324 {
325   - $objectId = CMISUtil::encodeObjectId('Folder', $response['results']['id']);
  325 + $objectId = CMISUtil::encodeObjectId(FOLDER, $response['results']['id']);
326 326 }
327 327  
328 328 return $objectId;
... ... @@ -633,7 +633,7 @@ class CMISObjectService {
633 633 // TODO consider sending back full properties on each object?
634 634 // Not sure yet what this output may be used for by a client, and the current specification (0.61c) says:
635 635 // "A list of identifiers of objects in the folder tree that were not deleted", so let's leave it returning just ids for now.
636   - $failedToDelete[] = CMISUtil::encodeObjectId('Folder', $objectId);
  636 + $failedToDelete[] = CMISUtil::encodeObjectId(FOLDER, $objectId);
637 637 $folderContents = $object->get_full_listing();
638 638 foreach($folderContents as $folderObject)
639 639 {
... ... @@ -723,7 +723,7 @@ class CMISObjectService {
723 723 }
724 724 // else
725 725 // {
726   -// $objectId = CMISUtil::encodeObjectId('Document', $response['results']['id']);
  726 +// $objectId = CMISUtil::encodeObjectId(DOCUMENT, $response['results']['id']);
727 727 // }
728 728  
729 729 @unlink($csFile);
... ...
lib/api/ktcmis/services/CMISVersioningService.inc.php
... ... @@ -117,7 +117,7 @@ class CMISVersioningService {
117 117  
118 118 // if successful, set $contentCopied = true; unless contentStream is not set
119 119 if ($pwc->getProperty('contentStreamFilename') != '') $contentCopied = true;
120   - $documentId = CMISUtil::encodeObjectId('Document', $documentId);
  120 + $documentId = CMISUtil::encodeObjectId(DOCUMENT, $documentId);
121 121  
122 122 // mark document object as checked out
123 123 $pwc->setProperty('isVersionSeriesCheckedOut', true);
... ...
lib/api/ktcmis/util/CMISUtil.inc.php
... ... @@ -307,8 +307,11 @@ class CMISUtil {
307 307 * via var_export (which returns a useable PHP string for creating the object from array content)
308 308 * and regular expressions to extract the array definitions and structure without the class specific code
309 309 *
310   - * NOTE this function is not reliable for objects which contain ktapi instances, as it appears there is a recursive reference
311   - * TODO attempt to deal with recursive references?
  310 + * NOTE this function is not reliable for objects which contain ktapi instances, as it appears there is a recursive reference;
  311 + * this will apply to any class which contains recursive references (which is bad practice and should not be done - the
  312 + * problem is with the object and not this code
  313 + *
  314 + * TODO attempt to deal with recursive references? - better to fix the objects in question, if possible
312 315 *
313 316 * @param object $data
314 317 * @return array $array
... ... @@ -318,7 +321,7 @@ class CMISUtil {
318 321 $array = array();
319 322  
320 323 $stringdata = var_export($data, true);
321   - // clean up ", )" - NOTE this may not be necessary
  324 + // clean up ", )" - NOTE this may not be necessary, but is included for safety
322 325 $stringdata = preg_replace('/, *\r?\n? *\)/', ')', $stringdata);
323 326  
324 327 // NOTE is this while loop even needed?
... ... @@ -351,14 +354,14 @@ class CMISUtil {
351 354 /**
352 355 * Checks the contentStream and ensures that it is a correct base64 string;
353 356 * This is purely for clients such as CMISSpaces breaking the content into
354   - * chunks before base64 encoding.
  357 + * chunks before base64 encoding each and this coming through as a single string containing multiple base64 chunks.
355 358 *
356 359 * If the stream is chunked, it is decoded in chunks and sent back as a single stream.
357 360 * If it is not chunked it is decoded as is and sent back as a single stream.
358 361 *
359 362 * NOTE there is an alternative version of this function called decodeChunkedContentStreamLong.
360 363 * that version checks line lengths, which should not be necessary.
361   - * this version merely splits on one or two "=" which is less complex and possibly faster (test this assumption)
  364 + * this version merely splits on one or two "=" which is less complex and appears to be faster
362 365 * (one or two "=" signs is the specified padding used for base64 encoding at the end of an encoded string, when needed)
363 366 *
364 367 * @param object $contentStream
... ... @@ -394,7 +397,7 @@ class CMISUtil {
394 397 }
395 398 }
396 399  
397   - // decode, append to output to be re-encoded
  400 + // decode, append to output
398 401 $decoded .= base64_decode($part);
399 402 }
400 403  
... ...