Commit 30d7fae36b0a8905c3ffa0193a3740e3fa79144a
1 parent
e6428228
Updated CMIS API with Document Creation functionality
Removed conflicting exceptions Updated CMIS API Unit Tests Committed by: Paul Barrett Reviewed by: Jarrett Jordaan
Showing
12 changed files
with
212 additions
and
97 deletions
ktwebservice/KTUploadManager.inc.php
lib/api/ktcmis/classes/CMISBaseObject.inc.php
| ... | ... | @@ -62,7 +62,7 @@ abstract class CMISBaseObject { |
| 62 | 62 | // TODO all we have here so far is getAttributes & getProperties |
| 63 | 63 | // add all the other methods as we go along |
| 64 | 64 | |
| 65 | - function __construct() | |
| 65 | + public function __construct() | |
| 66 | 66 | { |
| 67 | 67 | // $propertyDef = new PropertyDefinition(); |
| 68 | 68 | // $this->properties[] = $propertyDef; |
| ... | ... | @@ -73,7 +73,7 @@ abstract class CMISBaseObject { |
| 73 | 73 | * |
| 74 | 74 | * @return array $attributes |
| 75 | 75 | */ |
| 76 | - function getAttributes() | |
| 76 | + public function getAttributes() | |
| 77 | 77 | { |
| 78 | 78 | $attributes = array(); |
| 79 | 79 | |
| ... | ... | @@ -95,7 +95,7 @@ abstract class CMISBaseObject { |
| 95 | 95 | return $attributes; |
| 96 | 96 | } |
| 97 | 97 | |
| 98 | - function getAttribute($field) | |
| 98 | + public function getAttribute($field) | |
| 99 | 99 | { |
| 100 | 100 | return $this->{$field}; |
| 101 | 101 | } |
| ... | ... | @@ -104,7 +104,7 @@ abstract class CMISBaseObject { |
| 104 | 104 | * Sets properties for this type |
| 105 | 105 | * Obeys the rules as specified in the property definitions (once implemented) |
| 106 | 106 | */ |
| 107 | - function setProperty($field, $value) | |
| 107 | + public function setProperty($field, $value) | |
| 108 | 108 | { |
| 109 | 109 | $this->properties->setValue($field, $value); |
| 110 | 110 | } |
| ... | ... | @@ -123,11 +123,26 @@ abstract class CMISBaseObject { |
| 123 | 123 | /** |
| 124 | 124 | * Fetches properties for this object type |
| 125 | 125 | */ |
| 126 | - function getProperties() | |
| 126 | + public function getProperties() | |
| 127 | 127 | { |
| 128 | 128 | return $this->properties; |
| 129 | 129 | } |
| 130 | 130 | |
| 131 | + public function getProperty($property) | |
| 132 | + { | |
| 133 | + return $this->properties->getValue($property); | |
| 134 | + } | |
| 135 | + | |
| 136 | + public function reload($documentId) | |
| 137 | + { | |
| 138 | + $this->_get($documentId); | |
| 139 | + } | |
| 140 | + | |
| 141 | + private function _get($documentId) | |
| 142 | + { | |
| 143 | + // override in child classes | |
| 144 | + } | |
| 145 | + | |
| 131 | 146 | } |
| 132 | 147 | |
| 133 | 148 | ?> | ... | ... |
lib/api/ktcmis/exceptions/InvalidArgumentException.inc.php deleted
lib/api/ktcmis/exceptions/RuntimeException.inc.php deleted
lib/api/ktcmis/ktcmis.inc.php
| ... | ... | @@ -480,7 +480,7 @@ class KTObjectService extends KTCMISBase { |
| 480 | 480 | * @return string $objectId The id of the created folder object |
| 481 | 481 | */ |
| 482 | 482 | function createDocument($repositoryId, $typeId, $properties, $folderId = null, |
| 483 | - $contentStream = null, $versioningState = 'Major') | |
| 483 | + $contentStream = null, $versioningState = null) | |
| 484 | 484 | { |
| 485 | 485 | $objectId = null; |
| 486 | 486 | ... | ... |
lib/api/ktcmis/objecttypes/CMISDocumentObject.inc.php
| ... | ... | @@ -48,8 +48,8 @@ require_once(CMIS_DIR . '/util/CMISUtil.inc.php'); |
| 48 | 48 | |
| 49 | 49 | class CMISDocumentObject extends CMISBaseObject { |
| 50 | 50 | |
| 51 | - private $versionable; | |
| 52 | - private $contentStreamAllowed; | |
| 51 | + protected $versionable; | |
| 52 | + protected $contentStreamAllowed; | |
| 53 | 53 | private $ktapi; |
| 54 | 54 | private $uri; |
| 55 | 55 | |
| ... | ... | @@ -100,7 +100,7 @@ class CMISDocumentObject extends CMISBaseObject { |
| 100 | 100 | |
| 101 | 101 | private function _get($documentId) |
| 102 | 102 | { |
| 103 | - $object = $this->ktapi->get_document_by_id($documentId); | |
| 103 | + $object = $this->ktapi->get_document_by_id((int)$documentId); | |
| 104 | 104 | |
| 105 | 105 | // error? |
| 106 | 106 | if (PEAR::isError($object)) | ... | ... |
lib/api/ktcmis/objecttypes/CMISFolderObject.inc.php
| ... | ... | @@ -46,10 +46,10 @@ require_once(CMIS_DIR . '/util/CMISUtil.inc.php'); |
| 46 | 46 | |
| 47 | 47 | class CMISFolderObject extends CMISBaseObject { |
| 48 | 48 | |
| 49 | - var $ktapi; | |
| 50 | - var $uri; | |
| 49 | + private $ktapi; | |
| 50 | + private $uri; | |
| 51 | 51 | |
| 52 | - function __construct($folderId = null, &$ktapi = null, $uri = null) | |
| 52 | + public function __construct($folderId = null, &$ktapi = null, $uri = null) | |
| 53 | 53 | { |
| 54 | 54 | $this->ktapi = $ktapi; |
| 55 | 55 | $this->uri = $uri; |
| ... | ... | @@ -78,7 +78,7 @@ class CMISFolderObject extends CMISBaseObject { |
| 78 | 78 | |
| 79 | 79 | private function _get($folderId) |
| 80 | 80 | { |
| 81 | - $object = $this->ktapi->get_folder_by_id($folderId); | |
| 81 | + $object = $this->ktapi->get_folder_by_id((int)$folderId); | |
| 82 | 82 | |
| 83 | 83 | // error? |
| 84 | 84 | if (PEAR::isError($object)) | ... | ... |
lib/api/ktcmis/services/CMISNavigationService.inc.php
| ... | ... | @@ -83,7 +83,7 @@ class CMISNavigationService { |
| 83 | 83 | $repository = new CMISRepository($repositoryId); |
| 84 | 84 | |
| 85 | 85 | // if this is not a folder, cannot get descendants |
| 86 | - $type = CMISUtil::decodeObjectId($folderId); | |
| 86 | + $folderId = CMISUtil::decodeObjectId($folderId, $type); | |
| 87 | 87 | |
| 88 | 88 | if ($type != 'Folder') |
| 89 | 89 | { |
| ... | ... | @@ -125,7 +125,7 @@ class CMISNavigationService { |
| 125 | 125 | $repository = new CMISRepository($repositoryId); |
| 126 | 126 | |
| 127 | 127 | // if this is not a folder, cannot get children |
| 128 | - $type = CMISUtil::decodeObjectId($folderId); | |
| 128 | + $folderId = CMISUtil::decodeObjectId($folderId, $type); | |
| 129 | 129 | // NOTE this will quite possibly break the webservices |
| 130 | 130 | if ($type != 'Folder') |
| 131 | 131 | { |
| ... | ... | @@ -162,7 +162,7 @@ class CMISNavigationService { |
| 162 | 162 | $repository = new CMISRepository($repositoryId); |
| 163 | 163 | |
| 164 | 164 | // if this is not a folder, cannot get folder parent :) |
| 165 | - $type = CMISUtil::decodeObjectId($folderId); | |
| 165 | + $folderId = CMISUtil::decodeObjectId($folderId, $type); | |
| 166 | 166 | // NOTE this will quite possibly break the webservices |
| 167 | 167 | if ($type != 'Folder') |
| 168 | 168 | { |
| ... | ... | @@ -221,7 +221,7 @@ class CMISNavigationService { |
| 221 | 221 | { |
| 222 | 222 | $ancestry = array(); |
| 223 | 223 | |
| 224 | - $typeId = CMISUtil::decodeObjectId($objectId); | |
| 224 | + $objectId = CMISUtil::decodeObjectId($objectId, $typeId); | |
| 225 | 225 | |
| 226 | 226 | // TODO - what about other types? only implementing folders and documents at the moment so ignore for now |
| 227 | 227 | switch($typeId) | ... | ... |
lib/api/ktcmis/services/CMISObjectService.inc.php
| 1 | 1 | <?php |
| 2 | 2 | |
| 3 | 3 | require_once(KT_DIR . '/ktapi/ktapi.inc.php'); |
| 4 | +require_once(KT_DIR . '/ktwebservice/KTUploadManager.inc.php'); | |
| 4 | 5 | require_once(CMIS_DIR . '/exceptions/ConstraintViolationException.inc.php'); |
| 5 | 6 | require_once(CMIS_DIR . '/exceptions/ContentAlreadyExistsException.inc.php'); |
| 6 | 7 | require_once(CMIS_DIR . '/exceptions/ObjectNotFoundException.inc.php'); |
| ... | ... | @@ -8,6 +9,7 @@ require_once(CMIS_DIR . '/exceptions/StorageException.inc.php'); |
| 8 | 9 | require_once(CMIS_DIR . '/exceptions/StreamNotSupportedException.inc.php'); |
| 9 | 10 | require_once(CMIS_DIR . '/exceptions/UpdateConflictException.inc.php'); |
| 10 | 11 | require_once(CMIS_DIR . '/exceptions/VersioningException.inc.php'); |
| 12 | +require_once(CMIS_DIR . '/services/CMISNavigationService.inc.php'); | |
| 11 | 13 | require_once(CMIS_DIR . '/services/CMISRepositoryService.inc.php'); |
| 12 | 14 | require_once(CMIS_DIR . '/objecttypes/CMISDocumentObject.inc.php'); |
| 13 | 15 | require_once(CMIS_DIR . '/objecttypes/CMISFolderObject.inc.php'); |
| ... | ... | @@ -49,7 +51,7 @@ class CMISObjectService { |
| 49 | 51 | // TODO a better default value? |
| 50 | 52 | $properties = array(); |
| 51 | 53 | |
| 52 | - $typeId = CMISUtil::decodeObjectId($objectId); | |
| 54 | + $objectId = CMISUtil::decodeObjectId($objectId, $typeId); | |
| 53 | 55 | |
| 54 | 56 | if ($typeId == 'Unknown') |
| 55 | 57 | { |
| ... | ... | @@ -86,14 +88,8 @@ class CMISObjectService { |
| 86 | 88 | // TODO throw ConstraintViolationException if: |
| 87 | 89 | // value of any of the properties violates the min/max/required/length constraints |
| 88 | 90 | // specified in the property definition in the Object-Type. |
| 89 | - // TODO throw ConstraintViolationException if: | |
| 90 | - // The Object-Type definition specified by the typeId parameter's "contentStreamAllowed" attribute | |
| 91 | - // is set to "required" and no contentStream input parameter is provided | |
| 92 | - // TODO throw ConstraintViolationException if: | |
| 93 | - // The Object-Type definition specified by the typeId parameter's "versionable" attribute | |
| 94 | - // is set to "false" and a value for the versioningState input parameter is provided | |
| 95 | 91 | function createDocument($repositoryId, $typeId, $properties, $folderId = null, |
| 96 | - $contentStream = null, $versioningState = 'Major') | |
| 92 | + $contentStream = null, $versioningState = null) | |
| 97 | 93 | { |
| 98 | 94 | $objectId = null; |
| 99 | 95 | |
| ... | ... | @@ -129,38 +125,22 @@ class CMISObjectService { |
| 129 | 125 | |
| 130 | 126 | // Attempt to decode $folderId, use as is if not detected as encoded |
| 131 | 127 | $tmpObjectId = $folderId; |
| 132 | - $tmpTypeId = CMISUtil::decodeObjectId($tmpObjectId); | |
| 128 | + $tmpObjectId = CMISUtil::decodeObjectId($tmpObjectId, $tmpTypeId); | |
| 133 | 129 | if ($tmpTypeId != 'Unknown') |
| 134 | 130 | $folderId = $tmpObjectId; |
| 135 | 131 | |
| 136 | 132 | // if parent folder is not allowed to hold this type, throw exception |
| 137 | 133 | $CMISFolder = new CMISFolderObject($folderId, $this->ktapi); |
| 138 | - $folderProperties = $CMISFolder->getProperties(); | |
| 139 | - $allowed = $folderProperties->getValue('AllowedChildObjectTypeIds'); | |
| 134 | + $allowed = $CMISFolder->getProperty('AllowedChildObjectTypeIds'); | |
| 140 | 135 | if (!is_array($allowed) || !in_array($typeId, $allowed)) |
| 141 | 136 | { |
| 142 | 137 | throw new ConstraintViolationException('Parent folder may not hold objects of this type (' . $typeId . ')'); |
| 143 | 138 | } |
| 144 | 139 | |
| 145 | - // set title and name identical if only one submitted | |
| 146 | - if ($properties['title'] == '') | |
| 147 | - { | |
| 148 | - $properties['title'] = $properties['name']; | |
| 149 | - } | |
| 150 | - else if ($properties['name'] == '') | |
| 151 | - { | |
| 152 | - $properties['name'] = $properties['title']; | |
| 153 | - } | |
| 154 | - | |
| 155 | - if ($properties['type'] == '') | |
| 156 | - { | |
| 157 | - $properties['type'] = $properties['Default']; | |
| 158 | - } | |
| 159 | - | |
| 160 | 140 | // if content stream is required and no content stream is supplied, throw a ConstraintViolationException |
| 161 | 141 | if (($typeDefinition['attributes']['contentStreamAllowed'] == 'required') && empty($contentStream)) |
| 162 | 142 | { |
| 163 | - throw new ConstraintViolationException('The Knowledgetree Repository requires a content stream for document creation. ' | |
| 143 | + throw new ConstraintViolationException('This repository requires a content stream for document creation. ' | |
| 164 | 144 | . 'Refusing to create an empty document'); |
| 165 | 145 | } |
| 166 | 146 | else if (($typeDefinition['attributes']['contentStreamAllowed'] == 'notAllowed') && !empty($contentStream)) |
| ... | ... | @@ -168,25 +148,66 @@ class CMISObjectService { |
| 168 | 148 | throw new StreamNotSupportedException('Content Streams are not supported'); |
| 169 | 149 | } |
| 170 | 150 | |
| 151 | + // if versionable attribute is set to false and versioningState is supplied, throw a ConstraintViolationException | |
| 152 | + if (!$typeDefinition['attributes']['versionable'] && !empty($versioningState)) | |
| 153 | + { | |
| 154 | + throw new ConstraintViolationException('This repository does not support versioning'); | |
| 155 | + } | |
| 156 | + | |
| 171 | 157 | // TODO deal with $versioningState when supplied |
| 172 | 158 | |
| 173 | - // TODO Use add_document_with_metadata instead if metadata content submitted | |
| 174 | - $response = $this->ktapi->add_document($folderId, $properties['title'], $properties['name'], $properties['type'], $uploadedFile); | |
| 175 | - if ($response['status_code'] != 0) | |
| 159 | + // set title and name identical if only one submitted | |
| 160 | + if ($properties['title'] == '') | |
| 176 | 161 | { |
| 177 | - throw new StorageException('The repository was unable to create the document - ' . $response['message']); | |
| 162 | + $properties['title'] = $properties['name']; | |
| 178 | 163 | } |
| 179 | - else | |
| 164 | + else if ($properties['name'] == '') | |
| 180 | 165 | { |
| 181 | - $objectId = CMISUtil::encodeObjectId('Document', $response['results']['id']); | |
| 166 | + $properties['name'] = $properties['title']; | |
| 182 | 167 | } |
| 183 | 168 | |
| 184 | - // now that the document object exists, create the content stream from the supplied data | |
| 169 | + // TODO also set to Default if a non-supported type is submitted | |
| 170 | + if ($properties['type'] == '') | |
| 171 | + { | |
| 172 | + $properties['type'] = 'Default'; | |
| 173 | + } | |
| 174 | + | |
| 175 | + // create the content stream from the supplied data | |
| 176 | + // NOTE since the repository is set to require a content stream and we don't currently have another way to get the document data | |
| 177 | + // this check isn't strictly necessary; however it is needed for a repository which does not support content streams | |
| 185 | 178 | if (!empty($contentStream)) |
| 186 | 179 | { |
| 187 | - // TODO changeToken support | |
| 188 | - $changeToken = null; | |
| 189 | - $this->setContentStream($repositoryId, $objectId, false, $contentStream, $changeToken); | |
| 180 | + // NOTE There is a function in CMISUtil to do this but since KTUploadManager exists and has more functionality | |
| 181 | + // which could come in useful at some point I decided to go with that instead (did not know it existed when | |
| 182 | + // I wrote the CMISUtil function) | |
| 183 | + $uploadManager = new KTUploadManager(); | |
| 184 | + $file = $uploadManager->store_base64_file($contentStream, 'cmis_'); | |
| 185 | + // create the document from this temporary file as per usual | |
| 186 | + // TODO Use add_document_with_metadata instead if metadata content submitted || update metadata separately? | |
| 187 | + $response = $this->ktapi->add_document((int)$folderId, $properties['title'], $properties['name'], | |
| 188 | + $properties['type'], $file); | |
| 189 | + if ($response['status_code'] != 0) | |
| 190 | + { | |
| 191 | + throw new StorageException('The repository was unable to create the document. ' . $response['message']); | |
| 192 | + } | |
| 193 | + else | |
| 194 | + { | |
| 195 | + $objectId = CMISUtil::encodeObjectId('Document', $response['results']['content_id']); | |
| 196 | + } | |
| 197 | + | |
| 198 | + // remove temporary file | |
| 199 | + @unlink($file); | |
| 200 | + } | |
| 201 | + // else create the document object in the database but don't actually create any content since none was supplied | |
| 202 | + // NOTE perhaps this content could be supplied in the $properties array? | |
| 203 | + else | |
| 204 | + { | |
| 205 | + // TODO creation of document without content. leaving this for now as we require content streams and any code | |
| 206 | + // here will therefore never be executed; if we implement some form of template based document creation | |
| 207 | + // then we may have something else to do here; | |
| 208 | + // for now we just throw a general RuntimeException, since we should not | |
| 209 | + // actually reach this code unless something is wrong; this may be removed or replaced later | |
| 210 | + throw new RuntimeException('Cannot create empty document'); | |
| 190 | 211 | } |
| 191 | 212 | |
| 192 | 213 | return $objectId; |
| ... | ... | @@ -229,20 +250,19 @@ class CMISObjectService { |
| 229 | 250 | |
| 230 | 251 | // Attempt to decode $folderId, use as is if not detected as encoded |
| 231 | 252 | $tmpObjectId = $folderId; |
| 232 | - $tmpTypeId = CMISUtil::decodeObjectId($tmpObjectId); | |
| 253 | + $tmpObjectId = CMISUtil::decodeObjectId($tmpObjectId, $tmpTypeId); | |
| 233 | 254 | if ($tmpTypeId != 'Unknown') |
| 234 | 255 | $folderId = $tmpObjectId; |
| 235 | 256 | |
| 236 | 257 | // if parent folder is not allowed to hold this type, throw exception |
| 237 | 258 | $CMISFolder = new CMISFolderObject($folderId, $this->ktapi); |
| 238 | - $folderProperties = $CMISFolder->getProperties(); | |
| 239 | - $allowed = $folderProperties->getValue('AllowedChildObjectTypeIds'); | |
| 259 | + $allowed = $CMISFolder->getProperty('AllowedChildObjectTypeIds'); | |
| 240 | 260 | if (!is_array($allowed) || !in_array($typeId, $allowed)) |
| 241 | 261 | { |
| 242 | 262 | throw new ConstraintViolationException('Parent folder may not hold objects of this type (' . $typeId . ')'); |
| 243 | 263 | } |
| 244 | 264 | |
| 245 | - $response = $this->ktapi->create_folder($folderId, $properties['name'], $sig_username = '', $sig_password = '', $reason = ''); | |
| 265 | + $response = $this->ktapi->create_folder((int)$folderId, $properties['name'], $sig_username = '', $sig_password = '', $reason = ''); | |
| 246 | 266 | if ($response['status_code'] != 0) |
| 247 | 267 | { |
| 248 | 268 | throw new StorageException('The repository was unable to create the folder - ' . $response['message']); |
| ... | ... | @@ -255,6 +275,14 @@ class CMISObjectService { |
| 255 | 275 | return $objectId; |
| 256 | 276 | } |
| 257 | 277 | |
| 278 | + // NOTE this function is presently incomplete and untested. Completion deferred to implementation of Checkout/Checkin | |
| 279 | + // functionality | |
| 280 | + // NOTE I am not sure yet when this function would ever be called - checkin would be able to update the content stream | |
| 281 | + // already and the only easy method we have (via KTAPI as it stands) to update the content is on checkin anyway. | |
| 282 | + // Additionally this function doesn't take a value for the versioning status (major/minor) and so cannot pass it | |
| 283 | + // on to the ktapi checkin function. | |
| 284 | + // I imagine this function may be called if we ever allow updating document content independent of checkin, | |
| 285 | + // or if we change some of the underlying code and call direct to the document functions and not via KTAPI. | |
| 258 | 286 | /** |
| 259 | 287 | * Sets the content stream data for an existing document |
| 260 | 288 | * |
| ... | ... | @@ -277,6 +305,17 @@ class CMISObjectService { |
| 277 | 305 | // versioningException: The repository MAY throw this exception if the object is a non-current Document Version. |
| 278 | 306 | function setContentStream($repositoryId, $documentId, $overwriteFlag, $contentStream, $changeToken = null) |
| 279 | 307 | { |
| 308 | + // if no document id was supplied, we are going to create the underlying physical document | |
| 309 | + // NOTE while it might have been nice to keep this out of here, KTAPI has no method for creating a document without | |
| 310 | + // a physical upload, so we cannot create the document first and then add the upload as a content stream, the | |
| 311 | + // entire creation step needs to happen here. | |
| 312 | + | |
| 313 | + // Attempt to decode $documentId, use as is if not detected as encoded | |
| 314 | + $tmpObjectId = $documentId; | |
| 315 | + $tmpObjectId = CMISUtil::decodeObjectId($tmpObjectId, $tmpTypeId); | |
| 316 | + if ($tmpTypeId != 'Unknown') | |
| 317 | + $documentId = $tmpObjectId; | |
| 318 | + | |
| 280 | 319 | // fetch type definition of supplied document |
| 281 | 320 | $CMISDocument = new CMISDocumentObject($documentId, $this->ktapi); |
| 282 | 321 | |
| ... | ... | @@ -289,26 +328,34 @@ class CMISObjectService { |
| 289 | 328 | throw new StreamNotSupportedException('Content Streams are not allowed for this object type'); |
| 290 | 329 | } |
| 291 | 330 | |
| 292 | - $properties = $CMISDocument->getProperties(); | |
| 293 | - if (!empty($properties->getValue('ContentStreamFilename')) && (!$overwriteFlag)) | |
| 331 | + $csFileName = $CMISDocument->getProperty('ContentStreamFilename'); | |
| 332 | + if (!empty($csFileName) && (!$overwriteFlag)) | |
| 294 | 333 | { |
| 295 | 334 | throw new ContentAlreadyExistsException('Unable to overwrite existing content stream'); |
| 296 | 335 | } |
| 297 | 336 | |
| 298 | - // in order to set the stream we need to do the following: | |
| 299 | - // 1. decode the stream from the supplied base64 encoding | |
| 300 | - // 2. create a temporary file as if it were uploaded via a file upload dialog | |
| 301 | - // 3. create the document content as per usual | |
| 302 | - // 4. link to the created document object? this perhaps only happens on read anyway | |
| 303 | - | |
| 304 | - // if there is any problem updating the content stream, throw StorageException | |
| 305 | - // TODO real test parameter instead of hard-coded FALSE | |
| 306 | - if (false) | |
| 337 | + // NOTE There is a function in CMISUtil to do this but since KTUploadManager exists and has more functionality | |
| 338 | + // which could come in useful at some point I decided to go with that instead (did not know it existed when | |
| 339 | + // I wrote the CMISUtil function) | |
| 340 | + $uploadManager = new KTUploadManager(); | |
| 341 | + $file = $uploadManager->store_base64_file($contentStream, 'cmis_'); | |
| 342 | + // update the document content from this temporary file as per usual | |
| 343 | + // TODO Use checkin_document_with_metadata instead if metadata content submitted || update metadata separately? | |
| 344 | + $response = $this->ktapi->checkin_document($documentId, $csFileName, 'CMIS setContentStream action', $file, false); | |
| 345 | + if ($response['status_code'] != 0) | |
| 307 | 346 | { |
| 308 | - throw new StorageException('Unable to update the content stream'); | |
| 347 | + throw new StorageException('Unable to update the content stream. ' . $response['message']); | |
| 309 | 348 | } |
| 349 | +// else | |
| 350 | +// { | |
| 351 | +// $objectId = CMISUtil::encodeObjectId('Document', $response['results']['id']); | |
| 352 | +// } | |
| 353 | + | |
| 354 | + @unlink($csFile); | |
| 355 | + // update the CMIS document object with the content stream information | |
| 356 | +// $CMISDocument->reload($document['result']['document_id']); | |
| 310 | 357 | |
| 311 | - return $documentId; | |
| 358 | + return $CMISDocument->getProperty('ObjectId'); | |
| 312 | 359 | } |
| 313 | 360 | |
| 314 | 361 | } | ... | ... |
lib/api/ktcmis/services/CMISRepositoryService.inc.php
lib/api/ktcmis/util/CMISUtil.inc.php
| ... | ... | @@ -53,7 +53,7 @@ class CMISUtil { |
| 53 | 53 | * @param string $objectId |
| 54 | 54 | * @return string $encoded |
| 55 | 55 | */ |
| 56 | - static function encodeObjectId($typeId, $objectId) | |
| 56 | + static public function encodeObjectId($typeId, $objectId) | |
| 57 | 57 | { |
| 58 | 58 | $encoded = null; |
| 59 | 59 | |
| ... | ... | @@ -84,7 +84,7 @@ class CMISUtil { |
| 84 | 84 | * @param string $objectId |
| 85 | 85 | * @return string $typeId |
| 86 | 86 | */ |
| 87 | - static function decodeObjectId(&$objectId) | |
| 87 | + static public function decodeObjectId($objectId, &$typeId = null) | |
| 88 | 88 | { |
| 89 | 89 | $typeId = null; |
| 90 | 90 | |
| ... | ... | @@ -105,7 +105,7 @@ class CMISUtil { |
| 105 | 105 | break; |
| 106 | 106 | } |
| 107 | 107 | |
| 108 | - return $typeId; | |
| 108 | + return $objectId; | |
| 109 | 109 | } |
| 110 | 110 | |
| 111 | 111 | /** |
| ... | ... | @@ -118,7 +118,7 @@ class CMISUtil { |
| 118 | 118 | * @param object $ktapi // reference to ktapi instance |
| 119 | 119 | * @return array $CMISArray |
| 120 | 120 | */ |
| 121 | - static function createChildObjectHierarchy($input, $repositoryURI, &$ktapi) | |
| 121 | + static public function createChildObjectHierarchy($input, $repositoryURI, &$ktapi) | |
| 122 | 122 | { |
| 123 | 123 | $CMISArray = array(); |
| 124 | 124 | |
| ... | ... | @@ -172,7 +172,7 @@ class CMISUtil { |
| 172 | 172 | * @return array $CMISArray |
| 173 | 173 | */ |
| 174 | 174 | // NOTE this will have to change if we implement multi-filing |
| 175 | - static function createParentObjectHierarchy($input, $repositoryURI, &$ktapi) | |
| 175 | + static public function createParentObjectHierarchy($input, $repositoryURI, &$ktapi) | |
| 176 | 176 | { |
| 177 | 177 | $CMISArray = array(); |
| 178 | 178 | |
| ... | ... | @@ -209,7 +209,7 @@ class CMISUtil { |
| 209 | 209 | * @param string $linkText // 'child' or 'parent' - indicates direction of hierarchy => descending or ascending |
| 210 | 210 | * @return array $hierarchy |
| 211 | 211 | */ |
| 212 | - static function decodeObjectHierarchy($input, $linkText) | |
| 212 | + static public function decodeObjectHierarchy($input, $linkText) | |
| 213 | 213 | { |
| 214 | 214 | $hierarchy = array(); |
| 215 | 215 | |
| ... | ... | @@ -225,7 +225,7 @@ class CMISUtil { |
| 225 | 225 | return $hierarchy; |
| 226 | 226 | } |
| 227 | 227 | |
| 228 | - static function createObjectPropertiesEntry($properties) | |
| 228 | + static public function createObjectPropertiesEntry($properties) | |
| 229 | 229 | { |
| 230 | 230 | $object = array(); |
| 231 | 231 | |
| ... | ... | @@ -281,7 +281,7 @@ class CMISUtil { |
| 281 | 281 | * @param object $data |
| 282 | 282 | * @return array $array |
| 283 | 283 | */ |
| 284 | - static function objectToArray($data) | |
| 284 | + static public function objectToArray($data) | |
| 285 | 285 | { |
| 286 | 286 | $array = array(); |
| 287 | 287 | |
| ... | ... | @@ -309,11 +309,35 @@ class CMISUtil { |
| 309 | 309 | * @param boolean/other $input |
| 310 | 310 | * @return string |
| 311 | 311 | */ |
| 312 | - function boolToString($input) | |
| 312 | + static public function boolToString($input) | |
| 313 | 313 | { |
| 314 | 314 | return (($input === true) ? 'true' : (($input === false) ? 'false' : $input)); |
| 315 | 315 | } |
| 316 | 316 | |
| 317 | + /** | |
| 318 | + * Creates a temporary file | |
| 319 | + * Cleanup is the responsibility of the calling code | |
| 320 | + * | |
| 321 | + * @param string|binary $content The content to be written to the file. | |
| 322 | + * @param string $uploadDir Optional upload directory. Will use the KnowledgeTree system tmp directory if not supplied. | |
| 323 | + * @return string The path to the created file (for reference and cleanup.) | |
| 324 | + */ | |
| 325 | + static public function createTemporaryFile($content, $encoding = null, $uploadDir = null) | |
| 326 | + { | |
| 327 | + if(is_null($uploadDir)) | |
| 328 | + { | |
| 329 | + $oKTConfig =& KTConfig::getSingleton(); | |
| 330 | + $uploadDir = $oKTConfig->get('webservice/uploadDirectory'); | |
| 331 | + } | |
| 332 | + | |
| 333 | + $temp = tempnam($uploadDir, 'myfile'); | |
| 334 | + $fp = fopen($temp, 'wb'); | |
| 335 | + fwrite($fp, ($encoding == 'base64' ? base64_decode($content) : $content)); | |
| 336 | + fclose($fp); | |
| 337 | + | |
| 338 | + return $temp; | |
| 339 | + } | |
| 340 | + | |
| 317 | 341 | } |
| 318 | 342 | |
| 319 | 343 | ?> | ... | ... |
tests/ktcmis/testCmisApi.php
| ... | ... | @@ -355,10 +355,53 @@ class CMISTestCase extends KTUnitTestCase { |
| 355 | 355 | $this->printTable($properties['results'][0], 'Properties for CMIS Created Folder Object ' . $folderId . ' (getProperties())'); |
| 356 | 356 | |
| 357 | 357 | // delete |
| 358 | - CMISUtil::decodeObjectId($folderId); | |
| 359 | - $this->ktapi->delete_folder($folderId, 'Testing API', KT_TEST_USER, KT_TEST_PASS); | |
| 358 | + $this->ktapi->delete_folder(CMISUtil::decodeObjectId($folderId), 'Testing API', KT_TEST_USER, KT_TEST_PASS); | |
| 360 | 359 | } |
| 361 | 360 | |
| 361 | + // TEST 3 | |
| 362 | + // test creation of document | |
| 363 | + $folderId = 'F'.$this->folders[0]; | |
| 364 | + $folderId = 'F1'; | |
| 365 | + $properties = array('name' => 'Test CMIS Document 1', 'title' => 'test_cmis_doc_' . mt_rand() . '.txt'); | |
| 366 | + $contentStream = base64_encode('Some arbitrary text content'); | |
| 367 | + $created = $ObjectService->createDocument($repositoryId, 'Document', $properties, $folderId, $contentStream); | |
| 368 | + | |
| 369 | + $this->assertNotNull($created['results']); | |
| 370 | + | |
| 371 | +// echo '<pre>'.print_r($created, true).'</pre>'; | |
| 372 | + | |
| 373 | + if (!is_null($created['results'])) | |
| 374 | + { | |
| 375 | + $documentId = $created['results']; | |
| 376 | + | |
| 377 | + // check that document object actually exists | |
| 378 | + $properties = $ObjectService->getProperties($repositoryId, $documentId, false, false); | |
| 379 | + $this->assertNotNull($properties['results']); | |
| 380 | + | |
| 381 | + // test printout | |
| 382 | + $this->printTable($properties['results'][0], 'Properties for CMIS Created Document Object ' . $documentId . ' (getProperties())'); | |
| 383 | + } | |
| 384 | + | |
| 385 | +// // TEST 5 | |
| 386 | +// // test updating content stream for existing document | |
| 387 | +// $contentStream = base64_encode('Some updated text content for the content stream'); | |
| 388 | +// $updated = $ObjectService->setContentStream($repositoryId, $documentId, true, $contentStream); | |
| 389 | +// | |
| 390 | +// $this->assertNotNull($updated['results']); | |
| 391 | +// | |
| 392 | +//// echo '<pre>'.print_r($created, true).'</pre>'; | |
| 393 | +// | |
| 394 | +// if (!is_null($updated['results'])) | |
| 395 | +// { | |
| 396 | +//// $documentId = $updated['results']; | |
| 397 | +// | |
| 398 | +// // TODO test getContentStream here when we have it | |
| 399 | +// | |
| 400 | +// } | |
| 401 | + | |
| 402 | + // delete created document | |
| 403 | +// $this->ktapi->delete_document(CMISUtil::decodeObjectId($documentId), 'Testing API', false); | |
| 404 | + | |
| 362 | 405 | // tear down the folder/doc tree structure with which we were testing |
| 363 | 406 | $this->cleanupFolderDocStructure(); |
| 364 | 407 | ... | ... |